Adam-Langley / pybleno

A direct port of the Bleno bluetooth LE peripheral role library to Python2/3
MIT License
68 stars 34 forks source link

Type of Encoding #40

Closed LVJ047 closed 5 years ago

LVJ047 commented 5 years ago

Hello Adam,

I am trying to advertise a string data using the BLE service with the characteristic property 'Indicate'


class EchoCharacteristic(Characteristic):

def __init__(self, uuid):
    Characteristic.__init__(self, {
        'uuid': uuid,
        'properties': ['indicate'],
        'value': None
      })

    self._value = array.array('B', [0] * 0)
    self._updateValueCallback = None

on subscribing to the service a string must be indicated on the mobile app


def onSubscribe(self, maxValueSize, updateValueCallback):
    print('EchoCharacteristic - onSubscribe')
    textgenerator(updateValueCallback)
    self._updateValueCallback = updateValueCallback

def textgenerator(updateValueCallback): bomb = 0 VIN_no = VIN[bomb] print("simulated VIN: " + VIN_no ) string_utf = b64encode(VIN_no.encode()) updateValueCallback(string_utf)


I am currently encoding the string VIN_no to utf8 and sending over to Pybleno GATT.py as the updateValueCallback takes only integer value because of the following error:


Exception in thread HCISocketPoller: Traceback (most recent call last): File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner self.run() File "/usr/lib/python3.5/threading.py", line 862, in run self._target(*self._args, *self._kwargs) File "/usr/local/lib/python3.5/dist-packages/pybleno/hci_socket/BluetoothHCI/BluetoothHCI.py", line 197, in _socket_poller self._socket_on_data_user_callback(bytearray(data)) File "/usr/local/lib/python3.5/dist-packages/pybleno/hci_socket/Hci.py", line 414, in onSocketData self.emit('aclDataPkt', [handle, cid, pktData]) File "/usr/local/lib/python3.5/dist-packages/pybleno/hci_socket/Emit.py", line 17, in emit handler(arguments) File "/usr/local/lib/python3.5/dist-packages/pybleno/hci_socket/Bindings.py", line 169, in onAclDataPkt self._aclStream.push(cid, data) File "/usr/local/lib/python3.5/dist-packages/pybleno/hci_socket/AclStream.py", line 18, in push self.emit('data', [cid, data]) File "/usr/local/lib/python3.5/dist-packages/pybleno/hci_socket/Emit.py", line 17, in emit handler(arguments) File "/usr/local/lib/python3.5/dist-packages/pybleno/hci_socket/Gatt.py", line 228, in onAclStreamData self.handleRequest(data) File "/usr/local/lib/python3.5/dist-packages/pybleno/hci_socket/Gatt.py", line 275, in handleRequest response = self.handleWriteRequestOrCommand(request) File "/usr/local/lib/python3.5/dist-packages/pybleno/hci_socket/Gatt.py", line 774, in handleWriteRequestOrCommand handleAttribute.emit('subscribe', [self._mtu - 3, updateValueCallback]) File "/usr/local/lib/python3.5/dist-packages/pybleno/hci_socket/Emit.py", line 17, in emit handler(arguments) File "Echo.py", line 53, in onSubscribe textgenerator(updateValueCallback) File "Echo.py", line 96, in textgenerator updateValueCallback(VIN_no) File "/usr/local/lib/python3.5/dist-packages/pybleno/hci_socket/Gatt.py", line 762, in updateValueCallback indicateMessage[3 + i] = data[i] TypeError: an integer is required (got type str)


but after encoding the pybleno is decoding it in a different type


elif useIndicate:
                                    indicateMessage = array.array('B', [0] * (3 + dataLength))

                                    writeUInt8(indicateMessage, ATT_OP_HANDLE_IND, 0)
                                    writeUInt16LE(indicateMessage, valueHandle, 1)

                                    for i in range(0, dataLength):
                                        indicateMessage[3 + i] = data[i]

                                    self._lastIndicatedAttribute = attribute

                                    # debug('indicate message: ' + indicateMessage.toString('hex'))
                                    self.send(indicateMessage)

                            return updateValueCallback

I am sending in string 'SALRHBBV0HA001734' but the pybleno is returning 'U0FMUkhCQIYwSEEwMDE3'

Can you please confirm what kind of encoding is required for the string when calling updateValueCallback()

Thanks Output: bleno - VIECOLNET Hit to disconnect on -> stateChange: poweredOn on -> advertisingStart: success on -> servicesSet: success on -> accept, client: 61:a6:28:b4:54:1d subscribed to temperature measurement indications simulated VIN: SALRHBBV0HA001734 Screenshot_20190723-130503 1

Adam-Langley commented 5 years ago

Hi @LVJ047 Bluetooth LE does not define encodings - everything is passed as a byte buffer. It's up to your client application to determine how to handle that byte buffer when receiving. You need to convert your data to a buffer/array before passing it back - it does not accept strings (as per the error message).

There is no point in base-64 encoding your string before converting it to a byte array - that will only server to bloat the payload. Please look at the examples https://github.com/Adam-Langley/pybleno/blob/master/examples/batteryservice/BatteryLevelCharacteristic.py

See how responses are always converted to arrays/buffers.

Try something like this:

 def textgenerator(updateValueCallback):
   bomb = 0
   VIN_no = VIN[bomb]
   print("simulated VIN: " + VIN_no )
   # string_utf = b64encode(VIN_no.encode())
   buffer_utf = bytes(VIN_no, 'utf-8')
   updateValueCallback(buffer_utf)