The solution to this problem is probably pretty simple, but I am new to interfacing with a device dynamically. What I'm doing is I am making a python executable code, so the user doesn't have to have Idle on their computer or any kind of python interpreter, which means I don't know which USB port the device will be plugged in to. The program needs to be able to open a connection to a device that is connected through a serial to usb converter. How can I determine which connected device is the correct device to open a port to? I am using pySerial to interact with the device. Any help would be greatly appreciated.
No matter how you configure your device, at some point you're probably going to have to ask the user where the port is, or poll all serial devices for a known response. (Polling has it's pitfalls though, so read on!). Unlike USB devices, there is no vendor/device ID that is made known to the OS when you attach a plain-old serial device.
First you need to find the serial ports. Here's a question that might help: What is the cross-platform method of enumerating serial ports in Python (including virtual ports)?.
Once you have a list of serial ports, you could ask the user whether they know which one to use. If they do, problem solved!
If they don't, you could offer to poll ALL serial devices with some data that you know will yield a certain response from your device. Keep in mind though that if the user has other serial devices attached, your string of "hello" bytes might actually be the self-destruct sequence for some other device! Hence, you should warn the user that polling may interfere with other devices, and always prompt them before you do so.
Without knowing more about your code (eg. what comms framework, if any, you're using; are you doing this in the console or are you using a GUI toolkit, etc), it's impossible to say what the best way to code this might be. In the simplest case, you could just loop over all of your serial devices, send the greeting and check for a response. (You could also do this in parallel: loop once for the greeting, and loop again to check what's in the buffer. If you're going to get more fancy than that, use a proper library.)
Side note: You might be able to get around this if you have a built-in converter that you can set the vendor/device ID for, but the converter will still be automatically detected by any modern OS and enumerated as a serial port; you won't get to talk to it directly as a USB device. It could be possible to figure out which port goes with which ID, but I've never tried to do that. But this approach is useless if you're not the one who gets to pick the converter (eg. if it's a user-supplied cable).
This is the way that I used for identify Serial-USB conveter device like Arduino.
It checks 'USB' String of device description.
import serial as ser
import serial.tools.list_ports as prtlst
global COMs
COMs=[]
def getCOMs():
global COMs
pts= prtlst.comports()
for pt in pts:
if 'USB' in pt[1]: #check 'USB' string in device description
COMs.append(pt[0])
The only way I can think to get around the problem with probing unknown devices is to have the device send unsolicited "hello" responses continually. That was you can just connect to all serial devices and listen for the "hellos". Connecting and listening to a serial device shouldn't ever mess it up.
The downside is you have these messages cluttering up your serial stream. You could have a "I'm here now, stfu" command but then you can only connect to it once.
FTDI chips have a method of identification but you have to use their library to access the data.
Related
i am sending some commands having particular response serially using com port..the commands are kept in a file..i am reading each command through the file line by line and sending it serially over the com port..but when i am seeing it from the receiver end using Magic Terminal(Software)..i found that each command is going multiple times..which i am sending only one time..i have made a code in pycharm..and in the console i am seeing that command is going only once but from the uart receiving end the story is something else..i am stuck with this problem..i have maintain the same baudrate and everything but not able to diagnose the issue..
github link for the code is: https://github.com/AkshatPant06/Akshat-Pant/blob/master/cmd%20list
def recvResponse():
ser.write(serial.to_bytes(intCmd))
time.sleep(1)
data_recv=ser.read(2)
return data_recv
this i have used to receive the 2 byte response..
There seems to be nothing wrong with your code. At least to the extent I could reproduce, it only sends the command once (I tried your function after setting up my serial port in loopback).
I cannot say for sure but it might be that the terminal you're using has two windows, one for input and another one for output and somehow you're getting confused with what is in and out of your port.
One easy way to deal with this kind of issue is to use a sniffer on your port. You can do that combining com0com and Termite on Windows, as I recently explained here.
As you can see there is only one window on this terminal, and after setting up the forwarding you'll everything that comes in and out of your port. That should make it easier to see what your code is writing and reading.
To give you a conventional scenario to apply the sniffer trick you can refer to the following screenshot:
In this case, we have two real serial ports on a computer. On the first (COM9) we are running a Modbus server (you can imagine it as a bunch of memory addresses, each of one storing a 16-bit number). On COM10 we have a client that is sending queries asking for the contents of the first 10 addresses (called registers using the Modbus terminology). In a general use case, we have those ports linked with a cable, so we know (theoretically) that the client on COM10 is sending a data frame asking for those ten registers and the server on COM9 is answering with the numbers stored on those registers. But we are only able to see the contents on the server (left side of the picture) and what the client is receiving (right). What we don't see is what is traveling on the bus (yeah, we know what it is, but we don't know exactly how the Modbus protocol looks like on the inside).
If we want to tap on the bus to see what is being sent and received on each side we can create a couple of virtual ports with com0com and a port forwarding connection with Termite, something like the following screenshot:
Now we have moved our Modbus server to one of the virtual serial ports (COM4 in this case). After installing com0com we got (by default, but you can change names or add more port pairs, of course) a pair of forwarded ports (COM4<-->COM5). Now, if we want to see what is circulating through the ports we open Termite (bottom-right side of the picture) and set up another port forwarding scheme, in this case from virtual port COM5 to the real port COM9.
Finally (and exactly the same as before we were sniffing), we have COM9 connected together with COM10 with a cable. But now we are able to see all data going to and fro on the bus (all those HEX values you see on Termite displayed with the green/blue font).
As you can see, this will offer something similar to what you can do with more professional tools.
I have a dot-matrix printer LX-300 connected to my computer through the network. How do I send a raw string with ESCP characters directly to my printer in Python?
The computer is connected to the printer through another computer. I need to send a raw string because LX-300 image printing result is blurry.
The Problem
To send data down this route:
Client computer ---> Server (Windows machine) ---> printer (dot-matrix)
...and to not let Windows mess with the data; instead to send the raw data, including printer control codes, straight from the client computer.
My Solution
Here's how I solved a near-identical problem for a small in-house database application:
Step 1) Make the printer network-accessible without Windows getting its fingers in the data routed to it. I accomplished this by installing the printer using the "Generic/Text Only" driver, then installing
RawPrintServer on the Windows machine connected to the printer.
Step 2) Send raw data over the network to the TCP/IP port specified when you set up RawPrintServer (default is 9100). There are various ways to do that, here's what I did:
data = b"\x1B#A String To Print\x1B#" # be sure to use the right codes for your printer
ip_addr = 123.123.123.123 # address of the machine with the printer
port = 9100 # or whatever you set it to
s = socket.socket()
try:
s.connect((ip_addr, port))
s.send(data)
except:
# deal with the error
finally:
s.close()
Background
I thought about the problem in two parts:
Client machine: spitting out the data I need from Python with the correct formatting/control codes for my printer, and sending it across the network
Print server machine: transmitting the data to the locally connected printer
Number 1 is the easy part. There are actually some libraries in PyPI that may help with all the printer codes, but I found most of them are aimed at the little point-of-sale label printers, and were of limited use to me. So I just hard-coded what I needed into my Python program.
Of course, the way you choose to solve number 2 will effect how you send the data from Python. I chose the TCP/IP route to avoid dealing with Samba and Windows print issues.
As you probably discovered, Windows normally tries very hard to convert whatever you want to print to a bitmap and run the printer in graphics mode. We can use the generic driver and dump the data straight into the (local) printer port in order to prevent this.
The missing link, then, is getting from the network to the local printer port on the machine connected to the printer. Again, there are various ways to solve this. You could attempt to access the Windows printer share in some way. If you go the TCP/IP route like I did, you could write your own print server in Python. In my case, the RawPrintServer program "just worked" so I didn't investigate any further. Apparently all it does is grab incoming data from TCP port 9100 and shove it into the local printer port. Obviously you'll have to be sure the firewall isn't blocking the incoming connections on the print server machine. This method does not require the printer to be "shared" as far as Windows is concerned.
Depending on your situation (if you use DHCP), you might need to do some extra work to get the server's IP address in Python. In my case, I got the IP for free because of the peculiarity of my application.
This solution seems to be working out very well for me. I've got an old Panasonic printer running in Epson ESC/P compatibility mode connected to a Windows 7 machine, which I can print to from any other computer on the local network. Incidentally, this general idea should work regardless of what OS the client computer is running.
Ultimately, you will need and want to write your own wrapper/script to do this. And since you are using a distribution of Linux, this is relatively easy.
On a Linux OS, the simplest way to issue a print job is to open a subprocess to the lpr. Generally, using lpr lets you access the printer without the need to be logged in as root (being a superuser), which is desirable considering the amount of damage that can be done while logged in as a "superuser".
Code like the following:
import subprocess
lpr = subprocess.Popen("/usr/bin/lpr", stdin=subprocess.PIPE)
lpr.stdin.write(data_to_send_to_printer)
Should be a good jumping off point for you. Essentially, this code should allow you to accomplish what you need.
Be careful though; depending on your privilege levels, a call to open a subprocess might need root level/Superuser permissions.
Subprocesses generally inherit the User IDs and access rights by the user that is running the command. For example, if the subprocess is created by a root user, then you will need root user/Superuser rights to access that subprocess.
For more information, check out the hyperlinks I've included in the post.
Good luck!
I have 2 devices communicating with each other using Modbus and I would like to sniff this communication line using Python for logging purposes. I have connected my computer to the communication bus via a Modbus dongle, but I don't know how I can actually read the data.
I have used Pymodbus before, but I don't think that would work in this case since it only allows for master or slave devices (as far as I know)
Are there any other libraries that I can use for my purpose? Would it be possible for me to implement something like a read only socket on the COM port that doesn't interfere with existing communication on the bus?
Thank you!
You can try a MODBUS simulator like this one: It has an option to see the activity on the bus.
If you want to use another python MODBUS I recommend using modbus_tk. It has an example on how to create an MODBUS simulator. But to be able sniff the packets sent to other devices you will need to do some modifications to disable the automatic response.
If the only thing you want to do is to see the activity on the bus I recommend the first option.
I hope this helps you.
[Edit]:To be more specific you will need to download the following software : Modbus Poll - MODBUS slave simulator(which works on Windows) and plug your MODBUS dongle in the port you intend to use. After you do all the settings for the serial communications go to the Display tab and click on Communication. You will be able to see the traffic on the line.
I need to run both zigbee and SMS dongle on a raspberry pi, that means having to run both ports in a python script. Since xbee is always on ttyUSB0, is there a way I could set the dongle on ttyUSB1 or ttyUSB2 so that i dont have to configure it via gammu command everytime it is plugged in?
The best thing to do here is use a udev rule. This will allow you to symlink the device to a specific port, something like /dev/ttyXBEE and /dev/ttySMS in your case.
To accomplish this, you need to query the devices using udevadm to find some unique identifying information, then create a file /etc/udev/rules.d/99-usbserial.rules that will tell the Pi how to map the device.
This thread has an example.
Using a Lantronix UDS-1100 serial to IP converter. The goal is to write a small proof of concept piece in Python to capture serial data output by this device over IP.
I've done a couple test projects using sockets in python, but they were all done between python processes (python > python): listen() on one end, and connect(), sendall() etc on the other.
I think I can use sockets for this project, but before I invest a bunch of time into it, wanted to make sure it is a viable solution.
Can python sockets be used to capture IP traffic when the traffic is originating from a non-python source? I have full control over the IP and port that the device sends the serial data to, but there will be no python connect() initiated by the client. I can pre-pend then serial data with some connect() string if needed.
If sockets won't work, please recommend another solution...guessing it will be REST or similar.
Of course. TCP/IP is supposed to be cross-platform and cross-language, so in theory you should be able to communicate with every kind of device as long as you manage to process and send the expected protocol.