6
\$\begingroup\$

I am trying to use bluepy to write and read serial data to/from an HC-08 Bluetooth module. The HC-08 is connected to a device that returns a fixed number of bytes whenever it receives a message over the HC-08.

Below is my code so far. This seems to work—however, I kind of winged this code from examples and an a lot of trial and error. I am not entirely sure what I am doing. Therefore, any comments/feedback for potential improvements would be very welcome. The code is implemented as a class myhc08 that has a write method. This method writes a string to the hc08 and then reads out a set number of bytes.

import struct
import bluepy.btle as btle
from matplotlib import pyplot

class ReadDelegate(btle.DefaultDelegate):
    def __init__(self):
        self.data = b''
        
    def reset(self):
        self.data = b''
    
    def handleNotification(self, cHandle, data):
        self.data = self.data + data
    
    @property
    def data_length(self):
        return len(self.data)

class myHC08:
    def __init__(self):
        self.mac = '34:14:B5:50:34:77'
        self.write_service_id = 4
        self.write_service = None
        self.peripheral = btle.Peripheral(self.mac)
        self.delegate = ReadDelegate()
        self.peripheral.withDelegate(self.delegate)
        
    def connect(self):
        s = self.write_service_id
        services = self.peripheral.getServices()
        self.write_service = self.peripheral.getServiceByUUID(list(services)[s].uuid)
    
    def write(self, message, min_bytes, unpack_string=False):
        print('Writing:', message)
        self.delegate.reset()
        c = self.write_service.getCharacteristics()[0]
        c.write(bytes(message, "utf-8"))
        print('Receiving %i bytes' % min_bytes)
        while self.peripheral.waitForNotifications(1): pass
        while self.delegate.data_length < min_bytes: pass
        received = self.delegate.data
        if unpack_string: received = struct.unpack(unpack_string,received)
        return received
        
    def disconnect(self):
        self.peripheral.disconnect()
    


bt = myHC08()
bt.connect()
r = bt.write('1*', 1250*2, '1250H')
bt.disconnect()

In case this helps, my computer lists the following UUIDs for the HC-08 device:

00001800-0000-1000-8000-00805f9b34fb Generic Access
00001801-0000-1000-8000-00805f9b34fb Generic Attribute
0000180a-0000-1000-8000-00805f9b34fb Device Information
0000ffe0-0000-1000-8000-00805f9b34fb Unknown
0000fff0-0000-1000-8000-00805f9b34fb Unknown
\$\endgroup\$
1
  • 3
    \$\begingroup\$ Welcome to Code Review! \$\endgroup\$
    – Reinderien
    Nov 5, 2020 at 14:30

1 Answer 1

4
\$\begingroup\$

Concatenation

In computer science terms, depending on a lot of things, this:

    self.data = self.data + data

can be worst-case O(n^2). This happens when the Python runtime needs to work reallocating everything in the existing buffer before it's able to add new data. One way around this is to use BytesIO instead.

Casting to a list

Based on the documentation:

getServices() / Returns a list of Service objects

Since it's already a list, there is no need to re-cast to a list here:

    self.write_service = self.peripheral.getServiceByUUID(list(services)[s].uuid)

Disconnection safety

Since myHC08 has a disconnect method, it should be made into a context manager, and used in a with statement; or at the least:

bt.connect()
try:
    r = bt.write('1*', 1250*2, '1250H')
finally:
    bt.disconnect()
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Thank you very much for this. I will implement these suggestions. Thanks for catching those. \$\endgroup\$ Nov 5, 2020 at 19:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.