Constructing a script using a 3rd party library

70 views Asked by At

I have started to use a Raspberry Pi 4 with Python. The project I'm working on has led me to a published Python library on GitHub (keshavdv/victron-ble).

Having installed the library, I can successfully run from the CLI (discover, read, dump). However, trying to achieve the same through a Python script has left me head scratching.

CLI commands used:

victron-ble discover
victron-ble dump "b5:55:aa:4d:99:33"
victron-ble read "b5:55:aa:4d:99:33"@"eb8c557386614231dbd741db97e457c5"

This is the code that I have tried to use:

from victron_ble.cli import discover
from victron_ble.cli import dump
from victron_ble.cli import read

my_id = b'b5:55:aa:4d:99:33'
#where my_id is the MAC address of the device I wish to observe

my_key = 'eb8c557386614231dbd741db97e457c5'
#where my_key is the encypytion key of the device I wish to observe

dump_result = dump(my_key)
print(dump_result)

discover_result = discover()
print(discover_result)

Have tried the following format of the my_id variable in hope:

b'b5:55:aa:4d:99:33'
'b5:55:aa:4d:99:33'
'b555aa4d9933'
b'b5-55-aa-4d-99-33'
[b5:55:aa:4d:99:33]

One question would be, how would I replicate the CL instruction but with the script, in particular the format required for the MAC address and key. Thank you

2

There are 2 answers

2
ukBaz On

If I run with the code/script that you have posted I get the following error:

$ python3 with_cli_funcs.py 

Usage: with_cli_funcs.py [OPTIONS] ID
Try 'with_cli_funcs.py --help' for help.

Error: Got unexpected extra arguments (b 8 c 5 5 7 3 8 6 6 1 4 2 3 1 d b d 7 4 1 d b 9 7 e 4 5 7 c 5)

Process finished with exit code 2

This looks to me like the click library is expecting to inject the value in to the dump function with the decorators. https://github.com/keshavdv/victron-ble/blob/e28c5f8cc5f9f3062a2f36c2115d38214c07e741/victron_ble/cli.py#L45-L55

@cli.command(help="Dump all advertisements matching the given device ID")
@click.argument("id", type=str)
def dump(id: str):
    loop = asyncio.get_event_loop()


    async def scan():
        scanner = DebugScanner(id)
        await scanner.start()


    asyncio.ensure_future(scan())
    loop.run_forever()

I don't have any appropriate devices so I can't test this, but it would seem like the following should work:

import asyncio
import logging

from victron_ble.scanner import DebugScanner


def my_scan(id: str):
    loop = asyncio.get_event_loop()

    async def scan():
        scanner = DebugScanner(id)
        await scanner.start()

    asyncio.ensure_future(scan())
    loop.run_forever()


if __name__ == '__main__':
    my_id = 'b5:55:aa:4d:99:33'
    logger = logging.getLogger("victron_ble")
    logging.basicConfig()
    logger.setLevel(logging.DEBUG)
    my_scan(my_id)

2
IronDad75 On

So following the library script alongside the your answer script, I have amended to try and achieve the read function:

@cli.command(help="Read data from specified devices")
@click.argument("device_keys", nargs=-1, type=DeviceKeyParam())
def read(device_keys: List[Tuple[str, str]]):
    loop = asyncio.get_event_loop()

    async def scan(keys):
        scanner = Scanner(keys)
        await scanner.start()

    asyncio.ensure_future(scan({k: v for k, v in device_keys}))
    loop.run_forever()

Using this script:

import asyncio
import logging
from typing import List, Tuple

from victron_ble.scanner import Scanner


def my_scan(device_keys: List[Tuple[str, str]]):
    loop = asyncio.get_event_loop()

    async def scan(keys):
        scanner = Scanner(keys)
        await scanner.start()

    asyncio.ensure_future(scan({k: v for k, v in device_keys}))
    loop.run_forever()


if __name__ == '__main__':
    my_id = ("b5:55:aa:4d:99:33","149c3c2865054b71962dcb06866524a9")
    logger = logging.getLogger("victron_ble")
    logging.basicConfig()
    logger.setLevel(logging.DEBUG)
    my_scan(my_id)

Using the the value for my_id as above, returns error:

asyncio.ensure_future(scan({k: v for k, v in device_keys}))
                                     ^^^^
ValueError: too many values to unpack (expected 2)

If however, I amend the value of my_id to this:

my_id = ("b5:55:aa:4d:99:33@149c3c2865054b71962dcb06866524a9")

returns error:

asyncio.ensure_future(scan({k: v for k, v in device_keys}))
                                     ^^^^
ValueError: not enough values to unpack (expected 2, got 1)

The CLi argument to run that returns the correct result would be:

victron-ble read "b5:55:aa:4d:99:33"@"149c3c2865054b71962dcb06866524a9"

I'm guessing is a problem with my syntax within the script??