Anrijs / Aranet4-Python

Aranet4, Aranet2 and Aranet Radiation Python client
MIT License
212 stars 18 forks source link

is periodic on-demand scanning possible? #43

Open jonorthwash opened 3 months ago

jonorthwash commented 3 months ago

Given the issues calling asyncio more than once, is there a recommended way to on-demand scan (i.e., when some other function wants to)?

The aranet4.client.find_nearby() function, as used in the scanner_simple.py example, won't work because of the issues calling asynchio more than once.

Using aranet4.Aranet4Scanner() seems like a good alternative, but the scanner_advanced.py example is built around polling at a common interval. I need to poll periodically, triggered by some other action. If I have it .start() and .stop() every time it needs to poll, I assume I'll run into above-mentioned issues. Is there some way I can have it start, scan as requested (not with a fixed delay), and eventually stop?

Anrijs commented 3 months ago

scanner_advanced.py isn't using any intervals. It will set up scanner once with a callback function, that will be executed for every advertisement received, in the background.

If Aranet4Scanner doesn't fit you, you could also use plain BleakScanner. Just use Aranet4Advertisement to parse data:

import asyncio
from aranet4.client import Aranet4Advertisement
from aranet4.client import Aranet4
from bleak import BleakScanner

def process_advertisement(device, ad_data):
    adv = Aranet4Advertisement(device, ad_data)
    print(adv)

async def main():
    uuids = [Aranet4.AR4_SERVICE, Aranet4.AR4_OLD_SERVICE]
    scanner = BleakScanner(
        detection_callback=process_advertisement,
        service_uuids=uuids
    )
    await scanner.start()
    await asyncio.sleep(5)
    await scanner.stop()

asyncio.run(main())
jonorthwash commented 3 months ago

will be executed for every advertisement received, in the background.

If Aranet4Scanner doesn't fit you, you could also use plain BleakScanner. Just use Aranet4Advertisement to parse data

Both of these approaches, as I see them, are "always on", and use a sleep interval to determine how often they receive data. I would like something where I turn it on, wait for an advertisement, and turn it off, and can have this happen at will (and comparatively much more infrequently). Or am I misunderstanding how this code works?

Anrijs commented 3 months ago

Yes, they will be "always on", until stop() is called.

That sleep is there only to keep pogram open. It will not stop scanning and will receive and process advertisiements in background.

If you want to run scanner only at certain times, you will need to start and stop scanner yourself.

You could also use async with BleakScanner(callback) and ayncio.Event() to run in only when needed. Something like this:

import asyncio
import time
from aranet4.client import Aranet4Advertisement
from bleak import BleakScanner

# Your Aranet mac address
aranet_addr = 'AA:BB:CC:DD:EE:FF'

async def main():
    stop_event = None

    # callback for scanner
    def callback(device, ad_data):
        # if device address matches aranet address, set stop_event, that will stop scanner.
        if device.address == aranet_addr:
            adv = Aranet4Advertisement(device, ad_data)
            print("Found my aranet.")
            if adv:
                print(adv.readings.toString())
            stop_event.set()

    while True:
        stop_event = asyncio.Event()
        async with BleakScanner(callback):
            print("Scanner started")

            # wait for correct device in callback
            await stop_event.wait()
            print("Scanner stopped.")

        # do your own stuff here. sleep is just an example
        time.sleep(5)

asyncio.run(main())