The new release of uasyncio
is pre-installed in current daily firmware
builds and will be found in release builds starting with V1.13. This complete
rewrite of uasyncio
supports CPython 3.8 syntax. A design aim is that it
should be be a compatible subset of asyncio
.
These notes and the tutorial should be read in conjunction with the official docs
This repo contains the following:
Documented in the tutorial.
Documented in the tutorial. Comprises:
- CPython primitives not yet officially supported.
- Two additional primitives
Barrier
andMessage
. - Classes for interfacing switches and pushbuttons.
- A software retriggerable monostable timer class, similar to a watchdog.
This lightweight scheduler enables tasks to be scheduled at future times. These can be assigned in a flexible way: a task might run at 4.10am on Monday and Friday if there's no "r" in the month.
These device drivers are intended as examples of asynchronous code which are useful in their own right:
- GPS driver Includes various GPS utilities.
- HTU21D Temperature and humidity sensor.
- I2C Use Pyboard I2C slave mode to implement a UART-like asynchronous stream interface. Uses: communication with ESP8266, or (with coding) interface a Pyboard to I2C masters.
- NEC IR A receiver for signals from IR remote controls using the popular NEC protocol.
- HD44780 Driver for common character based LCD displays based on the Hitachi HD44780 controller.
This monitor enables a
running uasyncio
application to be monitored using a Pi Pico, ideally with a
scope or logic analyser.
These notes are intended for users familiar with asyncio
under CPython.
The MicroPython language is based on CPython 3.4. The uasyncio
library now
supports a subset of the CPython 3.8 asyncio
library. There are non-standard
extensions to optimise services such as millisecond level timing. Its design
focus is on high performance. Scheduling runs without RAM allocation.
The uasyncio
library supports the following features:
async def
andawait
syntax.- Awaitable classes (using
__iter__
rather than__await__
). - Asynchronous context managers.
- Asynchronous iterators.
uasyncio.sleep(seconds)
.- Timeouts (
uasyncio.wait_for
). - Task cancellation (
Task.cancel
). - Gather.
It supports millisecond level timing with the following:
uasyncio.sleep_ms(time)
It includes the following CPython compatible synchronisation primitives:
Event
.Lock
.gather
.
This repo includes code for the CPython primitives which are not yet officially supported.
The Future
class is not supported, nor are the event_loop
methods
call_soon
, call_later
, call_at
.
V3 is still a work in progress. The following is a list of issues which I hope will be addressed in due course.
There is currently no support for this: I/O is scheduled in round robin fashion
with other tasks. There are situations where this is too slow, for example in
I2S applications and ones involving multiple fast I/O streams, e.g. from UARTs.
In these applications there is still a use case for the fast_io
V2 variant.
These CPython primitives are outstanding:
Semaphore
.BoundedSemaphore
.Condition
.Queue
.
Many applications using the coding style advocated in the V2 tutorial will work
unchanged. However there are changes, firstly to uasyncio
itself and secondly
to modules in this repository.
- Task cancellation:
cancel
is now a method of aTask
instance. - Event loop methods:
call_at
,call_later
,call_later_ms
andcall_soon
are no longer supported. In CPython docs these are lightly deprecated in application code; there are simple workrounds. yield
in coroutines must be replaced byawait asyncio.sleep_ms(0)
: this is in accord with CPython whereyield
will produce a syntax error.- Awaitable classes. The
__iter__
method works butyield
must be replaced byawait asyncio.sleep_ms(0)
.
It is possible to write an awaitable class with code portable between MicroPython and CPython 3.8. This is discussed in the tutorial.
Classes based on uio.IOBase
will need changes to the write
method. See
tutorial.
It is bad practice
to create tasks before issuing asyncio.run()
. CPython 3.8 throws if you do.
Such code can be ported by wrapping functions that create tasks in a
coroutine as below.
There is a subtlety affecting code that creates tasks early:
loop.run_forever()
did just that, never returning and scheduling all created
tasks. By contrast asyncio.run(coro())
terminates when the coro does. Typical
firmware applications run forever so the coroutine started by .run()
must
await
a continuously running task. This may imply exposing an asynchronous
method which runs forever:
async def main():
obj = MyObject() # Constructor creates tasks
await obj.run_forever() # Never terminates
def run(): # Entry point
try:
asyncio.run(main())
finally:
asyncio.new_event_loop()
Modules asyn.py
and aswitch.py
are deprecated for V3 applications. See
the tutorial for V3 replacements which
are more RAM-efficient.
These were formerly provided in asyn.py
and may now be found in the
primitives
directory, along with additional unofficial primitives.
The CPython asyncio
library supports these synchronisation primitives:
Lock
- already incorporated in newuasyncio
.Event
- already incorporated.gather
- already incorporated.Semaphore
andBoundedSemaphore
. In this repository.Condition
. In this repository.Queue
. In this repository.
The above unofficial primitives are CPython compatible. Using future official versions will require a change to the import statement only.
Applications using asyn.py
should no longer import that module. Equivalent
functionality may now be found in the primitives
directory: this is
implemented as a Python package enabling RAM savings. The new versions are also
more efficient, replacing polling with the new Event
class.
These features in asyn.py
were workrounds for bugs in V2 and should not be
used with V3:
- The cancellation decorators and classes (cancellation works as per CPython).
- The nonstandard support for
gather
(now properly supported).
The Event
class in asyn.py
is now replaced by Message
- this is discussed
in the tutorial.
Applications using aswitch.py
should no longer import that module. Equivalent
functionality may now be found in the primitives
directory: this is
implemented as a Python package enabling RAM savings.
New versions are provided in this repository. Classes:
Delay_ms
Software retriggerable monostable (watchdog-like object).Switch
Debounced switch with close and open callbacks.Pushbutton
Pushbutton with double-click and long press callbacks.