Twisted's Serialport and disappearing serial port devices - python

I'm using twisted.internet.serialport to have my program be continuously connected to a device on a serial port.
Unfortunately my serial port is just a usb device, which means it can be disconnected or reset by the OS at any time (port 2 disabled by hub (EMI?), re-enabling... ). I see that pyserial has support for this for a few weeks and raises a SerialException.
What I would love to do is try to reconnect to the serial port that just disappeared every few seconds.
So, is there any way how I can tell twisted to notify me about a disconnect? Or should I go ahead and write a threaded wrapper for pyserial?
Thanks

It seems the only relevant change in branched version is a call to connectionLost() in the protocol.
Until it's fixed in the trunk I use a:
class fixedSerialPort(SerialPort):
def connectionLost(self, reason):
SerialPort.connectionLost(self, reason)
self.protocol.connectionLost(reason)
I tested it with Twisted 10.1 (on ubuntu) and 8.1 (on my trusty debian). Both works fine. No idea about other OSs though.

http://twistedmatrix.com/trac/ticket/3690 may be related.
The ticket appears blocked on proper Windows support. I'm not sure if this kind of disconnect event will trigger Twisted's internal connection lost detection code, but I would expect it to (even without a recent version of pyserial).
You could probably try out the branch linked from that ticket pretty easily to see if it does what you want, at least. And if so, perhaps you could help get the ticket actually resolved (the 10.2 release is coming up pretty soon).

Related

Bleak (python) does not respond on connect

I have found the correct Bluetooth address of the device I want to connect to. When I run the code below, it prints "Connecting to device..." but then hangs and never prints "Connected" or finishes running. No errors are thrown.
import asyncio
from bleak import BleakClient
address = "24:71:89:cc:09:05" # Replaced with actual bluetooth address
async def main(address):
print("Connecting to device...")
async with BleakClient(address) as client:
print("Connected")
asyncio.run(main(address))
Is this issue related to my PC software/drivers? I am on a Lenovo laptop running Windows 11.
Or, do some devices not respond to simple "connection requests"? The device I am connecting to is a Tesla Model 3, and I know there is a particular set of data I should be sending to authenticate. If this is the case, how do I send data without connecting with a BleakClient in this way?
Update: I should mention that scanning / discovering devices works just fine via Bleak. And, I tried connecting to other devices via Bleak and the same issue occurred. Bluetooth through the Windows Settings app works fine though.
I was also having issues using any bleak commands beyond discover(). I downgraded from 0.14.3 to 0.14.0 and that resolved my problem.
When I looked up "python tesla bluetooth api" I found my way to this site, which documents the API which seems great for what you are doing. That lets you do lots of things like unlocking, opening trunk, etc.
It sounds like the main problem is that you can't connect at all in order to do stuff. The way that site is written glosses over that part, just saying "send it over".
I would ensure that you have the right address, you should use this scanning code from the Bleak doc. Also, make sure that you can use bluetooth normally, like by connecting to a wireless speaker.
Sadly, this error is still unsolved in Bleak, in the project they claim: still waiting for someone to capture bluetooth packets.
Trying to connect, you get either an endless hang with no response or if the device is paired upfront:
Connection error: [WinError -2147483629] The object has been closed
It seems the Library isn't very mature for windows:
https://github.com/hbldh/bleak/issues?q=label%3A%22Backend%3A+WinRT%22+

How do you connect PyVisa to an Arduino Uno?

I'm trying to connect my Arduino Uno to my computer and writing code in python using PyVisa. I have installed PyVisa correctly, since it has worked with other devices. For some reason the Arduino Uno never returns a response. I'm using the NI Visa package, because I was hoping the pyvisa-py was the problem. Is there something I'm missing?
The code I am using to connect is:
import pyvisa_py as pv
port = "ASRL4::INSTR"
rm = pv.ResourceManager()
device = rm.open_resource(port)
The ResourceManager finds the correct port, and I don't get an error making the device. When I try to use a query however, like
print(device.query("*IBN?"))
It gives the following error:
pyvisa.errors.VisaIOError: VI_ERROR_TMO (-1073807339): Timeout expired before operation completed.
I haven't tried to use an Arduino with PyVisa in a long time. I always use the PySerial library instead. Here is a personal note I wrote about four years ago (in 2017) for a Python module interfacing with an Arduino.
This driver does not use the VISA layer to communicate with the device. Instead, it uses the more low-level and less general PySerial library. The reason for that is that the Arduino reboots ("resets itself") whenever the serial port is opened through VISA. This is a feature, not a bug, so that you don't have to manually reset it every time you flash a new firmware version from the Arduino IDE. As a consequence, though, the controller will not respond to requests for about two seconds after opening its serial port. The only way to avoid the reboot is making sure that the serial port's DTR line is not toggled when opening the resource. VISA, however, does so by default, and there seems to be no way to disable this disruptive behavior. In fact, VISA attributes cannot be set until after the resource has been opened. The PySerial library, on the other hand, does not have this limitation.
As the note is four years old, take it with a grain of salt. Things may have changed. But using PySerial instead of PyVisa is still your best bet. See my answer here for a few more details. And maybe do a web search with the keywords "Arduino" and "DTR" to see if there have been any recent developments.

how can i connect and send commands to a serial port while another program is using it?

I am using a telit he910g card. it is connected to my PC directly using a miniPCI slot.
I am using it for 3G internet connection and A-GPS/GPS services.
My system is running linux mint 17.1, the 3G connection is handled using the network manager APP and works great. The 3G connection is started and handled using a module that is part of a program I am writing.
The code I am using in order to connect to the serial port is this:
def _connect_to_device(self):
""" Connect to a serial port """
try:
self._device = serial.Serial(self._filename, baudrate=self._baud_rate)
except StandardError, e:
raise StandardError("Couldn't connect to GPS device. Error: %s" % str(e))
When I use the python program alone it works great. But when I try and use it while the 3G is on i cant connect to the serial device. The wierd thing is that if I try to connect to it using a program like "minicom" while 3G is turned on it DOES work.
So my question is: how can I make both run and work together? since now they are mutually exclusive.
thanks to all who help. :)
Glad you found a way round your problem. Just for completeness:
Normally, serial ports can be opened by multiple processes.
If one of them does ioctl(,TIOCEXCL) on the open file then further opens will return EBUSY until everyone closes the device. Only root can get past this and open the device at all times.
If root opens the device and does an ioctl(,TIOCNXCL), then other processes can open the device too.
In python, TIOCNXCL isnt defined anywhere, but you can do the ioctl (eg on stdin) with:
import fcntl
TIOCEXCL = 0x540c # from /usr/lib64/perl5/asm-generic/ioctls.ph
TIOCNXCL = 0x540d
print fcntl.ioctl(0, TIOCNXCL)
Ok, so it is solved.
the issue was that the telit module has 2 ports /dev/ttyACM0 (high speed) and /dev/ttyACM3 (lower speed).
I tried to connect to the high speed one, but apparently the 3G uses that one and it causes contentions.
So moving to use the lower speed port in my script solved the issue.

How to find out if serial port is closed?

I am working on a multi threaded server application for processing serial/USB ports.
The issue is that if a cable gets unplugged, pyserial keeps reporting that the port is open and available. When reading I only receive Empty exceptions (due to read timeout).
How do I find out that a port has been disconnected so that I can handle this case?
Edit: OS is Ubuntu 12.04
Edit 2: Clarification - I am connecting to serial port devices via Serial to USB connector, thus the device being disconnected is an USB device.
A Serial port has no real concept of "cable connected" or not connected.
Depending on the equipment you are using you could try to poll the DSR or CTS lines, and decide there is no device connected when those stay low over a certain time.
From wikipedia:
DTR and DSR are usually on all the time and, per the RS-232 standard
and its successors, are used to signal from each end that the other
equipment is actually present and powered-up
So if you've got a conforming device, the DSR line could be the thing you need.
Edit:
As you seem to use an USB2Serial converter, you can try to check whether the device node still exists - you don't need to try to open it.
so os.path.exists(devNode) could suffice.

Python indifference to serial / Ethernet

I'm trying to communicate with a device that uses the same protocol whether you're talking to it over a TCP socket or a serial port. Either way, it's an ASCII command-based interface, in which you type your command at a prompt, followed by a newline, you get a response with a newline, and then a new prompt.
> IDENTIFY
DEVICE_TYPE_RESPONSE
> TEST POWER
OK
>
The program can and should block until it gets the new prompt, but there needs to be a timeout so you don't wait forever in case of sudden device death. That timeout should be seconds so as not to falsely flag on a network glitch, but shouldn't force me to wait seconds once I've gotten my prompt character.
I'd love some way to abstract the interface so as to not care about what the underlying communications layer is. Just pass it either an open socket or an open serial port and let everything happen. Is there some good way to do this? Preferably capable of running under Python 2.6.
You could implement the protocol in Twisted which allows you to use TCP or the serial port as a transport without changing your protocol implementation. Twisted also allows you to set timeouts/delayed callbacks.
Python's serial package provides a lot of useful stuff including some serial over TCP/IP bridges. If you want to talk to it using ASCII/Telnet then you probably want the to use the '--convert' option with the Simple Serial to Network (TCP/IP) redirector.
Also you might want to take a look at this other related question on Converting serial port data to TCP/IP in a linux environment

Categories

Resources