Search code examples
pythonclassreturnbluetooth-lowenergyglobal-variables

Extracting a streaming return variable in my class


I'm using bluepy and I have a base code to read values comming from an arduino now I have the problem that when I try to extrac the variable num or tum from def handleNotification I don't have any succes in the code:

So I want to print the variable to use it in a formula in a while.

A second option will be asking how can I simplyfy my code to just connect and receive data?

This is my code:

from bluepy import btle

class MyDelegate(btle.DefaultDelegate):
    def __init__(self):
        btle.DefaultDelegate.__init__(self)
        # ... initialise here

    def handleNotification(self, cHandle, data):
        print("\n- handleNotification -\n")
        #print(data)
        num = list(data)[0]
        #print(num)
        tum = int.from_bytes(data, byteorder='big')
        #print(tum)
        #print(data.decode("utf-8"))#newline
        # ... perhaps check cHandle
        # ... process 'data'


# Initialisation  -------

p = btle.Peripheral("3a:dc:f3:6f:b1:dc")
p.setDelegate( MyDelegate() )

# Setup to turn notifications on, e.g.
svc = p.getServiceByUUID("81c30e5c-1101-4f7d-a886-de3e90749161")
ch = svc.getCharacteristics("81c30e5c-2101-4f7d-a886-de3e90749161")[0]
#   ch.write( setup_data )

setup_data = b"\x01\00"
p.writeCharacteristic(ch.valHandle+1, setup_data)

# Main loop --------

while True:
    if p.waitForNotifications(1.0):
        # handleNotification() was called
        continue

    print("Waiting...")
    # Perhaps do something else here

Solution

  • It is not clear from your question what you want to do with the number that you have read from the Arduino.

    A typical structure might be to have the BLE code to only handle reading the code from the Arduino, turning it from bytes to some other structure before passing it along. Characteristic values will always be sent as bytes and may have a number of values packed into one notification.

    One way to structure your could be to pass a function name to the MyDelegate and that be used when notifications happen. For example

    from bluepy import btle
    
    
    def my_main_code(new_value):
        print(new_value)
    
    
    class MyDelegate(btle.DefaultDelegate):
        def __init__(self, callback):
            self.callback = callback
            btle.DefaultDelegate.__init__(self)
            # ... initialise here
    
        def handleNotification(self, cHandle, data):
            # Convert data to be easily consumed by callback
            tum = int.from_bytes(data, byteorder='big')
            self.callback(tum)
    
    
    # Initialisation  -------
    p = btle.Peripheral("3a:dc:f3:6f:b1:dc")
    p.setDelegate( MyDelegate(my_main_code) )
    
    # Setup to turn notifications on, e.g.
    svc = p.getServiceByUUID("81c30e5c-1101-4f7d-a886-de3e90749161")
    ch = svc.getCharacteristics("81c30e5c-2101-4f7d-a886-de3e90749161")[0]
    
    setup_data = b"\x01\00"
    p.writeCharacteristic(ch.valHandle+1, setup_data)
    
    # Main loop --------
    
    while True:
        if p.waitForNotifications(1.0):
            # handleNotification() was called
            continue
    
        print("Waiting...")
    

    To respond to your "update 2" about the value from Bluetooth defining what gets sent over mqtt I've done the following. There needs to be a a lot of disclaimers around this as I have no way of testing this. I have tried to follow as closely as possible the structure in your question along with a few assumptions (that may be incorrect). The structure of the code could be something like this:

    from bluepy import btle
    import paho.mqtt.publish as publish
    
    hostname = "????????"
    
    
    def publish_mqtt(new_value):
        print(new_value)
        if new_value == 1:
            publish.single("dance/lights", "on", hostname=hostname)
        else:
            publish.single("dance/lights", "off", hostname=hostname)
    
    
    class MyDelegate(btle.DefaultDelegate):
        def __init__(self, callback):
            self.callback = callback
            btle.DefaultDelegate.__init__(self)
            # ... initialise here
    
        def handleNotification(self, cHandle, data):
            # Convert data to be easily consumed by callback
            tum = int.from_bytes(data, byteorder='big')
            self.callback(tum)
    
    
    # Initialisation  -------
    p = btle.Peripheral("3a:dc:f3:6f:b1:dc")
    p.setDelegate(MyDelegate(publish_mqtt))
    
    # Setup to turn notifications on, e.g.
    svc = p.getServiceByUUID("81c30e5c-1101-4f7d-a886-de3e90749161")
    ch = svc.getCharacteristics("81c30e5c-2101-4f7d-a886-de3e90749161")[0]
    
    setup_data = b"\x01\00"
    p.writeCharacteristic(ch.valHandle+1, setup_data)
    
    # Main loop --------
    
    while True:
        if p.waitForNotifications(1.0):
            # handleNotification() was called
            continue
    
        print("Waiting...")