Giter Club home page Giter Club logo

pyserial-asyncio's Introduction

pyserial-asyncio's People

Contributors

adminiuga avatar andrewleech avatar barobo avatar elupus avatar iiseymour avatar jabdoa2 avatar potens1 avatar puddly avatar rob-smallshire avatar septatrix avatar smurfix avatar spacemanspiff2007 avatar stlehmann avatar thedrow avatar wolfmanjm avatar zsquareplusc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyserial-asyncio's Issues

How would you pass parameters to generator returned from create_serial_connection()

e.g.

class MyProt(asyncio.Protocol)
    #BlahBlahBlah

loop = asyncio.get_event_loop()
prot = serial_asyncio.create_serial_connection(loop, MyProt, port, baudrate, myParam)
loop.run_until_complete(prot)

At this point I can't find a way to interact with bert and other parametrs such as MyParam are passed to pyserial. Is there a proper way to pass parameters to the creation of the MyProt instance that is done internally by asyncio?

I would like to be able to supply myParam or do something like bert.set_feature() but that does not work due to the way asyncio works.

I've tried hacking it with

_prot = prot.gi_frame.f_locals['args'][1]
_prot.set_feature(_prot, feature)

But that access the unbound MyProt rather than the running prot.

Handling Input/output error

Hello,
I've tried to use the example from the documentation to get data from my device and got an error, when I plug out the usb cable. At the same time, the main loop continues. How can I handle this error?

Traceback

Exception in callback SerialTransport._call_connection_lost(SerialExcepti...s on port?)',))
handle: <Handle SerialTransport._call_connection_lost(SerialExcepti...s on `port?)',))>`
Traceback (most recent call last):
  File "/usr/lib/python3.5/asyncio/events.py", line 125, in _run
    self._callback(*self._args)
  File "/usr/local/lib/python3.5/dist-packages/serial/aio.py", line 345, in _call_connection_lost
    self._serial.flush()
  File "/usr/local/lib/python3.5/dist-packages/serial/serialposix.py", line 578, in flush
    termios.tcdrain(self.fd)
termios.error: (5, 'Input/output error')

serial write is not non blocking

Using this on a Ubuntu linux system (14.04) I found that I got the following exception while writing to the serial port.

This would imply that the write is not correctly set to non blocking in the posix serial transport.

I'll continue to debug this issue.

protocol: <__main__.SerialConnection object at 0xb6d0bd8c>
transport: SerialTransport(<_UnixSelectorEventLoop running=True closed=False debug=False>, <__main__.SerialConnection object at 0xb6d0bd8c>, Serial<id=0xb6d0b9ac, open=True>(port='/dev/ttyACM0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=0, xonxoff=False, rtscts=False, dsrdtr=False))
Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/pyserial-3.3-py3.4.egg/serial/serialposix.py", line 534, in write
    n = os.write(self.fd, d)
BlockingIOError: [Errno 11] Resource temporarily unavailable

Socket support

When passing in socket://127.0.0.1:9999 as port to create_serial_connection to connect an EchoServerClientProtocol an AttributeError is thrown on accessing self._serial.fd.

File "/usr/local/lib/python3.5/site-packages/serial/aio.py", line 260, in _ensure_reader
    self._loop.add_reader(self._serial.fd, self._read_ready)
AttributeError: 'Serial' object has no attribute 'fd'

How would you flush the stream reader?

I want to clear the input buffer when starting a new request. Clearing the input buffer of the serial instance seems to not help - I'd guess the received data is already fed to the stream reader.
And at this point I don't now how to clear the bytes in the stream reader. reader.read() is a coroutine and is "blocking" until data is available. Additionally I didn't find a way to get the amount of bytes in the stream reader (then I would be able to read the amount of bytes and the buffer would be cleared).

How am I supposed to just clear the read stream?

StreamReader.read(n) returns incorrect amount of bytes

I am continuously receiving 5 byte frames via. serial and created a task that is supposed to do just that, unfortunately sometimes the .read(5) returns less than 5 bytes.
Am I doing something wrong or what is going on here?
I verified the received data with a serial terminal and that looked good.

My code is something like this:

async def open(self):
    self.reader, self.writer = await serial_asyncio.open_serial_connection(
                url="/dev/ttyUSB0", baudrate=115200
            )

async def read_task(self):
    data = await self.reader.read(5)
    await self.process_data(data)

connection lost - why?

Hi,
Thank you for working on this very nice library.

I tried copying the example from here: https://pyserial-asyncio.readthedocs.io/en/latest/shortintro.html and changed the baudrate etc.
The serial port is connected to an arduino uno running grbl and when i use the normal pyserial library this behaves as expected.
But when I run that sample program - the serialport is connected, I get some feed back from the arduino board (not all) and then the program just closes - see below

$ python serialaio.py
port opened SerialTransport(<_UnixSelectorEventLoop running=True closed=False debug=False>, <main.Output object at 0x1058bd4a8>, Serial<id=0x1058bd278, open=True>(port='/dev/cu.usbmodem1411', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=0, xonxoff=False, rtscts=False, dsrdtr=False))
data received b'\r\nG'
port closed

Is this caused by some bug in the pyserial-aio library or is it something else?

Thank you in advance

P.S.
I am running this on a macos, using python 3.6 and serial_asyncio v. 0.4

Serial rts on connection made

On connection made rts is set to False, is there a reason for doing so?

def connection_made(self, transport):
    self.transport = transport
    print('port opened', transport)
    transport.serial.rts = False
    transport.write(b'hello world\n')

Improve the API design of create_serial_connection

The implementation of create_serial_connection currently creates the Serial object, forwarding the *args and **kwargs parameters. A more flexible design would be to allow a Serial instance to be passed in by the caller.

Support for rs485

Hi there! I am currently working on migrating a real-time communications program from sync Python2.7 to async Python3.7. This program manages mobile radio devices via serial; each one with a different set of settings. The only thing that I'm missing right now is support for rs485 serials. PySerial has a 'rs485 mode' implementation, but I haven't seen anything about it on this library.

Is there any way to work around this (maybe a wrap around serial.rs48.RS485)?

Thanks,

Upload a package to pypi

Can you upload a release to pypi? That will allow us to simplify our install instructions for users. Currently, users have to install it from git with pip manually. With a pypi package we could just add it as dependency in setup.py.

Assertion Problems On Windows

We have a case where we hit this assertion on windows: https://github.com/pyserial/pyserial-asyncio/blob/master/serial_asyncio/__init__.py#L121

Can somebody explain the rational behind this assertion to me? n == 0 seems totally legit. Internally, os.write is called which may return 0. This seems to never happen on linux but on windows.

In my opinion the assert should be like this:
assert n >= 0 < len(data)

Same probably applies to this line: https://github.com/pyserial/pyserial-asyncio/blob/master/serial_asyncio/__init__.py#L262

There's no way to close the streams returned by open_serial_connection

With pyserial-asyncio 0.4 and python-3.8.0. This program:

import asyncio                                                                                      
import serial_asyncio                                                                               
                                                                                                    
async def main():                                                                                   
        (tty_read,tty_write) = await serial_asyncio.open_serial_connection(url="loop://")                                                                                    
                                                                                                    
asyncio.run(main())        

Outputs:

An open stream was garbage collected prior to establishing network connection; call "stream.close()" explicitly.

Yet there doesn't seem to be a way to close the streams:

tty_read.close()
AttributeError: 'StreamReader' object has no attribute 'close'

tty_write.close()
AttributeError: 'NoneType' object has no attribute 'flush'

Consider Adding Support For `loop://`

Per Pyserial URL Handlers documentation it's useful to have a loop:// handler. In unit testing I've used this extensively for simple testing. This avoids having to setup a TCP socket server as done in #1 .

Would it be possible to better support this? My hunch is this has something to do with how pyserial handles the loop:// functionality and it may not work well with asyncio.

Tests

Running the base pyserial-asyncio boilerplate code with loop:// shown below:

    loop = asyncio.get_event_loop()
    coro = serial_asyncio.create_serial_connection(loop, faraday.Output, 'loop://', baudrate=115200)
    loop.run_until_complete(coro)
    loop.run_forever()
    loop.close()

Results in the following output which is missing the "Hello, world" text that is expected (using pytest):

(.venv) bryce@bryce-ubuntu:~/Documents/git/faradayio$ sudo .venv/bin/python3 -m pytest -sk serialAsyncio
============================= test session starts ==============================
platform linux -- Python 3.5.2, pytest-3.4.1, py-1.5.2, pluggy-0.6.0
rootdir: /home/bryce/Documents/git/faradayio, inifile:
plugins: cov-2.5.1
collecting 34 items                                                            WARNING: No route found for IPv6 destination :: (no default route?). This affects only IPv6
collected 39 items                                                             

tests/test_serial.py port opened SerialTransport(<_UnixSelectorEventLoop running=True closed=False debug=False>, <faradayio.faraday.Output object at 0x7f571ca91b00>, Serial<id=0x7f571ca91b38, open=True>(port='loop://', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=0, xonxoff=False, rtscts=False, dsrdtr=False))
port closed
.

============================= 38 tests deselected ==============================
=================== 1 passed, 38 deselected in 0.38 seconds ====================

Yet the same code using a loopback hardware serial device on /dev/ttyUSB0 results in:

=================== 1 passed, 38 deselected in 0.40 seconds ====================
(.venv) bryce@bryce-ubuntu:~/Documents/git/faradayio$ sudo .venv/bin/python3 -m pytest -sk serialAsyncio
============================= test session starts ==============================
platform linux -- Python 3.5.2, pytest-3.4.1, py-1.5.2, pluggy-0.6.0
rootdir: /home/bryce/Documents/git/faradayio, inifile:
plugins: cov-2.5.1
collecting 34 items                                                            WARNING: No route found for IPv6 destination :: (no default route?). This affects only IPv6
collected 39 items                                                             

tests/test_serial.py port opened SerialTransport(<_UnixSelectorEventLoop running=True closed=False debug=False>, <faradayio.faraday.Output object at 0x7ff7bcb159e8>, Serial<id=0x7ff7c248c6a0, open=True>(port='/dev/ttyUSB0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=0, xonxoff=False, rtscts=False, dsrdtr=False))
data received b'Hello, World!\n'
port closed
.

============================= 38 tests deselected ==============================
=================== 1 passed, 38 deselected in 0.38 seconds ====================

@coroutine deprecated in Python 3.8

.venv/lib/python3.8/site-packages/serial_asyncio/__init__.py:409
  ../.venv/lib/python3.8/site-packages/serial_asyncio/__init__.py:409: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
    def create_serial_connection(loop, protocol_factory, *args, **kwargs):

And from https://docs.python.org/3/library/asyncio-task.html:

Note: Support for generator-based coroutines is deprecated and is scheduled for removal in Python 3.10.

How to read chunks from the serial port

Currently the callback gets called for every single character that comes over the serial.
Is it possible to read e.g. 100chars with a timeout so it's either 100 chars or timeout?
I am getting really high CPU usage (~5-10%) for a program that reads with 9600 baud.

Make loop parameter optional

For more information about the loop parameter see What are all these deprecated “loop” parameters in asyncio? and Passing asyncio loop by argument or using default asyncio loop.

For most use cases the loop parameter is not needed and is deprecated in most high level APIs since 3.8 and will be removed in 3.10. The main reason for its existence were a bad specification of asyncio.get_event_loop (<3.6) and poor performance (<3.7). However these are fixed now. While I am not sure about deprecating the loop parameter like it is done in the high level asyncio interfaces I think we should probably make the argument a keyword-only argument or at least optional.

This will make the API easier to understand and simpler for newcomers. However we should probably think of a good conversion plan (we are still in 0.x so semver allows breaking changes).

Thread-based sender

In MPF we use pyserial-asyncio to write to serials with up to 6MBaud/s. Unfortunately, we fail to saturate the serial as soon as the asyncio loop is not completely idle (even idle it is far from perfect). This is mostly caused by very small serial buffers in the linux kernel (1024 bytes by default) which can only be adjusted at compile time. Saturating a 6M serial with a 1024 byte buffer requires nearly 6.000 wake-ups per second with very low jitter which is the reason why this will never work properly.

To solve this we use separate threads (using asyncio's run_in_executor). Would you be up to support that in pyserial-asyncio? I would port our sender code to pyserial-asyncio in that case.

Higher level API that matches pyserial

Hey, I am excited for asyncio support for pyserial as our Braille E-Book reader uses pyserial as it's main communication link to the display.

Having used aiofiles I was expecting an API like this (for python 3.5+):

async with serial_asyncio.Serial('/dev/ttyS1', 19200, timeout=1) as ser:
     x = await ser.read()          
     s = await ser.read(10)  
     line = await ser.readline()  
     await ser.write(b'hello') 

Is something like this planned?

Improve Windows Support

The current implementation does not support Windows.
TODO: provide one
pull requests are welcome

Documentation

Is there more detailed documentation? I am kind of a newbie on python and I think this library could help with the issue I am working on but I have no clue what is going on because there is nothing besides a minimally commented example.

Provide serial object via Transport.get_extra_info()

Currently the serial object can be accessed via the .serial property. However asyncio provides a prefered way to access information about the transport and the underlying resources which is BaseTransport.get_extra_info.

To align more closely to the stdlib I would like to have this implemented (or make a PR as it does not seem to hard). Personally I would also vote for deprecating the direct access property but I would also understand keeping it as a shorthand...

termios.error on connection lost

Hi,

I am not sure where to report this, if here or to pyserial, but i am sure, that you will know what to do with it...

While playing with pyserial.aio and try to build serial server, which waits for USB/UART adapter to be connected, then process incoming data and if the connection will lost, then again wait for adapter. I start with base example there with virtual serial port (created via socat) and all seems to work, except situation when i simulate connection lost (exit the socat), where i got exception, which i was not able to catch:

Exception in callback SerialTransport._call_connection_lost(SerialExcepti...s on port?)',))
handle: <Handle SerialTransport._call_connection_lost(SerialExcepti...s on port?)',))>
Traceback (most recent call last):
  File "/usr/lib64/python3.4/site-packages/serial/aio.py", line 346, in _call_connection_lost
    self._serial.flush()
  File "/usr/lib64/python3.4/site-packages/serial/serialposix.py", line 550, in flush
    termios.tcdrain(self.fd)
termios.error: (5, 'Input/output error')

This exception causes, that the loop is not closed inside the connection_lost method in Output class (because it is not called at all), the connection stays open and when the port is created again, it is not more connected to program.

After small investigation in the /usr/lib64/python3.4/site-packages/serial/aio.py file (from pyserial 3.1.1 on my Funtoo Linux) i found that in the _call_connection_lost (the SerialTransport class) is called self._serial.flush(), where exception occurs (because there is no more this port in system). After i changed the line 345:

self._serial.flush()

to ignore this exception (because it is expected):

try:
    self._serial.flush()
except termios.error:
    pass

(and appropriate import termios of course) all seems to work as expected, i.e. the connection_lost method of the Output class is called and loop is closed.

I am not Python nor pyserialúasyncio expert, then i am not sure if this is solution or workaround, but i see that similar solution is

SerialTransport._poll_read() raises serial.serialutil.SerialException: ClearCommError failed (OSError(9, 'The handle is invalid.', None, 6)) when the serial port is late to open

Poll Read exception serial.serialutil.SerialException: ClearCommError failed (OSError(9, 'The handle is invalid.', None, 6))

System

- Windows 10 Pro 64 bit
- Python 3.7.4 32 bit
- pySerial 3.4
- pyserial-asyncio 0.4

Repo steps

- have to integrate a class (SerialFactory) that creates a async serial loop in a thread
- at some point this object needs to be destroyed (shutdown of the DUT) and then recreated
- when recreating the serial connection the serial port probably is not released fast enough. The SerialTransport calls _poll_read() and finds no self._port_handle

exception log

Exception in callback SerialTransport._poll_read()
handle: <TimerHandle when=370365.4535 SerialTransport._poll_read()>
Traceback (most recent call last):
File "D:\python\373\lib\asyncio\events.py", line 88, in _run
self._context.run(self._callback, *self.args)
File "D:\python\373\lib\site-packages\serial_asyncio_init
.py", line 276, in _poll_read
if self.serial.in_waiting:
File "D:\python\373\lib\site-packages\serial\serialwin32.py", line 257, in in_waiting
raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError()))
serial.serialutil.SerialException: ClearCommError failed (OSError(9, 'The handle is invalid.', None, 6))

proposed solution

A simple check that self.serial._port_handle is not None works
for SerialTransport._poll_read()
```python
    if os.name == "nt":
    def _poll_read(self):
        if self._has_reader:
            if self.serial._port_handle and self.serial.in_waiting:
            # if self.serial.in_waiting:
                self._loop.call_soon(self._read_ready)
            self._loop.call_later(self._poll_wait_time, self._poll_read)
```

The solution can be applied to SerialTransport._pool_write() though I haven't encountered any exceptions here 

```python 
        def _poll_write(self):
        if self._has_writer:
            if self.serial._port_handle and self.serial.out_waiting:
                self._loop.call_soon(self._write_ready)
            self._loop.call_later(self._poll_wait_time, self._poll_write)
```

serial_asyncio_port_handle_exception.txt

assert from write_ready

I have a low bandwidth serial read/write (read ~16 bytes at 0.5 Hz/~16 bytes at 1.0 Hz). I've confirmed that I only have one transport.write and that the amount of data being written is always > 0. Periodically, I see a stack trace where an is raised
assert data, 'Write buffer should not be empty'
I added if len(data) == 0: print("len = 0") and set a breakpoint on it. The callstack showed the following
_run, events.py:80
_run_once, base_events.py:1890
run_forever, base_events.py:596

I set breakpoints on connection lost and didn't hit that and I don't believe that the transport was closed.

How to catch the coroutine error?

Hi~ Nice work!

When i try to call create_serial_connection to open a port which is already opened by other tool, i just keep got serial.serialutil.SerialException: could not open port 'COM8': PermissionError, how can i to catch this error in a graceful way?

Crash on linux/posix in fast path

We saw this error several times with different users. However, it happens very rarely and I only got it reproduced once (from missionpinball/mpf#951):

asyncio : Unhandled error in exception handler
context: {'transport': SerialTransport(<_UnixSelectorEventLoop running=True closed=False debug=False>, <asyncio.streams.StreamReaderProtocol object at 0x7fc746514b00>, Serial<id=0x7fc74643fda0, open=True>(port='/dev/ttyUSB0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=0, xonxoff=False, rtscts=False, dsrdtr=False)), 'exception': SerialTimeoutException('Write timeout',), 'protocol': <asyncio.streams.StreamReaderProtocol object at 0x7fc746514b00>, 'message': 'Fatal write error on serial transport'}
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/serial/serialposix.py", line 534, in write
    n = os.write(self.fd, d)
BlockingIOError: [Errno 11] Resource temporarily unavailable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/data/home/jan/cloud/flipper/src/pyserial-asyncio/serial_asyncio/__init__.py", line 120, in write
    n = self._serial.write(data)
  File "/usr/local/lib/python3.5/dist-packages/serial/serialposix.py", line 568, in write
    raise writeTimeoutError
serial.serialutil.SerialTimeoutException: Write timeout

RFC2217 and pyserial-asyncio

Trying to connect to remote serial port served by ser2net with pyserial-asyncio. Fails due to error:
NotImplementedError: write_timeout is currently not supported

Trace:

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../nextion/client.py:53: in connect
    _, self.connection = await serial_asyncio.create_serial_connection(loop, self.make_protocol, url=self.url, baudrate=self.baudrate)
/usr/lib/python3.6/asyncio/coroutines.py:212: in coro
    res = func(*args, **kw)
/usr/local/lib/python3.6/dist-packages/serial_asyncio/__init__.py:412: in create_serial_connection
    transport = SerialTransport(loop, protocol, ser)
/usr/local/lib/python3.6/dist-packages/serial_asyncio/__init__.py:64: in __init__
    self._serial.write_timeout = 0
/usr/lib/python3/dist-packages/serial/serialutil.py:388: in write_timeout
    self._reconfigure_port()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Serial<id=0x7f37b3c5f2e8, open=True>(port='rfc2217://192.168.1.2:1900', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=0, xonxoff=False, rtscts=False, dsrdtr=False)

    def _reconfigure_port(self):
        """Set communication parameters on opened port."""
        if self._socket is None:
            raise SerialException("Can only operate on open ports")
    
        # if self._timeout != 0 and self._interCharTimeout is not None:
            # XXX
    
        if self._write_timeout is not None:
>           raise NotImplementedError('write_timeout is currently not supported')
E           NotImplementedError: write_timeout is currently not supported

/usr/lib/python3/dist-packages/serial/rfc2217.py:506: NotImplementedError

pyserial-asyncio sets write timeout here:

self._serial.write_timeout = 0

Similar issue on pyserial side: pyserial/pyserial#412

AttributeError: 'NoneType' object has no attribute 'write'

Hi
I've been trying to periodically write back data to a serial port, but it throws the following issue
AttributeError: 'NoneType' object has no attribute 'write'
any help is really appreciated

import asyncio
import serial_asyncio
import codecs


_reader=_writer=None 



async def SerialReader(loop):
    global _reader,_writer
    _reader,_writer = await serial_asyncio.open_serial_connection(url='COM7', baudrate=57600,loop=loop)
    while True:
            line = await _reader.readline()
            print(codecs.encode(line, 'base64'))
            
async def serialWriteLoop(writer,f):
    message =b'>*>p0x0800'
    while True:
        print(b'>*>p0x0800')
        for b in message:
            writer.write(bytes([b]))
        await asyncio.sleep(1/f);
        
loop = asyncio.new_event_loop();
asyncio.set_event_loop(loop)#
loop.run_until_complete(asyncio.gather(SerialReader(loop),serialWriteLoop(_writer,1)))
loop.run_forever() 
loop.close()

Is this Project still alive and maintained?

It seems like there wasn't any activity in this repository in the last couple years. Is there anyone else maintaining a fork or some other async implementation of serial?

How to use await

This may well be because of a misunderstanding of this package, but
how would I await within say connection_made within the example code?

No continuous builds

We need to get Travis CI up and running on this repo, but first we need some tests to run.

Write() does not do a genuine async write

Strictly speaking the write() does not do a real async write if the write buffer is empty. Even though the serial.write() is non blocking, doing a real write there is technically incorrect IMO.

In addition as there is a bug in the posix serial.write() where writing to a port that is not ready will cause it to enter a tight loop continously throwing an EAGAIN exception, so we end up effectively with a blocking write. See pyserial/pyserial#280.

The code I modified (and use) here does a real async write (every write gets buffered and executed asynchronously. This also avoids the aforementioned bug in serial.write().

If this is something you feel is the correct way to do it, let me know and I'll submit a PR.

I do undestand that issuing a genuine serial.write() if the buffer is empyy maybe more efficient so I could undersand why my solution may not be acceptible. (that is presuming the serial.write() bug is fixed). I have a workaround in the existing write() that I could submit that also avoids that bug, but keeps the instant write if the write buffer is empty.

Consider support for trio

Hi, I’ve been using pyserial-asyncio for a little bit now, and I have a suggestion. Right now the library is implemented on top of asyncio, but the result is that you don’t get a single file-like object to interact with as you do in the synchronous case.

I’ve recently been looking at trio which is an async framework inspired by David Beazley’s curio. Neither are built on asyncio, but trio especially looks much easier to use than asyncio. There is a ton of fantastic documentation that comes with trio, and there's a ton of testing/debugging/introspection facilities.

To give you an idea of how nice trio is to use, it provides a function trio.wrap_file() which takes a file-like object and returns another file-like object whose read, write, etc methods are all awaitable (you can still get to the non-file attributes through foo.wrapped.bar). In fact, I used this function to wrap a Serial instance, and in most cases it seems to work just like a natively async Serial class would. The wrap_file() function actually uses threads to do this, and as a result there are some edge cases where the wrapped object can become unresponsive. That’s why I’m requesting a trio-native Serial class.

What are your thoughts?

socket:// support on Windows

I've made a small change to a local checkout to support socket:// connections (for the purpose of building a fake for testing when hardware is not available/connected):

in _poll_write() (line 304 in master as of 25 AUG 2021), the attempt to read self.serial.out_waiting fails with an AttributeError because the Socket transport does not implement out_waiting.

I wrapped the call as follows:

try:
  if serial.out_waiting < self.max_out_waiting:
    self._write_ready()
except AttributeError:
   self.write_ready()

This seems to fix the issue with socket:// connections and doesn't break other usage, because if out_waiting exists the check runs as implemented.

If this is acceptable I can submit a pull request -- I'd like to get this upstream so my team doesn't need to maintain a fork!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.