Python: Get device "model" using pyvisa or pyserial - python

I wrote a data acquisition program/script that works with a device developed by our collaboration. The problem is that I can only read from this device. No writing is possible, so it's not possible to use a serial "?IDN*" command to know what device this is.
The only thing that defines this device is its "Model" that can be seen in "Devices and Printers" in Control Panel of Windows. The following figure shows it:
The guy who designed the device was able to create a labview simple program that extracts this name from the device through NI-VISA through something called "Intf Inst Name", which is called "Interface Information:Interface Description".
If I get this model name and compare it with the pyvisa device name, I'll be able to automatically detect the presence of our device, which is an important thing to have, in case a USB disconnect happens. This is because VISA opens the device through a name that can be different on every computer, but this name "GPS DATA LOGGER" is the same everywhere and always.
I need this solution to be cross-platform. That's why I need to use pyvisa or pyserial. Though any cross-platform alternative is OK.
So my question in brief: How can I use pyvisa/pyserial to find the model name corresponding to the device model (in my case "GPS DATA LOGGER")?
Please ask for any additional information you may require.
Update
I learned that there's an "attribute" pyvisa with the name "VI_ATTR_INTF_INST_NAME" that would get this name, but I don't know how to use it. Does anyone know how to read these attributes?

I found the way to do it. Unfortunately it involves opening every VISA device you have in your computer. I wrote a small pyvisa function that will do the task for you with comments. The function returns all the devices that contain the model name/descriptor mentioned as a parameter:
import pyvisa
def findInstrumentByDescriptor(descriptor):
devName = descriptor
rm = pyvisa.ResourceManager()
com_names=rm.list_resources()
devicesFound = []
#loop over all devices, open them, and check the descriptor
for com in range(len(com_names)):
try:
#try to open instrument, if failed, just skip to the next device
my_instrument=rm.open_resource(com_names[com])
except:
print("Failed to open " + com_names[com])
continue
try:
# VI_ATTR_INTF_INST_NAME is 3221160169, it contains the model name "GPS DATA LOGGER" (check pyvisa manual for other VISA attributes)
modelStr = my_instrument.get_visa_attribute(3221160169)
#search for the string you need inside the VISA attribute
if modelStr.find(devName) >= 0:
#if found, will be added to the array devicesFound
devicesFound.append(com_names[com])
my_instrument.close()
except:
#if exception is thrown here, then the device should be closed
my_instrument.close()
#return the list of devices that contain the VISA attribute required
return devicesFound
#here's the main call
print(findInstrumentByDescriptor("GPS DATA LOGGER"))

pyvisa has an optional query parameter for list_resources(), which you can use to narrow the scope of your search to just your device. The syntax for this is like a regular expression.
Try this:
from string import Template
VI_ATTR_INTF_INST_NAME = 3221160169
device_name = "GPS DATA LOGGER"
entries = dict(
ATTR = VI_ATTR_INTF_INST_NAME,
NAME = device_name )
query_template = Template(u'ASRL?*INSTR{$ATTR == "$NAME"}')
query = query_template.substitute(entries)
rm = visa.ResourceManager()
rm.list_resources(query)

Related

Python canopen send a domain

I'm using the canopen python library, see https://canopen.readthedocs.io/en/latest/index.html.
I'm trying to send a domain to my CANopen node:
# nodeHeadPort.sdo['Config Data2'].phys = b'\x11\x22\x33\x44\x55'
nodeHeadPort.sdo.download(0x6006, 0, b'\x11\x22\x33\x44\x55')
But the python gives an exception with:
canopen.sdo.exceptions.SdoAbortedError: Code 0x06090011, Subindex does not exist
And in the eds file I have the following:
[6006]
ParameterName=Config Data2
ObjectType=0x7
;StorageLocation=RAM
DataType=0x000F
AccessType=rw
DefaultValue=
PDOMapping=0
I guess my call in the python program should be different (without any subindex)? Does somebody know how to do?
This is what's going on the bus:
The reason for the issue was in the CANopen slave. I have to add their support for data type domain.
https://github.com/CANopenNode/CANopenDemo/blob/master/demo/domainDemo.c

server name reachability in dnspython

I am currently trying to find a way to check whether or not the name servers can respond to either TCP or UDP packets.
My idea behind that was, to get all the name servers from a website (for example google.com), store them in a list, and then try to send TCP and UDP messages to all of them.
Although I am getting the name servers, my interpreter shows a problem when I am trying to make a query on udp(check udpPacket on the code) saying:
"TypeError: coercing to Unicode: need string or buffer, NS found"
I am new in Python(coming from C and C++) and I am guessing this is just incompatible types.
I checked dnspython's documentation and could not find what kind of type NS is (probably it's a type by itself) and why it cannot be passed as an argument.
What do you think the problem is? Is there maybe a better way to solve that kind of problem?
def getNSResults(url):
#create an empty list where we can store all the nameservers we found
nameServers = []
nameServers = dns.resolver.query(url,dns.rdatatype.NS, raise_on_no_answer=False)
#create a dictionary where based on all the nameservers.
#1st label refers to the ns name of our url that we inserted.
#2nd label shows wether or not we received a UDP response or not.
#3rd label shows wether or not we received a TCP response or not.
results = {}
for nameServer in nameServers:
#make a dns ns query, acts as a dumb message since whatever we send we just care of what we get back
query = dns.message.make_query(dns.name.from_text(url), dns.rdatatype.ANY)
query.flags |= dns.flags.AD
query.find_rrset(query.additional, dns.name.root, 65535, dns.rdatatype.OPT, create=True, force_unique=True)
#try sending a udp packet to see if it's listening on UDP
udpPacket = dns.query.udp(query,nameServer)
#try sending a tcp packet to see if it's listening on TCP
tcpPacket = dns.query.tcp(None,nameServer)
#add the results in a dictionary and return it, to be checked later by the user.
results.update({"nsName" == nameServer, "receivedUDPPacket" == isNotNone(udpPacket),"receivedTCPPacket" == isNotNone(tcpPacket)})
Thanks in advance!
Looking at your code, I see some DNS problems, some Python problems, and some dnspython problems. Let's see if we can't learn something together.
DNS
First, the parameter to your function getNSResults is called url. When you send DNS queries, you query for a domain name. A URL is something totally different (e.g. https://example.com/index.html). I would rename url to something like domain_name, domain, or name. For more on the difference between URLs and domain names, see https://www.copahost.com/blog/domain-vs-url/.
Second, let's talk about what you're trying to do.
i am currently trying to find a way to check wether or not the name servers can respond to either tcp or udp packets.
My idea behind that was, to get all the name servers from a website (for example google.com), store them in a list, and then, try to send tcp and udp messages to all of them.
That sounds like a great approach. I think you might be missing a few details here. so let me explain the steps you can take to do this:
Do an NS query for a domain name. You already have this step in your code. What you'll actually get from that query is just another domain name (or multiple domain names). For example, if you run dig +short NS google.com, you'll get this output:
ns3.google.com.
ns1.google.com.
ns4.google.com.
ns2.google.com.
At this step, we have a list of one or more names of authoritative servers. Now we need an IP address to use to send them queries. So we'll do a type A query for each of the names we got from step 1.
Now we have a list of IP addresses. We can send a DNS query over UDP and one over TCP to see if they're supported.
Python
For the most part, your Python syntax is okay.
The biggest red flag I see is the following code:
results.update({"nsName" == nameServer,
"receivedUDPPacket" == isNotNone(udpPacket),
"receivedTCPPacket" == isNotNone(tcpPacket)})
Let's break this down a bit.
First, you have results, which is a dict.
Then you have this:
{"nsName" == nameServer,
"receivedUDPPacket" == isNotNone(udpPacket),
"receivedTCPPacket" == isNotNone(tcpPacket)}
which is a set of bools.
What I think you meant to do was something like this:
results.update({
"nsName": nameServer,
"receivedUDPPacket": true,
"receivedTCPPacket": true
})
Function and variables names in Python are usually written in lowercase, with words separated by underscores (e.g. my_variable, def my_function()). Class names are usually upper camel case (e.g. class MyClass).
None of this is required, you can name your stuff however you want, plenty of super popular libraries and builtins break this convention, just figured I'd throw it out there because it can be helpful when reading Python code.
dnspython
When you're not sure about the types of things, or what attributes things have, remember these four friends, all builtin to Python:
1. pdb
2. dir
3. type
4. print
pdb is a Python debugger. Just import pdb, and the put pdb.set_trace() where you want to break. Your code will stop there, and then you can check out the values of all the variables.
dir will return the attributes and methods of whatever you pass to it. Example: print(dir(udpPacket)).
type will return the type of an object.
print as you probably already know, will print out stuff so you can see it.
I'm going to leave this part for you to test out.
Run dir() on everything if you don't know what it is.
I also should probably mention help(), which is super useful for built-in stuff.
The summary for this section is that sometimes documentation isn't all there, or hard to find, especially when you're new to a language/library/whatever.
So you have to figure stuff out on your own, and that means using all the tools I've just mentioned, looking at the source code, things like that.
Summary
I hope this was helpful. I know it's a lot, it's probably too much, but just be patient and know that DNS and Python are some very useful and fun things to learn about.
I went ahead and wrote something up that is a start at what I think you're hoping to achieve.
I recommend walking through the whole thing and making sure you understand what's going on.
If you don't understand something, remember pdb and dir (and there's always Google, SO, etc).
import dns.resolver
import dns.message
import dns.rdatatype
import json
import sys
def check_tcp_and_udp_support(name):
# this will give me the first default system resolver from /etc/resolv.conf
# (or Windows registry)
where = dns.resolver.Resolver().nameservers[0]
q = dns.message.make_query(name, dns.rdatatype.NS)
ns_response = dns.query.udp(q, where)
ns_names = [t.target.to_text() for ans in ns_response.answer for t in ans]
# this code is the same as the one-liner above
# ns_names = []
# for ans in ns_response.answer:
# for t in ans:
# ns_names.append(t.target.to_text())
results = {}
for ns_name in ns_names:
# do type A lookup for nameserver
q = dns.message.make_query(ns_name, dns.rdatatype.A)
response = dns.query.udp(q, where)
nameserver_ips = [item.address for ans in response.answer for item in ans.items if ans.rdtype == dns.rdatatype.A]
# now send queries to the nameserver IPs
for nameserver_ip in nameserver_ips:
q = dns.message.make_query('example.com.', dns.rdatatype.A)
try:
udp_response = dns.query.udp(q, nameserver_ip)
supports_udp = True
except dns.exception.Timeout:
supports_udp = False
try:
tcp_response = dns.query.tcp(q, nameserver_ip)
supports_tcp = True
except dns.exception.Timeout:
supports_tcp = True
results[nameserver_ip] = {
'supports_udp': supports_udp,
'supports_tcp': supports_tcp
}
return results
def main():
results = check_tcp_and_udp_support('google.com')
# this is just fancy JSON printing
# you could do print(results) instead
json.dump(results, sys.stdout, indent=4)
if __name__ == '__main__':
main()
Again, I hope this is helpful. It's hard when I don't know exactly what's going on in your head, but this is what I've got for you.

Adafruit BLE python library can't list descriptors

I'm trying to use BLE library for python to communicate with one Nordic nrf51844 chipset. Because one characteristic is notification enabled, I need to enable notification from client side by setting the descriptor Client Characteristic Configuration to 0x0001. But I failed to get the descriptor with the call "characteristic.find_descriptor()" to get it. I also tried to print out all of descriptors discovered, but looks like there is no luck to get it work.
Below is the code I'm using to discover characteristics and its descriptor referred to the example of Adafruit BLE library:
def enable_notification(characteristic):
_enableDesc = characteristic.find_descriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID)
_cmd = bytearray([0x01, 0x00])
_enableDesc.write_value(_cmd)
def handle_device_message(device):
global _status
# Once connected do everything else in a try/finally to make sure the device
# is disconnected when done.
# Wait for service discovery to complete for at least the specified
# service and characteristic UUID lists. Will time out after 60 seconds
# (specify timeout_sec parameter to override).
_logger.info('Discovering services...')
device.discover([HES_SERVICE_UUID], [DATA_CHAR_UUID, STATUS_CHAR_UUID, FACTOR_CHAR_UUID])
# Find the HES service and its characteristics.
hes = device.find_service(HES_SERVICE_UUID)
dataC = hes.find_characteristic(DATA_CHAR_UUID)
statusC = hes.find_characteristic(STATUS_CHAR_UUID)
#factorC = hes.find_characteristic(FACTOR_CHAR_UUID)
dataC.list_descriptors()
statusC.list_descriptors()
enable_notification(dataC)
enable_notification(statusC)
But it always failed at "characteristic.find_descriptor()" with below error:
_enableDesc =
characteristic.find_descriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID)
File "build/bdist.macosx-10.11-x86_64/egg/Adafruit_BluefruitLE/interfaces/gatt.py", line 98, in find_descriptor
File "build/bdist.macosx-10.11-x86_64/egg/Adafruit_BluefruitLE/corebluetooth/gatt.py", line 124, in list_descriptors
File "build/bdist.macosx-10.11-x86_64/egg/Adafruit_BluefruitLE/corebluetooth/metadata.py", line 63, in get_all
TypeError: 'NoneType' object is not iterable
I looked into the source code of library, but can't find the interface to get descriptors explicitly. Can anyone help me on this?
Thanks!
Finally I figured out by checking the API of IOS to set notification. It should be set by calling setNotify for characteristic instead of writeValue for descriptor. And for the descriptor stuff, it shows we need to wait for some time before all descriptors are discovered and returned. Might be the issue implemented with Python. Not really verified with IOS native program.
BTW, after setting the notification, we need to wait for some time as well before the device sends notification to client.
Will get a Linux box to verify the implementation with blueZ is working well.

How to change iBus input method in python?

I am writing a Vim plugin to set iBus engines and input methods. So far I can change the engines with the code below:
function! im#setEngine(name)
python << EOF
try:
import ibus,vim
bus = ibus.Bus()
ic = ibus.InputContext(bus, bus.current_input_contxt())
name = vim.eval("a:name")
engines = bus.get_engines_by_names([name])
size = len(engines)
if size <= 0:
print "Could not find engine %s"%name
else:
engine = engines[0]
ic.set_engine(engine)
except Exception, e:
print "Failed to connect to iBus"
print e
EOF
endfunction
function! im#listEngines()
let l:engines = []
python << EOF
try:
import ibus,dbus,vim
bus = ibus.Bus()
names = []
for engine in bus.list_engines():
names.append(str(engine.name))
vim.command("let l:engines = %s"% names)
except Exception, e:
print "Failed to connect to iBus"
print e
EOF
return l:engines
endfunction
Now I am trying to also set the input method for the engines but I am unable to find how to do this. The iBus documentation is lacking on details so far.
Does anyone can provide pointers or examples on how to programatically (Python) change the iBus input method? Also a way to get a list of supported input methods for each engine would be great.
====
From this point I will try to provide more context on the problem I am trying to solve. Skip if you are not interested.
I implemented this plugin vim-im to disable input methods when entering Vim normal mode. This is important because Vim normal mode is unusable if iBus is set to a non ascii input method. If you use vim to write in Japanese, Chinese, Korean, etc... you may understand the issue.
The problem is that since iBus 1.5 the enable/disable methods my plugin depends on are deprecated. So my plugin works in Ubuntu <= 13.04 but not in Debian Jessie and possibly won't work on future Ubuntu versions either.
The only way I see to have similar functionality is to define a default iBus engine and input method and change iBus to those every time Vim enters in normal mode.
Reading the ibus library code I found an acceptable solution:
function! im#setInputMode(mode)
python << EOF
try:
import ibus,dbus,vim
bus = ibus.Bus()
conn = bus.get_dbusconn().get_object(ibus.common.IBUS_SERVICE_IBUS, bus.current_input_contxt())
ic = dbus.Interface(conn, dbus_interface=ibus.common.IBUS_IFACE_INPUT_CONTEXT)
mode = vim.eval("a:mode")
ic.PropertyActivate("InputMode." + mode, ibus.PROP_STATE_CHECKED)
except Exception, e:
print "Failed to connect to iBus"
print e
EOF
endfunction
This method allows me to change the input method of iBus by passing it a name like:
call im#setInputMode("Hiragana")
Unfortunately the input method name depends on the engine being used. For example for mozc I need to set it to "Direct" while for anthy I have to use "WideLatin" in order get correct input in vim Normal Mode.
If someone knows a way to query the iBus engines to get a list of supported InputMode would be great. Also a way to query the engine for the current set InputMethod would help too.

How do you escape a dash in Jython/Websphere?

I have a Jython script that is used to set up a JDBC datasource on a Websphere 7.0 server. I need to set several properties on that datasource. I am using this code, which works, unless value is '-'.
def setCustomProperty(datasource, name, value):
parms = ['-propertyName', name, '-propertyValue', value]
AdminTask.setResourceProperty(datasource, parms)
I need to set the dateSeparator property on my datasource to just that - a dash. When I run this script with setCustomProperty(ds, 'dateSeparator', '-') I get an exception that says, "Invalid property: ". I figured out that it thinks that the dash means that another parameter/argument pair is expected.
Is there any way to get AdminTask to accept a dash?
NOTE: I can't set it via AdminConfig because I cannot find a way to get the id of the right property (I have multiple datasources).
Here is a solution that uses AdminConfig so that you can set the property value to the dash -. The solution accounts for multiple data sources, finding the correct one by specifying the appropriate scope (i.e. the server, but this could be modified if your datasource exists within a different scope) and then finding the datasource by name. The solution also accounts for modifying the existing "dateSeparator" property if it exists, or it creates it if it doesn't.
The code doesn't look terribly elegant, but I think it should solve your problem :
def setDataSourceProperty(cell, node, server, ds, propName, propVal) :
scopes = AdminConfig.getid("/Cell:%s/Node:%s/Server:%s/" % (cell, node, server)).splitlines()
datasources = AdminConfig.list("DataSource", scopes[0]).splitlines()
for datasource in datasources :
if AdminConfig.showAttribute(datasource, "name") == ds :
propertySet = AdminConfig.list("J2EEResourcePropertySet", datasource).splitlines()
customProp = [["name", propName], ["value", propVal]]
for property in AdminConfig.list("J2EEResourceProperty", propertySet[0]).splitlines() :
if AdminConfig.showAttribute(property, "name") == propName :
AdminConfig.modify(property, customProp)
return
AdminConfig.create("J2EEResourceProperty", propertySet[0], customProp)
if (__name__ == "__main__"):
setDataSourceProperty("myCell01", "myNode01", "myServer", "myDataSource", "dateSeparator", "-")
AdminConfig.save()
Please see the Management Console preferences settings. You can do what you are attempting now and you should get to see the Jython equivalent that the Management Console is creating for its own use. Then just copy it.
#Schemetrical solution worked for me. Just giving another example with jvm args.
Not commenting on the actual answer because I don't have enough reputation.
server_name = 'server1'
AdminTask.setGenericJVMArguments('[ -serverName %s -genericJvmArguments "-agentlib:getClasses" ]' % (server_name))
Try using a String instead of an array to pass the parameters using double quotes to surround the values starting with a dash sign
Example:
AdminTask.setVariable('-variableName JDK_PARAMS -variableValue "-Xlp -Xscm250M" -variableDescription "-Yes -I -can -now -use -dashes -everywhere :-)" -scope Cell=MyCell')

Categories

Resources