Example - Asyncio

A common requirement is to forward received RFM69 packets onward to a web API. However HTTP requests can be slow and we need to consider how to manage possible delays. If we block the radio receiver loop while making the necessary HTTP request, then time critical messages will be forced to wait!

We could solve this problem in a number of ways. In this example we are going to use Asyncio. It’s worth mentioning here that although Asyncio is often touted as the wonder child of Python 3, asynchronous processing is not new to Python. More importantly, Asyncio is not a silver bullet and depending on your task may not be the best solution. I am not going to go over old ground talking about the pros and cons of async vs sync or concurrency and parallelism, Abu Ashraf Masnun has a nice article called Async Python: The Different Forms of Concurrency which I think covers this topic well.

Install the additional dependencies

pip install aiohttp cchardet aiodns

Asyncio RESTful API Gateway

The destination url is set to http://httpbin.org/post. This is a free online service which will echo back the post data sent to the service. It has a whole host (pardon the pun) of other tools for testing HTTP clients.

# pylint: disable=missing-function-docstring,redefined-outer-name

import asyncio
from aiohttp import ClientSession
from RFM69 import Radio, FREQ_433MHZ

async def call_API(url, packet):
    async with ClientSession() as session:
        print("Sending packet to server")
        async with session.post(url, json=packet.to_dict('%c')) as response:
            response = await response.read()
            print("Server responded", response)

async def receiver(radio):
    while True:
        print("Receiver")
        for packet in radio.get_packets():
            print("Packet received", packet.to_dict())
            await call_API("http://httpbin.org/post", packet)
        await asyncio.sleep(10)

async def send(radio, to, message):
    print ("Sending")
    if radio.send(to, message, attempts=3, waitTime=100):
        print ("Acknowledgement received")
    else:
        print ("No Acknowledgement")

async def pinger(radio):
    print("Pinger")
    counter = 0
    while True:
        await send(radio, 2, "ping {}".format(counter))
        counter += 1
        await asyncio.sleep(5)


loop = asyncio.get_event_loop()
node_id = 1
network_id = 100
with Radio(FREQ_433MHZ, node_id, network_id, isHighPower=True, verbose=False) as radio:
    print ("Started radio")
    loop.create_task(receiver(radio))
    loop.create_task(pinger(radio))
    loop.run_forever()

loop.close()