mrjohannchang / aioserial.py Goto Github PK
View Code? Open in Web Editor NEWpyserial-asyncio for humans.
Home Page: https://pypi.org/project/aioserial/
License: Mozilla Public License 2.0
pyserial-asyncio for humans.
Home Page: https://pypi.org/project/aioserial/
License: Mozilla Public License 2.0
I have a USB-Serial port on windows 10 worked with PySerial but not with aioserial.
Hello,
I'm unsure how to make this repeatable for others without a similar hardware device, but I am experiencing a lot of data loss.
I have a USB serial device that writes out a bytecode. I am reading with await aioserial_instance.read_async(size=1)
. Every once in a while (maybe when it switches between async tasks), the next read byte has skipped forward quite a bit in the buffer. This is at a really high baudrate (230400
).
I think a good proof, that the code works fine under multiple os and Python versions, tests should be added.
As well they help for future contributions.
Hi~ nice work.
in python 3.7 and virtual env, i got some error here:
import aioserial
import serial
class AioSerial(serial.Serial):
AttributeError: module 'serial' has no attribute 'Serial'
aioserial
is an excellent package for writing and reading data from serial ports. Thanks for creating it!
I have a serial device I am communicating with that can receive commands and respond to those commands. For example, I can write {get_temperature}
to the serial port and the serial device will respond back with the current temperature. The aioserial
package handles this task elegantly.
My serial device will also send back data to indicate that a button, for example, has been pushed on the device. This data is sent back asynchronously without being initiated by a command from the client computer. I think it's just my ignorance of asyncio
, but I'm trying to figure out how to receive and process these button push events arriving from the serial device while still being able to send specific commands and receive responses from the serial device.
Here's the code I've written so far for getting temperature:
import asyncio
from aioserial import AioSerial
PORT = "COM4"
BAUDRATE = 115_200
serial = AioSerial(port=PORT, baudrate=BAUDRATE, timeout=5.0)
async def send_command_await_response(command):
command_encoded = bytes(command, encoding='utf8')
await serial.write_async(command_encoded)
result = await serial.readline_async()
return result.rstrip().decode()
async def main():
command = "{get_temperature}"
response = await send_command_await_response(command)
print(f"{response=}")
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
Can you share some insights into how I could use aioserial
to accomplish my objective?
Most of my serial ports are opened by the serial_for_url
factory function.
I find that the hwgrep and spy urls are invaluable for bringup and debugging.
hwgrep is also quite valuable on attaching to specific hardware.
Do have any thoughts on extending these url based classes into your library.
perhaps an async_serial_for_url
function
I don't see an easy way without a metaclass to add in the mixin for overriding the port function.
运行了simple example,串口接收不到什么东西啊。
`async def read_and_print(aioserial_instance: aioserial.AioSerial):
while True:
print((await aioserial_instance.read_async()).decode(errors='ignore'), end='', flush=True)
asyncio.run(read_and_print(aioserial.AioSerial(port='COM35')))
`
希望能简单演示一下
Hello! I was just about to open a new library and was checking asyncio naming conventions when I found aioserial.
I have not reviewed this repository extensively, but my initial impression is that it uses ThreadPoolExecutors to wrap the pySerial library.
My work with pySerial has focused on reworking its backend at the OS level to support asyncio with no need to create new threads. This, I believe, is a more elegant solution that fits with the OS API intended use and the "single thread spirit" of asyncio.
So far I have a working asyncio implementation using the Windows API. I am neither a Linux nor Windows developer, but more comfortable on Linux, and my gut feeling is that async serial will be supported by Linux APIs more easily than Windows.
Let me know if you would be interested in my contributing to this repository with the intention of replacing thread pools with native OS event signaling.
Hi,
I am trying to do something fairly simple. I have a serial device (a micro:bit) that when I send it a 'g' followed by a carriage return, it returns a string of data.
Using a terminal emulator, If I do this, here is the string I get back:
16,-96,-1008,False,False,0,0,0,9,9,5
The data is generated via a Micropython print() function, so the string is terminated with '\n'
I wrote the following program with aioserial, but I am not receiving anything back:
import aioserial
import asyncio
async def read_and_print(aioserial_instance: aioserial.AioSerial):
cmd = 'g\n'
cmd = bytes(cmd.encode())
print('send', await aioserial_instance.write_async(cmd))
await asyncio.sleep(2)
print(('received: ', await aioserial_instance.readline_async()).decode(errors='ignore'), end='', flush=True)
asyncio.run(read_and_print(aioserial.AioSerial(port='/dev/ttyACM0')))
I've tried this with and without the sleep, and the behavior is the same.
I see that I sent 2 bytes based on the first print statement, but I never received anything back.
I also tried using read_async and the same result.
I am guessing my code contains some dumb mistake. Could you please tell me what I did wrong?
Thanks.
Hi, I've been testing arduino communication with serial.
during running it always connected , buy sometime the read is incorrect
python in run in version 3.9 in Debian 11
This is the python code
import serial
import aioserial
import asyncio
import time
import sys
import logging
class SerialListener:
def __init__(self, port="/dev/ttyUSB0", baudrate=9600):
self._port = port
self._baud_rate = baudrate
self._run = True
self._serial = None
self._logger = logging.getLogger()
async def stop(self):
self._run = False
async def start(self):
await self.reconnect()
await self.listen()
async def disconnect(self):
self._logger.info("Cleanup serial {}".format(self._port))
if self._serial is not None:
try:
self._serial.close()
except:
self._logger.info(sys.exc_info())
self._serial = None
async def reconnect(self):
await self.disconnect()
while self._serial is None:
try:
self._serial = aioserial.AioSerial(
port=self._port, baudrate=self._baud_rate
)
self._logger.info("Connected to {}".format(self._port))
except serial.serialutil.SerialException:
self._logger.info("{} not ready".format(self._port))
except:
self._logger.info(sys.exc_info())
await asyncio.sleep(1)
async def listen(self):
while self._run:
try:
data = await self._serial.read_until_async()
code = data.decode(errors="ignore").strip()
self._logger.info("Receive {}".format(code))
except asyncio.CancelledError:
break
except serial.serialutil.SerialException:
# Blocking call
await self.reconnect()
except:
self._logger.info(sys.exc_info())
await asyncio.sleep(0.1)
def main():
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s %(levelname)s %(name)s : %(message)s",
handlers=[logging.StreamHandler(sys.stdout)],
)
logger = logging.getLogger()
serial_listener = SerialListener(port="/dev/ttyUSB0", baudrate=9600)
loop = asyncio.get_event_loop()
try:
asyncio.ensure_future(serial_listener.start())
loop.run_forever()
except asyncio.CancelledError:
logger.info("Receive Cancel")
except KeyboardInterrupt:
logger.info("Receive Keyboard Interrupt")
except:
logger.info("Unknown Error")
logger.info(sys.exc_info())
finally:
logger.info("Stop application")
loop.run_until_complete(asyncio.wait([serial_listener.stop()]))
if __name__ == "__main__":
main()
This is arduino part
const int buttonPin = 4;
int buttonState = 0;
int value = 0;
void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
}
void loop() {
buttonState = digitalRead(4);
if (buttonState == HIGH)
{
value = 0x01;
} else if (buttonState == LOW)
{
value = 0x00;
}
if (Serial.available()) {
// Sending value to python
Serial.println(value);
}
delay(500);
}
It is very simple code, basically the arduino will send a value 0x01 when button is press and 0x00 when not every .5 second
When starting the python script, sometime the delay is lower then .5 second, and any button press in the arduino will not send the correct value , it kept sending the default value.
On re-connection either by repluging the usb cable or restarting the script might cause the same problem. The most visible is when I clear the terminal.
Testing same script in windows 10 with port COM3 ( using pyserial ) the problem doesn't seem to occur
Any idea what the cause ?
Hi,
I'm just about using your library. And it works fine so far, thank you.
However, i do not succeed in setting / clearing the RTS.
I need this to reset a esp8266 board.
the original esptool.py works like this:
def hard_reset(self):
self._setRTS(True) # EN->LOW
time.sleep(0.1)
self._setRTS(False)
but when i do this with your lib, this seems not to do anything :-(
any idea?
python 3.8
aioserial 1.2.3
pyserial 3.4
aio1= aioserial.AioSerial(port='/dev/ttyUSB0', baudrate='115200' )
print("reset rts ")
aio1.rts=False
await asyncio.sleep(0.1)
aio1.rts=True
aio1.is_open -> this one seems to be correct and usable
Hey there,
Thank you for creating this library I used this in an installation last year and it worked great!
Since then I am trying to rebuild the project and downloaded the updates you have made since then with pip3 install.
I followed your example given here, however maybe there have been changes which now makes this slightly out of date?
When running the code I now get an issue There is no current event loop in thread 'Thread-1
I wondered how I might adjust the example to work with the loop system?
many thanks in advance!
Hi~
when i send follow many times (in hex, no \r\n):
01 01 00 00 00 00
recv are:
b'\x07\x07\x83\x06\x06\x86'
b'IHII\xc9\xc9'
b'%%\x01!!%'
and the recv code is:
res = await self.ins.read_async(size=AckMsg.ack_size())
print("read data ok!", res)
why?
Hi,
The version check for the availability of get_running_loop fails for version 3.6.7
>>> sys.version_info
sys.version_info(major=3, minor=6, micro=7, releaselevel='final', serial=0)
>>> sys.version_info > (3, 6)
True
>>> asyncio.get_running_loop
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'asyncio' has no attribute 'get_running_loop'
https://github.com/changyuheng/aioserial/blob/ee2fc0e246c7e815c928e1d2d695f692e5ef9e9b/src/aioserial/aioserial.py#L56
https://github.com/changyuheng/aioserial/blob/ee2fc0e246c7e815c928e1d2d695f692e5ef9e9b/src/aioserial/aioserial.py#L57
asyncio.get_running_loop is new in version 3.7
Regards,
Seems like aioserial.cancel_read()
does not work. It might be that I am not aware of some concurrency rule(s), as I am quite inexperienced with asyncio
/aioserial
.
Here is the minimum steps to reproduce:
import asyncio
import time
import aioserial
async def read_and_print(port: aioserial.AioSerial):
while True:
try:
print("Reading....")
data: bytes = await port.read_async()
print(data, flush=True)
except asyncio.CancelledError:
print("Cancelled")
break
except Exception:
print("Other exception?")
break
async def wait_and_cancel(port: aioserial.AioSerial):
await asyncio.sleep(1)
print("Cancel request!")
port.cancel_read()
async def main():
port: aioserial.AioSerial = aioserial.AioSerial(port="COM6", baudrate=115200, timeout=5)
start = time.perf_counter()
await asyncio.gather(read_and_print(port), wait_and_cancel(port))
end = time.perf_counter()
print(f"Duration: {end-start:3f}")
if __name__ == "__main__":
asyncio.run(main())
Read timeout is intentionally set to 5 sec, while it should be canceled by cancel_read()
after 1 sec.
I would expect first cancel_read()
to throw exception and break out of read_and_print()
, something like this:
Reading....
Cancel request!
Cancelled
Duration: 1.001
Instead, nothing happens and loop is continuing:
Reading....
Cancel request!
b''
Reading....
b''
Reading....
b''
Reading....
b''
...
I've tested this with non-async version of the same code, with aioserial
(read()
running in thread, cancel_read()
in main), and it works, so it must be something related to async stuff.
Any help is very appreciated.
Like so:
Traceback (most recent call last):
File "discover.py", line 18, in <module>
asyncio.run(asyncio.gather(read_and_print(aioserial_instance), aioserial_instance.write_async(b'Hello, World!\n')))
File "/Users/up/anaconda3/envs/winch/lib/python3.8/asyncio/runners.py", line 37, in run
raise ValueError("a coroutine was expected, got {!r}".format(main))
ValueError: a coroutine was expected, got <_GatheringFuture pending>
Python 3.8
https://github.com/changyuheng/aioserial/blob/master/src/aioserial/aioserial.py#L61
Is this correct or a typo?
@property
def loop(self):
return self._loop
@loop.setter
self.loop = value
Hello,
Is there a way to discard unread data? My use case is that I send a command to a device, read the first line, an then discard all the data it sends until I send more data.
Thanks!
Example in README, aioserial equivalence
chapter, does not work.
Here is the traceback:
...test_aiserial.py:16: DeprecationWarning: There is no current event loop
asyncio.run(asyncio.gather(read_and_print(aioserial_instance), aioserial_instance.write_async(b"Hello, World!\n")))
Traceback (most recent call last):
File "...test_aiserial.py", line 16, in <module>
asyncio.run(asyncio.gather(read_and_print(aioserial_instance), aioserial_instance.write_async(b"Hello, World!\n")))
File "Python311\Lib\asyncio\runners.py", line 190, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "Python311\Lib\asyncio\runners.py", line 89, in run
raise ValueError("a coroutine was expected, got {!r}".format(coro))
ValueError: a coroutine was expected, got <_GatheringFuture pending>
sys:1: RuntimeWarning: coroutine 'AioSerial.write_async' was never awaited
sys:1: RuntimeWarning: coroutine 'read_and_print' was never awaited
VSCode Pylance static analysis reports:
Argument of type "Future[tuple[None, int]]" cannot be assigned to parameter "main" of type "Coroutine[Any, Any, _T@run]" in function "run"
"Future[tuple[None, int]]" is incompatible with "Coroutine[Any, Any, _T@run]"Pylance[reportGeneralTypeIssues](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportGeneralTypeIssues)
Windows 10, 64 bit
Python 3.11.0
aioserial==1.3.1
pyserial==3.5
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.