def main(): # initialize I2C i2c = board.I2C() # initialize sensors bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c) sht31d = adafruit_sht31d.SHT31D(i2c) # initialize BLE ble = BLERadio() # create custom advertisement object advertisement = IOTGAdvertisement() # set device name ble.name = "IOTG1" # set initial value # will use only first 5 chars of name advertisement.md_field = ble.name[:5] + "0000" # BLRE advertising interval in seconds BLE_ADV_INT = 0.2 # start BLE advertising ble.start_advertising(advertisement, interval=BLE_ADV_INT) # main loop while True: # print values - this will be available on serial print("Temperature: {:.1f} C".format(bmp280.temperature)) print("Humidity: {:.1f} %".format(sht31d.relative_humidity)) # get sensor data T = int(bmp280.temperature) H = int(sht31d.relative_humidity) # stop advertsing ble.stop_advertising() # update advertisement data advertisement.md_field = ble.name[:5] + chr(T) + chr(H) + "00" # start advertising ble.start_advertising(advertisement, interval=BLE_ADV_INT) # sleep for 2 seconds time.sleep(2)
class NametagsApp: def __init__(self, init_ui=True): self.ble = BLERadio() ui.display_qr(self.addr_suffix) self.nameservice = NameService() self.advertisement = ProvideServicesAdvertisement(self.nameservice) self.scan_response = Advertisement() self.scan_response.complete_name = "BADGE-{}".format(self.addr_suffix) self.ble.start_advertising(self.advertisement, self.scan_response) @property def addr_suffix(self): addr = self.ble.address_bytes return "{:02X}{:02X}{:02X}".format(addr[3], addr[4], addr[5]) def update(self): if self.ble.connected: self.nameservice.update() ui.display_qr(self.addr_suffix) def process_input(self): buttons = badge.gamepad.get_pressed() if buttons & badge.BTN_ACTION: self.cleanup() return True return False def run(self): self.running = True while self.running: self.process_input() self.update() def cleanup(self): self.ble.stop_advertising() self.running = False
ble.name = "Sense" # The Bluefruit Playground app looks in the manufacturer data # in the advertisement. That data uses the USB PID as a unique ID. # Feather Bluefruit Sense USB PID: # This board is not yet support on the app. # Arduino: 0x8087, CircuitPython: 0x8088 adv = AdafruitServerAdvertisement() adv.pid = 0x8088 while True: # Advertise when not connected. ble.start_advertising(adv) while not ble.connected: pass ble.stop_advertising() while ble.connected: now_msecs = time.monotonic_ns() // 1000000 # pylint: disable=no-member if now_msecs - accel_last_update >= accel_svc.measurement_period: accel_svc.acceleration = lsm6ds33.acceleration accel_last_update = now_msecs if now_msecs - baro_last_update >= baro_svc.measurement_period: baro_svc.pressure = bmp280.pressure baro_last_update = now_msecs button_svc.set_pressed(False, not button.value, False) if now_msecs - humidity_last_update >= humidity_svc.measurement_period:
class Radio: """ Represents a connection through which one can send or receive strings and bytes. The radio can be tuned to a specific channel upon initialisation or via the `configure` method. """ def __init__(self, **args): """ Takes the same configuration arguments as the `configure` method. """ # For BLE related operations. self.ble = BLERadio() # The uid for outgoing message. Incremented by one on each send, up to # 255 when it's reset to 0. self.uid = 0 # Contains timestamped message metadata to mitigate report of # receiving of duplicate messages within AD_DURATION time frame. self.msg_pool = set() # Handle user related configuration. self.configure(**args) def configure(self, channel=42): """ Set configuration values for the radio. :param int channel: The channel (0-255) the radio is listening / broadcasting on. """ if -1 < channel < 256: self._channel = channel else: raise ValueError("Channel must be in range 0-255") def send(self, message): """ Send a message string on the channel to which the radio is broadcasting. :param str message: The message string to broadcast. """ return self.send_bytes(message.encode("utf-8")) def send_bytes(self, message): """ Send bytes on the channel to which the radio is broadcasting. :param bytes message: The bytes to broadcast. """ # Ensure length of message. if len(message) > MAX_LENGTH: raise ValueError( "Message too long (max length = {})".format(MAX_LENGTH)) advertisement = _RadioAdvertisement() # Concatenate the bytes that make up the advertised message. advertisement.msg = struct.pack("<BB", self._channel, self.uid) + message self.uid = (self.uid + 1) % 255 # Advertise (block) for AD_DURATION period of time. self.ble.start_advertising(advertisement) time.sleep(AD_DURATION) self.ble.stop_advertising() def receive(self): """ Returns a message received on the channel on which the radio is listening. :return: A string representation of the received message, or else None. """ msg = self.receive_full() if msg: return msg[0].decode("utf-8").replace("\x00", "") return None def receive_full(self): """ Returns a tuple containing three values representing a message received on the channel on which the radio is listening. If no message was received then `None` is returned. The three values in the tuple represent: * the bytes received. * the RSSI (signal strength: 0 = max, -255 = min). * a microsecond timestamp: the value returned by time.monotonic() when the message was received. :return: A tuple representation of the received message, or else None. """ try: for entry in self.ble.start_scan(_RadioAdvertisement, minimum_rssi=-255, timeout=1, extended=True): # Extract channel and unique message ID bytes. chan, uid = struct.unpack("<BB", entry.msg[:2]) if chan == self._channel: now = time.monotonic() addr = entry.address.address_bytes # Ensure this message isn't a duplicate. Message metadata # is a tuple of (now, chan, uid, addr), to (mostly) # uniquely identify a specific message in a certain time # window. expired_metadata = set() duplicate = False for msg_metadata in self.msg_pool: if msg_metadata[0] < now - AD_DURATION: # Ignore expired entries and mark for removal. expired_metadata.add(msg_metadata) elif (chan, uid, addr) == msg_metadata[1:]: # Ignore matched messages to avoid duplication. duplicate = True # Remove expired entries. self.msg_pool = self.msg_pool - expired_metadata if not duplicate: # Add new message's metadata to the msg_pool and # return it as a result. self.msg_pool.add((now, chan, uid, addr)) msg = entry.msg[2:] return (msg, entry.rssi, now) finally: self.ble.stop_scan() return None
class BLEHID(AbstractHID): def post_init(self, ble_name='KMK Keyboard', **kwargs): self.conn_id = -1 self.ble = BLERadio() self.ble.name = ble_name self.hid = HIDService() self.hid.protocol_mode = 0 # Boot protocol # Security-wise this is not right. While you're away someone turns # on your keyboard and they can pair with it nice and clean and then # listen to keystrokes. # On the other hand we don't have LESC so it's like shouting your # keystrokes in the air if not self.ble.connected or not self.hid.devices: self.start_advertising() self.conn_id = 0 @property def devices(self): """Search through the provided list of devices to find the ones with the send_report attribute.""" if not self.ble.connected: return [] result = [] # Security issue: # This introduces a race condition. Let's say you have 2 active # connections: Alice and Bob - Alice is connection 1 and Bob 2. # Now Chuck who has already paired with the device in the past # (this assumption is needed only in the case of LESC) # wants to gather the keystrokes you send to Alice. You have # selected right now to talk to Alice (1) and you're typing a secret. # If Chuck kicks Alice off and is quick enough to connect to you, # which means quicker than the running interval of this function, # he'll be earlier in the `self.hid.devices` so will take over the # selected 1 position in the resulted array. # If no LESC is in place, Chuck can sniff the keystrokes anyway for device in self.hid.devices: if hasattr(device, "send_report"): result.append(device) return result def _check_connection(self): devices = self.devices if not devices: return False if self.conn_id >= len(devices): self.conn_id = len(devices) - 1 if self.conn_id < 0: return False if not devices[self.conn_id]: return False return True def hid_send(self, evt): if not self._check_connection(): return device = self.devices[self.conn_id] while len(evt) < len(device._characteristic.value) + 1: evt.append(0) return device.send_report(evt[1:]) def clear_bonds(self): import _bleio _bleio.adapter.erase_bonding() def next_connection(self): self.conn_id = (self.conn_id + 1) % len(self.devices) def previous_connection(self): self.conn_id = (self.conn_id - 1) % len(self.devices) def start_advertising(self): advertisement = ProvideServicesAdvertisement(self.hid) advertisement.appearance = BLE_APPEARANCE_HID_KEYBOARD self.ble.start_advertising(advertisement) def stop_advertising(self): self.ble.stop_advertising()
class Ble(): def __init__(self, onConnectionStateChanged, onAdvertising=None, onWrite=None): self._ble = BLERadio() self._uart_server = UARTService() self._onAdvertising = onAdvertising self._onWrite = onWrite self._advertisement = ProvideServicesAdvertisement(self._uart_server) self._isAdvertising = False self._onAdvertising = onAdvertising self._onWrite = onWrite self.__oldConnectionState = False self._onConnectionStateChanged = onConnectionStateChanged self._enabled = False def write(self, data): if self._ble.connected: self._uart_server.write(data) if self._onWrite: self._onWrite(data) def startAdvertising(self): if not self._ble.connected: self.stopAdvertising() self._ble.start_advertising(self._advertisement) display("Start Phone App and connect") display("Started Advertising to BLE devices") if self._onAdvertising: self._onAdvertising() self._isAdvertising = True def stopAdvertising(self): # if self._ble.connected: display("Stopped Advertising") self._ble.stop_advertising() self._isAdvertising = False def read(self): if self._ble.connected != self.__oldConnectionState: self._onConnectionStateChanged() self.__oldConnectionState = self._ble.connected def enable(self): self.startAdvertising() self._enabled = True def disable(self): self.stopAdvertising() self._enabled = False def toggle(self): if self._enabled: self.disable() else: self.enable() @property def isAdvertising(self): return self._isAdvertising @property def connected(self): return self._ble.connected @property def enabled(self): return self._enabled
###################################################### # Main Code ###################################################### while True: print("WAITING for BlueFruit device...") # Advertise when not connected. ble.start_advertising(advertisement) # Tell other devices that Clue has a Bluetooth UART connection. while not ble.connected: # Check to see if another device has connected with the Clue via Bluetooth. if clue.button_a: break pass # Do nothing this loop. # Connected ble.stop_advertising() # Stop telling other devices about the Clue's Bluetooth UART Connection. print("CONNECTED") # Loop and read packets while ble.connected: # Check to see if we are still connected. if clue.button_a: break # Keeping trying until a good packet is received try: packet = Packet.from_stream(uart_server) # Try to get new messages from connected device. except ValueError: continue # Only handle button packets
def main(): DEBUG = True BOARD = True #flag indicating whether attached to a board. try: import board except NotImplementedError: # no board attached so mock sensors, services etc import mock as mk print('No valid board. Using mock sensors and services') BOARD = False # sensors import adafruit_lsm6ds.lsm6ds33 # motion import adafruit_lis3mdl # magnetometer import adafruit_apds9960.apds9960 # EMR import time dummy_sensor = DummySensor() if BOARD: # valid board present use real sensors import analogio battery = analogio.AnalogIn(board.VOLTAGE_MONITOR) motion = adafruit_lsm6ds.lsm6ds33.LSM6DS33(board.I2C()) magnet = adafruit_lis3mdl.LIS3MDL(board.I2C()) emr = adafruit_apds9960.apds9960.APDS9960(board.I2C()) # emr.enable_proximity = True emr.enable_color = True # Create and initialize the available services. ble = BLERadio() battery_svc = BatteryService() motion_svc = MotionService() magnet_svc = MagnetService() emr_svc = EMRService() dummy_svc = DummyService() adv = PhysBrykServerAdvertisement() else: #use mock sensors and services # Accelerometer and gyro motion = mk.Sensor() magnet = mk.Sensor() emr = mk.Sensor() battery = mk.Sensor() ble = mk.Service() battery_svc = mk.Service() motion_svc = mk.Service() magnet_svc = mk.Service() emr_svc = mk.Service() dummy_svc = mk.Service() adv = mk.Service() ble.name = "PhysBryk_Alpha" last_update = 0 while True: # Advertise when not connected. ble.start_advertising(adv) if DEBUG: print('Connecting...') while not ble.connected: pass ble.stop_advertising() if DEBUG: print('Connected!') while ble.connected: now_msecs = time.monotonic_ns() // 1000000 # pylint: disable=no-member if now_msecs - last_update >= MEASUREMENT_PERIOD: battery_svc.voltage = battery_svc.get_voltage(battery) motion_svc.acceleration = motion.acceleration # m/s/s motion_svc.gyro = motion.gyro # rad/s magnet_svc.magnetic = magnet.magnetic # microT emr_svc.intensity = emr_svc.get_lux(emr.color_data) emr_svc.spectrum = emr.color_data emr_svc.proximity = emr.proximity dummy_svc.value = 42 dummy_sensor.update() last_update = now_msecs if DEBUG: print(f'motion acceleration: {motion_svc.acceleration}') print(f'motion gyro: {motion_svc.gyro}') print(f'magnet magnet: {magnet_svc.magnetic}') print(f'emr intensity: {emr_svc.intensity}') print(f'emr spectrum: {emr_svc.spectrum}') print(f'emr proximity: {emr_svc.proximity}') print(f'battery: {battery_svc.voltage}') print(f'dummy: {dummy_svc.value}') if not BOARD: for s in mk.sensors: s.update()
class Split(Module): '''Enables splitting keyboards wirelessly, or wired''' def __init__( self, split_flip=True, split_side=None, split_type=SplitType.UART, split_target_left=True, uart_interval=20, data_pin=None, data_pin2=None, target_left=True, uart_flip=True, debug_enabled=False, ): self._is_target = True self._uart_buffer = [] self.split_flip = split_flip self.split_side = split_side self.split_type = split_type self.split_target_left = split_target_left self.split_offset = None self.data_pin = data_pin self.data_pin2 = data_pin2 self.target_left = target_left self.uart_flip = uart_flip self._is_target = True self._uart = None self._uart_interval = uart_interval self._debug_enabled = debug_enabled if self.split_type == SplitType.BLE: try: from adafruit_ble import BLERadio from adafruit_ble.advertising.standard import ( ProvideServicesAdvertisement, ) from adafruit_ble.services.nordic import UARTService self.ProvideServicesAdvertisement = ProvideServicesAdvertisement self.UARTService = UARTService except ImportError: print('BLE Import error') return # BLE isn't supported on this platform self._ble = BLERadio() self._ble_last_scan = ticks_ms() - 5000 self._connection_count = 0 self._uart_connection = None self._advertisment = None self._advertising = False self._psave_enable = False def during_bootup(self, keyboard): # Set up name for target side detection and BLE advertisment name = str(getmount('/').label) if self.split_type == SplitType.BLE: self._ble.name = name else: # Try to guess data pins if not supplied if not self.data_pin: self.data_pin = keyboard.data_pin # Detect split side from name if self.split_side is None: if name.endswith('L'): # If name ends in 'L' assume left and strip from name self._is_target = bool(self.split_target_left) self.split_side = SplitSide.LEFT elif name.endswith('R'): # If name ends in 'R' assume right and strip from name self._is_target = not bool(self.split_target_left) self.split_side = SplitSide.RIGHT # if split side was given, find master from split_side. elif self.split_side == SplitSide.LEFT: self._is_target = bool(self.split_target_left) elif self.split_side == SplitSide.RIGHT: self._is_target = not bool(self.split_target_left) # Flips the col pins if PCB is the same but flipped on right if self.split_flip and self.split_side == SplitSide.RIGHT: keyboard.col_pins = list(reversed(keyboard.col_pins)) self.split_offset = len(keyboard.col_pins) if self.split_type == SplitType.UART and self.data_pin is not None: if self._is_target: self._uart = busio.UART( tx=self.data_pin2, rx=self.data_pin, timeout=self._uart_interval ) else: self._uart = busio.UART( tx=self.data_pin, rx=self.data_pin2, timeout=self._uart_interval ) # Attempt to sanely guess a coord_mapping if one is not provided. if not keyboard.coord_mapping: keyboard.coord_mapping = [] rows_to_calc = len(keyboard.row_pins) * 2 cols_to_calc = len(keyboard.col_pins) * 2 for ridx in range(rows_to_calc): for cidx in range(cols_to_calc): keyboard.coord_mapping.append(intify_coordinate(ridx, cidx)) def before_matrix_scan(self, keyboard): if self.split_type == SplitType.BLE: self._check_all_connections() self._receive_ble(keyboard) elif self.split_type == SplitType.UART: if self._is_target or self.data_pin2: self._receive_uart(keyboard) elif self.split_type == SplitType.ONEWIRE: pass # Protocol needs written return def after_matrix_scan(self, keyboard): if keyboard.matrix_update: if self.split_type == SplitType.UART and self._is_target: pass # explicit pass just for dev sanity... elif self.split_type == SplitType.UART and ( self.data_pin2 or not self._is_target ): self._send_uart(keyboard.matrix_update) elif self.split_type == SplitType.BLE: self._send_ble(keyboard.matrix_update) elif self.split_type == SplitType.ONEWIRE: pass # Protocol needs written else: print('Unexpected case in after_matrix_scan') return def before_hid_send(self, keyboard): if not self._is_target: keyboard.hid_pending = False return def after_hid_send(self, keyboard): return def on_powersave_enable(self, keyboard): if self.split_type == SplitType.BLE: if self._uart_connection and not self._psave_enable: self._uart_connection.connection_interval = self._uart_interval self._psave_enable = True def on_powersave_disable(self, keyboard): if self.split_type == SplitType.BLE: if self._uart_connection and self._psave_enable: self._uart_connection.connection_interval = 11.25 self._psave_enable = False def _check_all_connections(self): '''Validates the correct number of BLE connections''' self._connection_count = len(self._ble.connections) if self._is_target and self._connection_count < 2: self._target_advertise() elif not self._is_target and self._connection_count < 1: self._initiator_scan() def _initiator_scan(self): '''Scans for target device''' self._uart = None self._uart_connection = None # See if any existing connections are providing UARTService. self._connection_count = len(self._ble.connections) if self._connection_count > 0 and not self._uart: for connection in self._ble.connections: if self.UARTService in connection: self._uart_connection = connection self._uart_connection.connection_interval = 11.25 self._uart = self._uart_connection[self.UARTService] break if not self._uart: if self._debug_enabled: print('Scanning') self._ble.stop_scan() for adv in self._ble.start_scan( self.ProvideServicesAdvertisement, timeout=20 ): if self._debug_enabled: print('Scanning') if self.UARTService in adv.services and adv.rssi > -70: self._uart_connection = self._ble.connect(adv) self._uart_connection.connection_interval = 11.25 self._uart = self._uart_connection[self.UARTService] self._ble.stop_scan() if self._debug_enabled: print('Scan complete') break self._ble.stop_scan() def _target_advertise(self): '''Advertises the target for the initiator to find''' self._ble.stop_advertising() if self._debug_enabled: print('Advertising') # Uart must not change on this connection if reconnecting if not self._uart: self._uart = self.UARTService() advertisement = self.ProvideServicesAdvertisement(self._uart) self._ble.start_advertising(advertisement) self.ble_time_reset() while not self.ble_rescan_timer(): self._connection_count = len(self._ble.connections) if self._connection_count > 1: self.ble_time_reset() if self._debug_enabled: print('Advertising complete') break self._ble.stop_advertising() def ble_rescan_timer(self): '''If true, the rescan timer is up''' return bool(ticks_diff(ticks_ms(), self._ble_last_scan) > 5000) def ble_time_reset(self): '''Resets the rescan timer''' self._ble_last_scan = ticks_ms() def _send_ble(self, update): if self._uart: try: if not self._is_target: update[1] += self.split_offset self._uart.write(update) except OSError: try: self._uart.disconnect() except: # noqa: E722 if self._debug_enabled: print('UART disconnect failed') if self._debug_enabled: print('Connection error') self._uart_connection = None self._uart = None def _receive_ble(self, keyboard): if self._uart is not None and self._uart.in_waiting > 0 or self._uart_buffer: while self._uart.in_waiting >= 3: self._uart_buffer.append(self._uart.read(3)) if self._uart_buffer: keyboard.secondary_matrix_update = bytearray(self._uart_buffer.pop(0)) return def _send_uart(self, update): # Change offsets depending on where the data is going to match the correct # matrix location of the receiever if self._is_target: if self.split_target_left: update[1] += self.split_offset else: update[1] -= self.split_offset else: if self.split_target_left: update[1] += self.split_offset else: update[1] -= self.split_offset if self._uart is not None: self._uart.write(update) def _receive_uart(self, keyboard): if self._uart is not None and self._uart.in_waiting > 0 or self._uart_buffer: if self._uart.in_waiting >= 60: # This is a dirty hack to prevent crashes in unrealistic cases import microcontroller microcontroller.reset() while self._uart.in_waiting >= 3: self._uart_buffer.append(self._uart.read(3)) if self._uart_buffer: keyboard.secondary_matrix_update = bytearray(self._uart_buffer.pop(0)) return
class BLEHID(AbstractHID): BLE_APPEARANCE_HID_KEYBOARD = const(961) # Hardcoded in CPy MAX_CONNECTIONS = const(2) def __init__(self, ble_name=str(getmount('/').label), **kwargs): self.ble_name = ble_name super().__init__() def post_init(self): self.ble = BLERadio() self.ble.name = self.ble_name self.hid = HIDService() self.hid.protocol_mode = 0 # Boot protocol # Security-wise this is not right. While you're away someone turns # on your keyboard and they can pair with it nice and clean and then # listen to keystrokes. # On the other hand we don't have LESC so it's like shouting your # keystrokes in the air if not self.ble.connected or not self.hid.devices: self.start_advertising() @property def devices(self): '''Search through the provided list of devices to find the ones with the send_report attribute.''' if not self.ble.connected: return {} result = {} for device in self.hid.devices: if not hasattr(device, 'send_report'): continue us = device.usage up = device.usage_page if up == HIDUsagePage.CONSUMER and us == HIDUsage.CONSUMER: result[HIDReportTypes.CONSUMER] = device continue if up == HIDUsagePage.KEYBOARD and us == HIDUsage.KEYBOARD: result[HIDReportTypes.KEYBOARD] = device continue if up == HIDUsagePage.MOUSE and us == HIDUsage.MOUSE: result[HIDReportTypes.MOUSE] = device continue if up == HIDUsagePage.SYSCONTROL and us == HIDUsage.SYSCONTROL: result[HIDReportTypes.SYSCONTROL] = device continue return result def hid_send(self, evt): if not self.ble.connected: return # int, can be looked up in HIDReportTypes reporting_device_const = evt[0] device = self.devices[reporting_device_const] report_size = len(device._characteristic.value) while len(evt) < report_size + 1: evt.append(0) return device.send_report(evt[1:report_size + 1]) def clear_bonds(self): import _bleio _bleio.adapter.erase_bonding() def start_advertising(self): if not self.ble.advertising: advertisement = ProvideServicesAdvertisement(self.hid) advertisement.appearance = self.BLE_APPEARANCE_HID_KEYBOARD self.ble.start_advertising(advertisement) def stop_advertising(self): self.ble.stop_advertising()
class Room: def __init__(self, use_debug=False): self.use_debug = use_debug self.subscription_ids = {} self.subscription_messages_on_reconnect = [] self.ble = BLERadio() self.uart_server = UARTService() self.advertisement = ProvideServicesAdvertisement(self.uart_server) self.chunk_size = 20 # adafruit_ble can only write in 20 byte chunks self.recv_msg_cache = "" def debug(self, msg): if self.use_debug: print(msg) def cleanup(self): self.uart_server.write('~:\n'.encode("utf-8")) def claim(self, claim_str): # Cleanup claim = cleanup all previous claims self.uart_server.write('N:{}\n'.format(claim_str).encode("utf-8")) def when(self, query_strings, callback): x = str(random.randint(0, 9999)) subscription_id = '0'*(4-len(x)) + x # like 0568 self.subscription_ids[subscription_id] = callback # S:0568:$ $ value is $x::$ $ $x is open x = 'S:{}:{}\n'.format(subscription_id, '::'.join(query_strings)).encode("utf-8") self.subscription_messages_on_reconnect.append(x) def parse_results(self, val): self.debug("parsing results: {}".format(val)) result_vals = val[1:-1].split("},{") results = [] for result_val in result_vals: result = {} rvs = result_val.split(",") for rv in rvs: kv = rv.strip().split(":") result[kv[0].replace('"', '').replace("'", '')] = kv[1].strip() results.append(result) return results def check_read_msg_cache_and_callbacks(self): lines = self.recv_msg_cache.split("\n") self.debug("lines: {}".format(lines)) if len(lines) > 1: # trim off the last line (either '' if \n is the last char or a partial string) # because it is not part of a string that ends in a \n full_lines = lines[:-1] for line_msg in full_lines: self.debug("Proccesing new sub update: {}".format(line_msg)) # 1234[{x:"5",y:"1"},{"x":1,"y":2}] sub_id = line_msg[:4] # first four characters of message are sub id val = line_msg[4:] if sub_id not in self.subscription_ids: print("Unknown sub id {}".format(sub_id)) continue callback = self.subscription_ids[sub_id] callback(self.parse_results(val)) self.recv_msg_cache = lines[-1] def listen_and_update_subscriptions(self): # self.debug("listening~~~~~") if self.uart_server.in_waiting: read_msg = self.uart_server.read(self.uart_server.in_waiting) self.recv_msg_cache += read_msg.decode("utf-8") self.check_read_msg_cache_and_callbacks() self.debug("sub update: {}".format(self.recv_msg_cache)) def connected(self): if not self.ble.connected: # Advertise when not connected. print("BLE not connected, advertising...") self.ble.start_advertising(self.advertisement) while not self.ble.connected: pass self.ble.stop_advertising() print("BLE now connected") time.sleep(1.0) # Give BLE connector time setup before sending data for sub_msg in self.subscription_messages_on_reconnect: self.debug("Sending sub message: {}".format(sub_msg)) self.uart_server.write(sub_msg) self.listen_and_update_subscriptions() return True