#CircuitPython BLE ManufacturerData

1 messages · Page 1 of 1 (latest)

pallid holly
#

Thanks @north ember! the second github project was extremely helpful. I now understand how the Manufacture data is used and was able to get my scan code working.

This might be a little specific but I cant seem to get my ManufacturerDataFields to parse correctly now that I have the ManufactureData working. Any ideas? Here is my current code:

#
class SonyAdvertisement(ProvideServicesAdvertisement):
    """Sony camera ProvideServicesAdvertisement subclass."""

    # Defines a key to match this class with scanned ProvideServicesAdvertisement
    #   Matches Sony Manufacture Code (0x2D, 0x01) and Device Code (camera = 0x03, 0x00) in little endian
    match_prefixes = (struct.pack(">BBBBB", 0xFF, 0x2D, 0x01, 0x03, 0x00),)

    name = None
    """Human readable name, populated later with the data from an Advertisement."""

    # Defines the manufacture_data structure based on the provided Compand ID. Necessary for ManufacturerDataField parsing.
    manufacturer_data = LazyObjectField(
        ManufacturerData,
        "manufacturer_data",
        advertising_data_type = 0xFF,
        company_id = 0x2D01,
        key_encoding = ">B",
    )

    pairing_status = ManufacturerDataField(0x22, ">H")
    """Pairing status of the device."""


def ScanForCameras():
    logger.info("Scanning")
    devices = {}
    for advertisement in ble.start_scan(SonyAdvertisement, Advertisement, timeout=5):
        if isinstance(advertisement, SonyAdvertisement):
            if advertisement.address not in devices:
                devices[advertisement.address] = advertisement
                logger.debug(f"Found: {advertisement}")
        elif isinstance(advertisement, Advertisement):
            if advertisement.address in devices and devices[advertisement.address].name is None:
                devices[advertisement.address].name = advertisement.complete_name
                logger.debug(f"{advertisement.complete_name} is at {advertisement.address}")
        else:
            logger.warning(f"Unknown advertisement type: {type(advertisement)}")

    for address, advertisement in devices.items():
        logger.info(f"Found {advertisement.name} at {address}, status: {advertisement.pairing_status}")
#

Its a bit hard to read but here is my code output:

70937.5: INFO - Scanning
70937.6: DEBUG - Found: <SonyAdvertisement manufacturer_data=<ManufacturerData company_id=2d01 data=03 00 65 00 0f 33 22 bb 00 21 60 00 23 b7 0c 00 00 00 00 00 > services=<BoundServiceList: UUID(0x1800)> flags=<AdvertisingFlags limited_discovery general_discovery le_only > >
70937.6: DEBUG - Jingleheimer-A7M4 is at <Address d0:40:ef:e0:ff:ba>
70942.5: INFO - Found Jingleheimer-A7M4 at <Address d0:40:ef:e0:ff:ba>, status: None

I can see the key 0x22 I want in the ManufacturerData but for some reason, status in the last line (which is my ManufactuererDataField) is still coming back as None

north ember
#

one way to debug this is to get the .py version of the adafruit_ble library and put some print statements in various places

pallid holly
#

The endian indicators are on purpose to match the guides I am following that reverse engineered the data.

#

Interesting idea, so essentially drop some debug into the library to see whats going on. Ill give that a shot. Thanks!

pallid holly
#

@north ember thanks again for your help so far, I am slowly but surely making progress I think. I've hit another roadblock though and wonder if you might have some wisdom. I've got my app using the BLE library to sending commands to a WRITE Characteristic as the Central. However, I'm struggling to get data back from that same Service via a NOTIFY Characteristic.

Digging through the BLE and BLEIO libraries I noticed the BLE wrapper library does not expose the ability to enable notifications via the CCCD function BLEIO exposes (https://circuitpython.readthedocs.io/en/latest/shared-bindings/_bleio/index.html#bleio.Characteristic.set_cccd) Am I missing something? Additionally, I'm not seeing a good way to set a callback in the BLE library for Notify characteristics like you can in the Arduino implementation, maybe the BLE lib is missing this whole feature?

north ember
pallid holly
#

Yea I used the BatteryService as a template for creating my Service class implementation, so I'm glad I stumbled on that. Maybe I am just accessing the Notify data improperly?.... Here is what I have for my service class and how I'm using the connection:

class CameraRemoteControlService(Service):
    """Provides a Service to control the camera with a small subset of features."""

    SHUTTER_RELEASED = 0x0601
    PRESS_TO_FOCUS = 0x0701
    HOLD_FOCUS = 0x0801
    TAKE_PICTURE = 0x0901

    uuid = VendorUUID("8000FF00-FF00-FFFF-FFFF-FFFFFFFFFFFF")
    
    RemoteNotify = StructCharacteristic(
        "<BBB",
        properties=Characteristic.NOTIFY,
        uuid=StandardUUID(0xFF02),
    )

    RemoteCommand = Uint32Characteristic(
        properties=Characteristic.WRITE,
        uuid=StandardUUID(0xFF01),
    )

# Logic in here that scans and establishes the connection omitted for cleanliness....

## Attempt to use one of the provided device services
if CameraRemoteControlService in connection:
    logger.debug("Found service!")
    connection[CameraRemoteControlService].RemoteCommand = CameraRemoteControlService.PRESS_TO_FOCUS
    time.sleep(1.5)
    print(connection[CameraRemoteControlService].RemoteNotify)  # Is this right for accessing the notify data?
else:
    logger.debug("No service found...")
    print(connection)

What I get is the following error from accessing RemoteNotify:

160049.0: DEBUG - Found service!
Traceback (most recent call last):
  File "code.py", line 159, in <module>
  File "code.py", line 149, in ScanForCameras
  File "adafruit_ble/characteristics/__init__.py", line 246, in __get__
  File "adafruit_ble/characteristics/__init__.py", line 142, in __get__
_bleio.BluetoothError: Unknown gatt error: 0x0102
#

Interestingly, the BatterService is both READ and NOTIFY. The Characteristic im attempting to get is only NOTIFY according to the nRF Connect app I used to get a little more insight. Maybe that is why I cant read it via the Connection?

north ember
pallid holly
#

I am acting as a central. the CameraRemoteControlService is remote to me

#

Here's a bit of info I scanned on the service Im trying to use:

#

I can see the data im interested (three bytes) via the app when I enable the Notification for the NOTIFY Characteristic. Needing to enable those notifications is what led to my question about setting the CCCD in BLEIO

north ember
#

note the bind(), which has a set_cccd() in it, and then temperature_humidity(), which reads from the _readings_buf into data, and then checks the length. The _readings_buf is a one-element buffer, so it doesn't keep more than one reading at a time.

#

this is all quite complicated, sorry, and not well documented

pallid holly
#

OK cool! Ill dig through that a bit. Thanks again!

#

No worries, its hard to document every situation someone may want to accomplish

north ember
#

so you would make RemoteNotify be a subclass of ComplexCharacteristic`, as done in there.

#

there's a lot of reflection and Python trickery going on under the covers