class RileyLink(PacketRadio): def __init__(self): self.peripheral = None self.pa_level_index = PA_LEVELS.index(0x84) self.data_handle = None self.logger = getLogger() self.address = None if os.path.exists(RILEYLINK_MAC_FILE): with open(RILEYLINK_MAC_FILE, "r") as stream: self.address = stream.read() self.service = None self.response_handle = None self.notify_event = Event() self.initialized = False def connect(self, force_initialize=False): try: if self.address is None: self.address = self._findRileyLink() if self.peripheral is None: self.peripheral = Peripheral() try: state = self.peripheral.getState() if state == "conn": return except BTLEException: pass self._connect_retry(3) self.service = self.peripheral.getServiceByUUID(RILEYLINK_SERVICE_UUID) data_char = self.service.getCharacteristics(RILEYLINK_DATA_CHAR_UUID)[0] self.data_handle = data_char.getHandle() char_response = self.service.getCharacteristics(RILEYLINK_RESPONSE_CHAR_UUID)[0] self.response_handle = char_response.getHandle() response_notify_handle = self.response_handle + 1 notify_setup = b"\x01\x00" self.peripheral.writeCharacteristic(response_notify_handle, notify_setup) while self.peripheral.waitForNotifications(0.05): self.peripheral.readCharacteristic(self.data_handle) if self.initialized: self.init_radio(force_initialize) else: self.init_radio(True) except BTLEException: if self.peripheral is not None: self.disconnect() raise def disconnect(self, ignore_errors=True): try: if self.peripheral is None: self.logger.info("Already disconnected") return self.logger.info("Disconnecting..") if self.response_handle is not None: response_notify_handle = self.response_handle + 1 notify_setup = b"\x00\x00" self.peripheral.writeCharacteristic(response_notify_handle, notify_setup) except BTLEException: if not ignore_errors: raise finally: try: if self.peripheral is not None: self.peripheral.disconnect() self.peripheral = None except BTLEException: if ignore_errors: self.logger.exception("Ignoring btle exception during disconnect") else: raise def get_info(self): try: self.connect() bs = self.peripheral.getServiceByUUID(XGATT_BATTERYSERVICE_UUID) bc = bs.getCharacteristics(XGATT_BATTERY_CHAR_UUID)[0] bch = bc.getHandle() battery_value = int(self.peripheral.readCharacteristic(bch)[0]) self.logger.debug("Battery level read: %d", battery_value) version, v_major, v_minor = self._read_version() return { "battery_level": battery_value, "mac_address": self.address, "version_string": version, "version_major": v_major, "version_minor": v_minor } except BTLEException as btlee: raise PacketRadioError("Error communicating with RileyLink") from btlee finally: self.disconnect() def _read_version(self): version = None try: if os.path.exists(RILEYLINK_VERSION_FILE): with open(RILEYLINK_VERSION_FILE, "r") as stream: version = stream.read() else: response = self._command(Command.GET_VERSION) if response is not None and len(response) > 0: version = response.decode("ascii") self.logger.debug("RL reports version string: %s" % version) try: with open(RILEYLINK_VERSION_FILE, "w") as stream: stream.write(version) except IOError: self.logger.exception("Failed to store version in file") if version is None: return "0.0", 0, 0 try: m = re.search(".+([0-9]+)\\.([0-9]+)", version) if m is None: raise PacketRadioError("Failed to parse firmware version string: %s" % version) v_major = int(m.group(1)) v_minor = int(m.group(2)) self.logger.debug("Interpreted version major: %d minor: %d" % (v_major, v_minor)) return version, v_major, v_minor except Exception as ex: raise PacketRadioError("Failed to parse firmware version string: %s" % version) from ex except IOError: self.logger.exception("Error reading version file") except PacketRadioError: raise response = self._command(Command.GET_VERSION) if response is not None and len(response) > 0: version = response.decode("ascii") self.logger.debug("RL reports version string: %s" % version) try: m = re.search(".+([0-9]+)\\.([0-9]+)", version) if m is None: raise PacketRadioError("Failed to parse firmware version string: %s" % version) v_major = int(m.group(1)) v_minor = int(m.group(2)) self.logger.debug("Interpreted version major: %d minor: %d" % (v_major, v_minor)) return (version, v_major, v_minor) except PacketRadioError: raise except Exception as ex: raise PacketRadioError("Failed to parse firmware version string: %s" % version) from ex def init_radio(self, force_init=False): try: version, v_major, v_minor = self._read_version() if v_major < 2: self.logger.error("Firmware version is below 2.0") raise PacketRadioError("Unsupported RileyLink firmware %d.%d (%s)" % (v_major, v_minor, version)) if not force_init: if v_major == 2 and v_minor < 3: response = self._command(Command.READ_REGISTER, bytes([Register.SYNC1, 0x00])) else: response = self._command(Command.READ_REGISTER, bytes([Register.SYNC1])) if response is not None and len(response) > 0 and response[0] == 0xA5: return self._command(Command.RADIO_RESET_CONFIG) self._command(Command.SET_SW_ENCODING, bytes([Encoding.MANCHESTER])) frequency = int(433910000 / (24000000 / pow(2, 16))) self._command(Command.SET_PREAMBLE, bytes([0x66, 0x65])) self._command(Command.UPDATE_REGISTER, bytes([Register.FREQ0, frequency & 0xff])) self._command(Command.UPDATE_REGISTER, bytes([Register.FREQ1, (frequency >> 8) & 0xff])) self._command(Command.UPDATE_REGISTER, bytes([Register.FREQ2, (frequency >> 16) & 0xff])) self._command(Command.UPDATE_REGISTER, bytes([Register.PKTCTRL1, 0x20])) self._command(Command.UPDATE_REGISTER, bytes([Register.PKTCTRL0, 0x00])) self._command(Command.UPDATE_REGISTER, bytes([Register.FSCTRL1, 0x06])) self._command(Command.UPDATE_REGISTER, bytes([Register.MDMCFG4, 0xCA])) self._command(Command.UPDATE_REGISTER, bytes([Register.MDMCFG3, 0xBC])) self._command(Command.UPDATE_REGISTER, bytes([Register.MDMCFG2, 0x06])) self._command(Command.UPDATE_REGISTER, bytes([Register.MDMCFG1, 0x70])) self._command(Command.UPDATE_REGISTER, bytes([Register.MDMCFG0, 0x11])) self._command(Command.UPDATE_REGISTER, bytes([Register.DEVIATN, 0x44])) self._command(Command.UPDATE_REGISTER, bytes([Register.MCSM0, 0x18])) self._command(Command.UPDATE_REGISTER, bytes([Register.FOCCFG, 0x17])) self._command(Command.UPDATE_REGISTER, bytes([Register.FSCAL3, 0xE9])) self._command(Command.UPDATE_REGISTER, bytes([Register.FSCAL2, 0x2A])) self._command(Command.UPDATE_REGISTER, bytes([Register.FSCAL1, 0x00])) self._command(Command.UPDATE_REGISTER, bytes([Register.FSCAL0, 0x1F])) self._command(Command.UPDATE_REGISTER, bytes([Register.TEST1, 35])) self._command(Command.UPDATE_REGISTER, bytes([Register.TEST0, 0x09])) self._command(Command.UPDATE_REGISTER, bytes([Register.PATABLE0, PA_LEVELS[self.pa_level_index]])) self._command(Command.UPDATE_REGISTER, bytes([Register.FREND0, 0x00])) self._command(Command.UPDATE_REGISTER, bytes([Register.SYNC1, 0xA5])) self._command(Command.UPDATE_REGISTER, bytes([Register.SYNC0, 0x5A])) response = self._command(Command.GET_STATE) if response != b"OK": raise PacketRadioError("Rileylink state is not OK. Response returned: %s" % response) self.initialized = True except PacketRadioError as rle: self.logger.error("Error while initializing rileylink radio: %s", rle) raise def tx_up(self): if self.pa_level_index < len(PA_LEVELS) - 1: self.pa_level_index += 1 self._set_amp(self.pa_level_index) def tx_down(self): if self.pa_level_index > 0: self.pa_level_index -= 1 self._set_amp(self.pa_level_index) def set_tx_power(self, tx_power): if tx_power is None: return elif tx_power == TxPower.Lowest: self._set_amp(0) elif tx_power == TxPower.Low: self._set_amp(PA_LEVELS.index(0x12)) elif tx_power == TxPower.Normal: self._set_amp(PA_LEVELS.index(0x60)) elif tx_power == TxPower.High: self._set_amp(PA_LEVELS.index(0xC8)) elif tx_power == TxPower.Highest: self._set_amp(PA_LEVELS.index(0xC0)) def get_packet(self, timeout=5.0): try: self.connect() return self._command(Command.GET_PACKET, struct.pack(">BL", 0, int(timeout * 1000)), timeout=float(timeout)+0.5) except PacketRadioError as rle: self.logger.error("Error while receiving data: %s", rle) raise def send_and_receive_packet(self, packet, repeat_count, delay_ms, timeout_ms, retry_count, preamble_ext_ms): try: self.connect() return self._command(Command.SEND_AND_LISTEN, struct.pack(">BBHBLBH", 0, repeat_count, delay_ms, 0, timeout_ms, retry_count, preamble_ext_ms) + packet, timeout=30) except PacketRadioError as rle: self.logger.error("Error while sending and receiving data: %s", rle) raise def send_packet(self, packet, repeat_count, delay_ms, preamble_extension_ms): try: self.connect() result = self._command(Command.SEND_PACKET, struct.pack(">BBHH", 0, repeat_count, delay_ms, preamble_extension_ms) + packet, timeout=30) return result except PacketRadioError as rle: self.logger.error("Error while sending data: %s", rle) raise def _set_amp(self, index=None): try: self.connect() if index is not None: self.pa_level_index = index self._command(Command.UPDATE_REGISTER, bytes([Register.PATABLE0, PA_LEVELS[self.pa_level_index]])) self.logger.debug("Setting pa level to index %d of %d" % (self.pa_level_index, len(PA_LEVELS))) except PacketRadioError: self.logger.exception("Error while setting tx amplification") raise def _findRileyLink(self): scanner = Scanner() found = None self.logger.debug("Scanning for RileyLink") retries = 10 while found is None and retries > 0: retries -= 1 for result in scanner.scan(1.0): if result.getValueText(7) == RILEYLINK_SERVICE_UUID: self.logger.debug("Found RileyLink") found = result.addr try: with open(RILEYLINK_MAC_FILE, "w") as stream: stream.write(result.addr) except IOError: self.logger.warning("Cannot store rileylink mac radio_address for later") break if found is None: raise PacketRadioError("Could not find RileyLink") return found def _connect_retry(self, retries): while retries > 0: retries -= 1 self.logger.info("Connecting to RileyLink, retries left: %d" % retries) try: self.peripheral.connect(self.address) self.logger.info("Connected") break except BTLEException as btlee: self.logger.warning("BTLE exception trying to connect: %s" % btlee) try: p = subprocess.Popen(["ps", "-A"], stdout=subprocess.PIPE) out, err = p.communicate() for line in out.splitlines(): if "bluepy-helper" in line: pid = int(line.split(None, 1)[0]) os.kill(pid, 9) break except: self.logger.warning("Failed to kill bluepy-helper") time.sleep(1) def _command(self, command_type, command_data=None, timeout=10.0): try: if command_data is None: data = bytes([1, command_type]) else: data = bytes([len(command_data) + 1, command_type]) + command_data self.peripheral.writeCharacteristic(self.data_handle, data, withResponse=True) if not self.peripheral.waitForNotifications(timeout): raise PacketRadioError("Timed out while waiting for a response from RileyLink") response = self.peripheral.readCharacteristic(self.data_handle) if response is None or len(response) == 0: raise PacketRadioError("RileyLink returned no response") else: if response[0] == Response.COMMAND_SUCCESS: return response[1:] elif response[0] == Response.COMMAND_INTERRUPTED: self.logger.warning("A previous command was interrupted") return response[1:] elif response[0] == Response.RX_TIMEOUT: return None else: raise PacketRadioError("RileyLink returned error code: %02X. Additional response data: %s" % (response[0], response[1:]), response[0]) except Exception as e: raise PacketRadioError("Error executing command") from e
def update(self, force_update=False): if force_update or (self._last_update is None) or (datetime.now() - self._min_update_inteval > self._last_update): self._lock.acquire() try: p = Peripheral(self._mac, "public") chList = p.getCharacteristics() for ch in chList: if str(ch.uuid) == SERVICE_UUID: if p.writeCharacteristic(ch.getHandle(), b'\x55\x03' + bytes([self.get_sequence()]) + b'\x11', True): data = ch.read() humihex = data[6:8] temphex = data[4:6] temp10 = int.from_bytes(temphex, byteorder='little') humi10 = int.from_bytes(humihex, byteorder='little') self._temperature = float(temp10) / 100.0 self._humidity = float(humi10) / 100.0 if p.writeCharacteristic(ch.getHandle(), b'\x55\x03' + bytes([self.get_sequence()]) + b'\x10', True): data = ch.read() battery10 = data[4] self._battery = float(battery10) / 10.0 break p.disconnect() except Exception as ex: print("Unexpected error: {}".format(ex)) p.disconnect() finally: self._lock.release()
def __get_raw_data(self,force_update = False): if self.__address is None: return starttime = int(time.time()) if force_update or starttime - self.__cached_data['last_update'] > terrariumMiFloraSensor.__CACHE_TIMEOUT: try: miflora_dev = Peripheral(self.__address) #Read battery and firmware version attribute self.__cached_data['battery'], self.__cached_data['firmware'] = unpack('<xB5s',miflora_dev.readCharacteristic(terrariumMiFloraSensor.__MIFLORA_FIRMWARE_AND_BATTERY)) #Enable real-time data reading miflora_dev.writeCharacteristic(terrariumMiFloraSensor.__MIFLORA_REALTIME_DATA_TRIGGER, str(bytearray([0xa0, 0x1f])), True) #Read plant data self.__cached_data['temperature'], self.__cached_data['light'], self.__cached_data['moisture'], self.__cached_data['fertility'] = unpack('<hxIBHxxxxxx',miflora_dev.readCharacteristic(terrariumMiFloraSensor.__MIFLORA_GET_DATA)) # temperature, sunlight, moisture, fertility = unpack('<hxIBHxxxxxx',miflora_dev.readCharacteristic(53)) # Close connection... miflora_dev.disconnect() self.__cached_data['last_update'] = starttime except Exception, ex: print ex
def readData (self, mqttClient): print("reading data from device " + self.__mac) sys.stdout.flush() p = Peripheral(self.__mac, iface=HCI_INTERFACE) p.withDelegate(self.__delegate) try: battery = p.readCharacteristic(BATTERY_HANDLE) self.__lastBattery = battery[0] except: print("failed to read battery from " + self.__mac) sys.stdout.flush() p.writeCharacteristic(TEMP_HUM_WRITE_HANDLE, TEMP_HUM_WRITE_VALUE) if not p.waitForNotifications(3.0): print("failed to read data from " + self.__mac) sys.stdout.flush() try: p.disconnect() except: pass print("read data from " + self.__mac + " " + str(self.__lastTemp) + "," + str(self.__lastHum) + "," + str(self.__lastBattery)) sys.stdout.flush() msg =\ '{'\ '"idx" : ' + str(self.__id) + ','\ '"nvalue" : 0,'\ '"svalue" : "' + str(self.__lastTemp) + ';' + str(self.__lastHum) + ';0",'\ '"Battery" : ' + str(self.__lastBattery) + ' '\ '}' mqttClient.publish(DEFAULT_IN_TOPIC, msg);
def startPWS(addr, ssid, psk): logger.info(f"Connect to device {addr}") grantorHandler = GrantorHandler(ssid, psk) # Init Peripheral, connect to it an set read delegate peripheral = Peripheral(addr, ADDR_TYPE_RANDOM) peripheral.setDelegate(WPNearbyReadDelegate(grantorHandler)) pwsService = peripheral.getServiceByUUID(PWSGATTServiceUUID) pwsCharacteristic = pwsService.getCharacteristics( forUUID=PWSGATTCharacteristicUUID)[0] logger.debug(f"PWS characteristic: {pwsCharacteristic.getHandle()}") grantorHandler.pwsCharacteristic = pwsCharacteristic time.sleep(0.5) # Subscribe to the PWS characteristics by sending 0x0200 to pwsCharacteristic Handle+1 (Todo clean uo and check if it is always +1) peripheral.writeCharacteristic(pwsCharacteristic.getHandle() + 2, b"\x01\x00", withResponse=True) grantorHandler.sendPWS1() while peripheral.waitForNotifications(2): pass peripheral.disconnect() logger.info("Wi-Fi Password Sharing completed")
def run(self): while True: if not switchqueue.empty(): try: item = switchqueue.get() switch = item['on'] macaddress = self.convertMac(item['macaddress']) auth_key = unhexlify(item['authkey']) notifications = NotificationDelegate() device = Peripheral(macaddress, ADDR_TYPE_RANDOM) device.setDelegate(notifications) device.writeCharacteristic(STATE_NOTIFY_HANDLE, NOTIFY_VALUE, True) device.writeCharacteristic( STATE_HANDLE, sign('\x01' + ('\x00', '\x01')[switch], auth_key)) while True: if device.waitForNotifications(1.0): print('Ending session') break print('Waiting for notification') device.disconnect() except Exception as e: print(e) time.sleep(1)
class GAmonitor(object): SERVICE_UUIDS = [ UUID('c0be9c58-a717-4e18-828c-a41836f0c7e5'), # Sensors ] CHARACTERISTIC_UUIDS = {'9a067338-1da7-4e0f-8b4a-1e445e1e2df9': 'ACC'} NOTIFICATION_CHARACTERISTIC_UUIDS = [ 'ACC', ] # Notification data NOTIFICATION_ON = struct.pack("BB", 0x01, 0x00) NOTIFICATION_OFF = struct.pack("BB", 0x00, 0x00) def __init__(self, mac_address): self.macAddress = mac_address self.delegate = ScanDelegate() def set_delegate(self, delegate): self.delegate = delegate def connect(self): print('getting peripheral', sys.stderr) self.peripheral = Peripheral(self.macAddress, addrType='public') # Retrieve all characteristics from desired services and map them from their UUID self.peripheral.getServices() svc = self.peripheral.getServiceByUUID( "c0be9c58-a717-4e18-828c-a41836f0c7e5") characteristics = { svcid: svc.getCharacteristics()[i] for svcid, i in zip(self.CHARACTERISTIC_UUIDS, range(2)) } print(characteristics, sys.stderr) # Store each characteristic's value handle for each characteristic name self.characteristicValueHandles = dict( (name, characteristics[uuid].getHandle()) for uuid, name in self.CHARACTERISTIC_UUIDS.items()) # Subscribe for notifications for name in self.NOTIFICATION_CHARACTERISTIC_UUIDS: print('Enabling notification: ', sys.stderr) self.peripheral.writeCharacteristic( self.characteristicValueHandles[name] + 1, self.NOTIFICATION_ON, True) print(name, sys.stderr) print(self.characteristicValueHandles[name] + 1, sys.stderr) self.peripheral.setDelegate(self.delegate) def disconnect(self): self.peripheral.disconnect() def wait_for_notifications(self, timeout): print('calling wait for notifications') return self.peripheral.waitForNotifications(timeout)
class MiTemperature(object): '''' Class to read the temperature from the MiTemp sensor from Amazon. Heavily based on https://github.com/JsBergbau/MiTemperature2 but refactored for my application ''' def __init__(self, deviceAddr, addrType=ADDR_TYPE_PUBLIC, iface=0): self.deviceAddr = deviceAddr self.iface = iface self.addrType = addrType self.timeout = 10.0 def _connect(self): self._periph = Peripheral(deviceAddr=self.deviceAddr, addrType=self.addrType, iface=self.iface) enable_notification_temp_humidity = b'\x01\x00' self._periph.writeCharacteristic(0x0038, enable_notification_temp_humidity, True) self._periph.writeCharacteristic(0x0046, b'\xf4\x01\x00', True) self._delegate = _MiDelegate() self._periph.withDelegate(self._delegate) logging.debug("Connected to {}".format(self.deviceAddr)) self.measurement = self._delegate.measurement def _disconnect(self): self._periph.disconnect() def _reading(self): """ Returns the most recent temperature reading :rtype: Measurement """ self._connect() result = None if self._periph.waitForNotifications(self.timeout): logging.debug("Received notification") result = self._delegate.measurement else: logging.error("No trigger from delegate") self._disconnect() return result def reading(self): """" Return the readings a tuple of temperatiure, humidity, battery level :rtype: (float, float, float) """ measurement = self._reading() return measurement.temperature, measurement.humidity, measurement.batterylevel def temperature(self): measurement = self._reading() if measurement is None: return None else: return measurement.temperature
def subscribe(self): while True: connected = False while connected == False: try: print("connecting to LBE: ", self.device.id) p = Peripheral(self.device.id) except Exception as e: #print (e) sleep(2) else: connected = True p.setDelegate(MyDelegate(self.device)) #Get ButtonService ButtonService = p.getServiceByUUID(button_service_uuid) print("Connected to " + self.device.id) dd = deviceMap[self.device.id] dd.status = Device.Status.CONNECTED # Get The Button-Characteristics # for ch in ButtonService.getCharacteristics(): # print (ch.propertiesToString(), ch.uuid) ButtonC = ButtonService.getCharacteristics( button_chararcteristics_uuid)[0] #Get The handle tf the Button-Characteristics hButtonC = ButtonC.getHandle() # Search and get Get The Button-Characteristics "property" (UUID-0x1124 Human Interface Device (HID))) # wich is located in a handle in the range defined by the boundries of the ButtonService for desriptor in p.getDescriptors( hButtonC, 0xFFFF ): # The handle range should be read from the services #print ("descr", desriptor) # if (desriptor.uuid == 0x2902): # but is not done due to a Bluez/BluePy bug :( #print ("Button1 Client Characteristic Configuration found at handle 0x"+ format(desriptor.handle,"02X")) hButtonCCC = desriptor.handle p.writeCharacteristic(hButtonCCC, struct.pack('<bb', 0x01, 0x00)) print("Notification is turned on for ", self.device) while True: try: if p.waitForNotifications(1.0): continue except BTLEDisconnectError as e: print(e) dd = deviceMap[self.device.id] dd.status = Device.Status.DISCONNECTED break # reconect
class Nuimo(object): SERVICE_UUIDS = [ UUID('0000180f-0000-1000-8000-00805f9b34fb'), # Battery UUID('f29b1525-cb19-40f3-be5c-7241ecb82fd2'), # Sensors UUID('f29b1523-cb19-40f3-be5c-7241ecb82fd1') # LED Matrix ] CHARACTERISTIC_UUIDS = { UUID('00002a19-0000-1000-8000-00805f9b34fb'): 'BATTERY', UUID('f29b1529-cb19-40f3-be5c-7241ecb82fd2'): 'BUTTON', UUID('f29b1528-cb19-40f3-be5c-7241ecb82fd2'): 'ROTATION', UUID('f29b1527-cb19-40f3-be5c-7241ecb82fd2'): 'SWIPE', UUID('f29b1526-cb19-40f3-be5c-7241ecb82fd2'): 'FLY', UUID('f29b1524-cb19-40f3-be5c-7241ecb82fd1'): 'LED_MATRIX' } NOTIFICATION_CHARACTERISTIC_UUIDS = [ 'BATTERY', # Uncomment only if you are not using the iOS emulator (iOS does't support battery updates without authentication) 'BUTTON', 'ROTATION', 'SWIPE', 'FLY'] # Notification data NOTIFICATION_ON = struct.pack("BB", 0x01, 0x00) NOTIFICATION_OFF = struct.pack("BB", 0x00, 0x00) def __init__(self, mac_address): self.macAddress = mac_address self.delegate=NuimoDelegate(self) def set_delegate(self, delegate): self.delegate = delegate def connect(self): self.peripheral = Peripheral(self.macAddress, addrType='random') # Retrieve all characteristics from desired services and map them from their UUID characteristics = list(itertools.chain(*[self.peripheral.getServiceByUUID(uuid).getCharacteristics() for uuid in Nuimo.SERVICE_UUIDS])) characteristics = dict((c.uuid, c) for c in characteristics) # Store each characteristic's value handle for each characteristic name self.characteristicValueHandles = dict((name, characteristics[uuid].getHandle()) for uuid, name in Nuimo.CHARACTERISTIC_UUIDS.items()) # Subscribe for notifications for name in Nuimo.NOTIFICATION_CHARACTERISTIC_UUIDS: self.peripheral.writeCharacteristic(self.characteristicValueHandles[name] + 1, Nuimo.NOTIFICATION_ON, True) self.peripheral.setDelegate(self.delegate) def wait_for_notifications(self): self.peripheral.wait_for_notifications(1.0) def display_led_matrix(self, matrix, timeout, brightness=1.0): matrix = '{:<81}'.format(matrix[:81]) bites = list(map(lambda leds: reduce(lambda acc, led: acc + (1 << led if leds[led] not in [' ', '0'] else 0), range(0, len(leds)), 0), [matrix[i:i+8] for i in range(0, len(matrix), 8)])) self.peripheral.writeCharacteristic(self.characteristicValueHandles['LED_MATRIX'], struct.pack('BBBBBBBBBBBBB', bites[0], bites[1], bites[2], bites[3], bites[4], bites[5], bites[6], bites[7], bites[8], bites[9], bites[10], max(0, min(255, int(255.0 * brightness))), max(0, min(255, int(timeout * 10.0)))), True)
class BLEController: def __init__(self, delegate): # Variables self._delegate = delegate def connect(self, server_mac): self._server_mac = server_mac self._peripheral = Peripheral(self._server_mac) self._peripheral.setDelegate(self._delegate) self._listening = False def disconnect(self): self._peripheral.disconnect() def print_services(self, primary_service_uuid): svcs = self._peripheral.getServices() print("Services:") for s in svcs: print(s) print("Characteristics:") svc = self._peripheral.getServiceByUUID(primary_service_uuid) chs = svc.getCharacteristics() for c in chs: print(str(c) + " handle: " + str(c.getHandle())) def listen(self): if not self._listening: # Are we listening already? self._listening = True while self._listening: if self._peripheral.waitForNotifications( 1.0): # Calls the delegate if true # Delegate was called continue print('BLEController.listen() -> Listening...') def listen_async(self): #raise Exception("Not Implemented") self._listen_thread = _thread.start_new_thread(self.listen, ()) def adjust_light_source(self, value): # value is a tuple of RGB i.e. (255, 255, 255) # BLE characteristic expects a byte array value_bytes = bytes(value) print("BLEController.adjust_light_source -> {}".format(value_bytes)) handle = 49 # The handle value has to be found using e.g. print_services(), bluez, or similar self._peripheral.writeCharacteristic(handle, value_bytes) def stop_listening(self): self._listening = False
class BLEDevice(Thread): def __init__(self, room_batch_queue, room_sub_update_queue, addr, addrType, ble_activity_lock): Thread.__init__(self) print("Created BLE Device: {}".format(addr)) self.room_batch_queue = room_batch_queue self.room_sub_update_queue = room_sub_update_queue self.addr = addr self.addrType = addrType self.ble_activity_lock = ble_activity_lock def ble_listen_loop(self, write_cs, notify_cs): print("writing something so connection stays alive") write_cs.write(b"hey") print("listening to read...") while True: if self.conn.waitForNotifications(1.0): continue print("waiting...") # TODO: Listen for self.room_sub_update_queue updates time.sleep(0.05) def run(self): print("attempting connect to {}".format(self.addr)) self.ble_activity_lock.acquire() self.conn = Peripheral(self.addr, self.addrType) self.ble_activity_lock.release() print("Connected! {}".format(self.addr)) css = self.conn.getCharacteristics() notify_cs = None write_cs = None for cs in css: print(cs.uuid, cs.propertiesToString()) # per.getCharacteristics(uuid='6e400003-b5a3-f393-e0a9-e50e24dcca9e')[0] if cs.propertiesToString() == "NOTIFY ": notify_cs = cs if "WRITE" in cs.propertiesToString(): write_cs = cs if write_cs and notify_cs: self.conn.setDelegate(MyDelegate(self.addr, self.room_batch_queue)) # enable notification setup_data = b"\x01\x00" notify_handle = notify_cs.getHandle() + 1 self.conn.writeCharacteristic(notify_handle, setup_data, withResponse=True) self.ble_listen_loop(write_cs, notify_cs) else: print( "Device {} did not have a write and notify BLE characteristic." .format(self.addr))
def __get_raw_data(self, force_update=False): if self.__address is None: return starttime = int(time.time()) if force_update or starttime - self.__cached_data[ 'last_update'] > terrariumMiFloraSensor.__CACHE_TIMEOUT: try: cached_data = {} for item in self.__cached_data: cached_data[item] = None miflora_dev = Peripheral(self.__address) #Read battery and firmware version attribute cached_data['battery'], cached_data['firmware'] = unpack( '<xB5s', miflora_dev.readCharacteristic( terrariumMiFloraSensor.__MIFLORA_FIRMWARE_AND_BATTERY)) #Enable real-time data reading miflora_dev.writeCharacteristic( terrariumMiFloraSensor.__MIFLORA_REALTIME_DATA_TRIGGER, bytearray([0xa0, 0x1f]), True) #Read plant data cached_data['temperature'], cached_data['light'], cached_data[ 'moisture'], cached_data['fertility'] = unpack( '<hxIBHxxxxxx', miflora_dev.readCharacteristic( terrariumMiFloraSensor.__MIFLORA_GET_DATA)) # Close connection... miflora_dev.disconnect() cached_data['last_update'] = starttime for item in self.__cached_data: self.__cached_data[item] = cached_data[item] self.__errors = 0 except Exception as ex: self.__errors += 1 if self.__errors > 3: logger.error( 'Error getting new data from sensor at address: \'%s\'. Error: %s' % (self.__address, ex)) else: logger.warning( 'Error getting new data from sensor at address: \'%s\'. Error: %s' % (self.__address, ex))
def send_data(self, device_addr: str, origin_data): """ 异常执行-发送数据到设备 :param device_addr: 设备地址 :param origin_data 待发送的原始数据 :return: """ # 此处需要把原始数据转换为字典数据,示例:{title:'标题',content:'内容'} data_dict = json5.loads(origin_data) print('prepare send message -> title:{},payload:{}'.format( data_dict['title'], data_dict['payload'])) # 发送数据到手环标题指令(字符串转16进制) hex_data_title_origin = binascii.b2a_hex(data_dict['title'].encode()) title_data_full = 'a4' + hex( int(len(hex_data_title_origin) / 2) + 1)[2:].zfill(2) + '01' + str( hex_data_title_origin).strip('b').strip("'") # 发送数据到手环内容指令(字符串转16进制) hex_data_payload_origin = binascii.b2a_hex( data_dict['payload'].encode()) payload_data_full = 'a4' + hex( int(len(hex_data_payload_origin) / 2) + 1)[2:].zfill( 2) + '02' + str(hex_data_payload_origin).strip('b').strip("'") # 数据折包 title_data_list = re.findall(r'.{1,40}', title_data_full) payload_data_list = re.findall(r'.{1,40}', payload_data_full) to_be_sent_list = [self.command_send_data_start] to_be_sent_list.extend(title_data_list) to_be_sent_list.extend(payload_data_list) to_be_sent_list.append(self.command_send_data_end) try: peripheral = Peripheral(deviceAddr=device_addr, addrType=ADDR_TYPE_RANDOM, iface=0) except BTLEException as e: print('raspberry pi link wristband device failure, {}'.format(e)) return # 正常连接到设备蓝牙,发送数据 try: for data in to_be_sent_list: peripheral.writeCharacteristic(handle=29, val=binascii.a2b_hex(data)) time.sleep(0.2) except BTLEDisconnectError as e: print('send message:{} to device exception, {}'.format(data, e)) time.sleep(1)
def write_state(self, value): from bluepy.btle import Peripheral device = None try: # connect to device device = Peripheral(self._mac) # send PIN code auth device.writeCharacteristic( 0x3c, self._pin.to_bytes(4, byteorder='little'), True) _LOGGER.info("Auth success for {}".format(self._mac)) # set date+time now = datetime.now() device.writeCharacteristic( 0x25, bytes([ now.minute, now.hour, now.day, now.month, now.year - 2000 ])) # handle any outstanding value updates if value: device.writeCharacteristic(0x35, value, True) # writing something here does a "commit" device.writeCharacteristic(0x3a, bytes([randint(0, 255)])) _LOGGER.info("Updated switch to {}".format(value[0])) self._state = (device.readCharacteristic(0x35)[0] & 8 > 0) except Exception as e: _LOGGER.error("Exception: %s ", str(e)) finally: if device is not None: device.disconnect()
def configure_device(scanEntry): logging.info("Connecting to: %s", scanEntry.addr) try: peripheral_device = Peripheral(scanEntry) except: logging.warning("_-_-_ Failed to connect to: %s", scanEntry.addr) else: peripheral_device.setDelegate(ConfigDelegate()) # serviceList = peripheral_device.getServices() # logging.debug(serviceList) # logging.debug(list(serviceList)) # for service in peripheral_device.getServices(): # logging.debug("S: %s", service.uuid) # for characteristic in service.getCharacteristics(): # logging.debug("C: %s", characteristic.uuid) # Read HW ID and apply corresponding configuration hw_id_char = peripheral_device.getCharacteristics(uuid="00001101-0f58-2ba7-72c3-4d8d58fa16de")[0] hw_id = unpack("H", hw_id_char.read())[0] logging.info("HWID:%s", hw_id) if hw_id == HW_ID_CLIMATE: config = climate_configuration elif hw_id == 5: config = conference_configuration else: peripheral_device.disconnect() return uartRxChar = peripheral_device.getCharacteristics(uuid="6e400003-b5a3-f393-e0a9-e50e24dcca9e")[0] uartTxChar = peripheral_device.getCharacteristics(uuid="6e400002-b5a3-f393-e0a9-e50e24dcca9e")[0] # logging.debug(uartRxChar) # logging.debug(uartTxChar) # logging.debug("RX char properties: %s", uartRxChar.propertiesToString()) # logging.debug("TX char properties: %s", uartTxChar.propertiesToString()) logging.debug("Enable notification") uartRxCharDescriptorHandle = uartRxChar.getHandle() + 1 peripheral_device.writeCharacteristic(uartRxCharDescriptorHandle , (1).to_bytes(2, byteorder='little')) # logging.debug(uartRxChar.getHandle()) # logging.debug(uartTxChar.getHandle()) for x in range(0, len(config)): # logging.debug(x) uartTxChar.write(config[x]) if peripheral_device.waitForNotifications(1): pass # logging.debug("Notification received") else: logging.debug("No notification received") peripheral_device.waitForNotifications(1) logging.info("Configuration complete") peripheral_device.disconnect()
def send_ir(self, key, ir_data): self._lock.acquire() sent = False p = None try: p = Peripheral(self._mac, "public") ch_list = p.getCharacteristics() for ch in ch_list: if str(ch.uuid) == SERVICE_UUID: sequence = self.get_sequence() if p.writeCharacteristic(ch.getHandle(), b'\x55' + bytes(len(a2b_hex(key)) + 3, [sequence]) + b'\x03' + a2b_hex(key), True): data = ch.read() if len(data) == 5 and data[4] == 1: sent = True else: send_list = [] packet_count = int(len(ir_data) / 30) + 1 if len(data) % 30 != 0: packet_count = packet_count + 1 send_list.append( b'\x55' + bytes(len(a2b_hex(key)) + 5, [sequence]) + b'\x00' + bytes([0, packet_count]) + a2b_hex(key)) i = 0 while i < packet_count - 1: if len(ir_data) - i * 30 < 30: send_ir_data = ir_data[i * 30:] else: send_ir_data = ir_data[i * 30:(i + 1) * 30] send_list.append( b'\x55' + bytes([int(len(send_ir_data) / 2 + 4), sequence]) + b'\x00' + bytes([i + 1]) + a2b_hex( send_ir_data)) i = i + 1 error = False for j in range(len(send_list)): r = p.writeCharacteristic(ch.getHandle(), send_list[j], True) if not r: error = True break if not error: sent = True break except Exception as ex: print("Unexpected error: {}".format(ex)) finally: if not p: p.disconnect() self._lock.release() return sent
class BluepyBackend(AbstractBackend): """Backend for Miflora using the bluepy library.""" def __init__(self, adapter='hci0'): """Create new instance of the backend.""" super(self.__class__, self).__init__(adapter) self._peripheral = None def connect(self, mac): """Connect to a device.""" from bluepy.btle import Peripheral m = re.search(r'hci([\d]+)', self.adapter) if m is None: raise ValueError('Invalid pattern "{}" for BLuetooth adpater. ' 'Expetected something like "hci0".'.format( self.adapter)) iface = int(m.group(1)) self._peripheral = Peripheral(mac, iface=iface) def disconnect(self): """Disconnect from a device.""" self._peripheral.disconnect() self._peripheral = None def read_handle(self, handle): """Read a handle from the device. You must be connected to do this. """ if self._peripheral is None: raise BluetoothBackendException('not connected to backend') return self._peripheral.readCharacteristic(handle) def write_handle(self, handle, value): """Write a handle from the device. You must be connected to do this. """ if self._peripheral is None: raise BluetoothBackendException('not connected to backend') return self._peripheral.writeCharacteristic(handle, value, True) def check_backend(self): """Check if the backend is available.""" try: import bluepy.btle # noqa: F401 except ImportError: raise BluetoothBackendException('bluepy not found') @staticmethod def scan_for_devices(timeout): """Scan for bluetooth low energy devices. Note this must be run as root!""" from bluepy.btle import Scanner scanner = Scanner() result = [] for device in scanner.scan(timeout): result.append((device.addr, device.getValueText(9))) return result
def init(): peripheral = Peripheral("d8:e3:66:b3:b9:95", btle.ADDR_TYPE_RANDOM) peripheral.withDelegate(delegate) peripheral.writeCharacteristic(12, (1).to_bytes(2, byteorder='little')) try: while delegate.flag: if peripheral.waitForNotifications(10): continue break except: print("disconnected") finally: peripheral.disconnect() sys.exit(0)
class BluepyBackend(AbstractBackend): def __init__(self, adapter='hci0'): super(self.__class__, self).__init__(adapter) self._peripheral = None def connect(self, mac): from bluepy.btle import Peripheral self._peripheral = Peripheral(mac) def disconnect(self): self._peripheral.disconnect() self._peripheral = None def read_handle(self, handle): if self._peripheral is None: raise BluetoothBackendException('not connected to backend') return self._peripheral.readCharacteristic(handle) def write_handle(self, handle, value): if self._peripheral is None: raise BluetoothBackendException('not connected to backend') return self._peripheral.writeCharacteristic(handle, value, True) def check_backend(self): try: import bluepy.btle # noqa: F401 except ImportError: raise BluetoothBackendException('bluepy not found')
def switchOff(self): print("LED stripe " + self.__mac + " is switching off") p = Peripheral(self.__mac, iface=0) data = bytearray( [0x7e, 0x04, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, 0xef]) try: p.writeCharacteristic(WRITE_HANDLE, data) except: print("failed to write command SwitchOff to " + self.__mac) try: p.disconnect() except: pass
class BluetoothPoller: _DATA_MODE_LISTEN = bytes([0x01, 0x00]) def __init__(self, address: str, label: str, results: List[SensorValues], iface: int): self.peripheral = Peripheral(deviceAddr=address, iface=iface) self.peripheral.withDelegate( ValueDelegate(label=label, results=results)) def wait_for_notification(self, handle: int, timeout=1.0): self.peripheral.writeCharacteristic(handle, BluetoothPoller._DATA_MODE_LISTEN) return self.peripheral.waitForNotifications(timeout) def disconnect(self): self.peripheral.disconnect()
class Switchmate(SwitchDevice): """Representation of a Switchmate.""" def __init__(self, mac, friendly_name) -> None: """Initialize the Switchmate.""" from bluepy.btle import ADDR_TYPE_RANDOM, Peripheral, BTLEException self._state = False self._friendly_name = friendly_name self._handle = 0x2e self._mac = mac try: self._device = Peripheral(self._mac, ADDR_TYPE_RANDOM) except BTLEException as ex: _LOGGER.error("Failed to setup switchmate: " + ex.message) raise PlatformNotReady() @property def unique_id(self) -> str: """Return a unique, HASS-friendly identifier for this entity.""" return '{0}_{1}'.format(self._mac.replace(':', ''), self.entity_id) @property def name(self) -> str: """Return the name of the switch.""" return self._friendly_name @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self) -> None: """Synchronize state with switch.""" self._state = b'\x00' == self._device.readCharacteristic(self._handle) print("state", self._state) @property def is_on(self) -> bool: """Return true if it is on.""" return self._state def turn_on(self, **kwargs) -> None: """Turn the switch on.""" self._device.writeCharacteristic(self._handle, b'\x00', True) self._state = True self.schedule_update_ha_state() def turn_off(self, **kwargs) -> None: """Turn the switch off.""" self._device.writeCharacteristic(self._handle, b'\x01', True) self._state = False self.schedule_update_ha_state()
def main(): scanner = Scanner().withDelegate(ScanDelegate()) device_list = scanner.scan(5) # scan for 5 seconds for device in device_list: if (device.addr.lower() == DH_ADDRESS.lower()): print("Target device host discovered!") # RSSI = Received Signal Strength Indicator #print("Device %s (%s), RSSI=%d dB" % (device.addr, device.addrType, device.rssi )) scan_data = device.getScanData() device_name = scan_data[2][2] auth_service_uuid = scan_data[4][2] #print(device_name) #print(auth_service_uuid) #for (adtype,desc,value) in device.getScanData(): # print("\t%s = %s" % (desc, value)) device = Peripheral(DH_ADDRESS) device.setMTU(520) device.setDelegate(PeripheralDelegate()) print("Successfully connected to device host") auth_service = device.getServiceByUUID(auth_service_uuid) auth_char = auth_service.getCharacteristics()[0] # read authentication characteristic state #print(auth_char.valHandle) auth_char_cccd = auth_char.getHandle() + 1 print("CCCD 0x%X" % auth_char_cccd) device.writeCharacteristic(auth_char_cccd, b"\x01\x00") #device.withDelegate(PeripheralDelegate()) auth_char_val = auth_char.read() print(auth_char_val) #if(auth_char_val == 0): ## print("Zero") # wait for server confirmation as a notification message while True: if (device.waitForNotifications(1.0)): print("new notification from server") continue print("Waiting...")
def start(self): try: device = Peripheral(self.macaddress, ADDR_TYPE_RANDOM, int(os.environ['SCAN_HCI'])) notifications = NotificationDelegate(self.macaddress) device.setDelegate(notifications) device.writeCharacteristic(AUTH_NOTIFY_HANDLE, NOTIFY_VALUE, True) device.writeCharacteristic(AUTH_HANDLE, AUTH_INIT_VALUE, True) print('Press button') statusqueue.put('Press button on Switchmate to get auth key') while True: if device.waitForNotifications(1.0): statusqueue.put('Ending session') break statusqueue.put('Waiting for notification') time.sleep(0) device.disconnect() except Exception as e: print(e)
def changeState (self, onOff): print("LED stripe " + self.__mac + " is changing state to " + str(onOff)) sys.stdout.flush() p = Peripheral(self.__mac, iface=HCI_INTERFACE) if (onOff == 0): data = bytearray([0x7e, 0x04, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, 0xef]) else: data = bytearray([0x7e, 0x04, 0x04, 0xf0, 0x00, 0x01, 0xff, 0x00, 0xef]) try: p.writeCharacteristic(WRITE_HANDLE, data) except: print("failed to change state of lotus lantern " + self.__mac) sys.stdout.flush() try: p.disconnect() except: pass
def load_data(self): data = None if self.get_address() is not None: try: sensor = Peripheral(self.get_address()) #Read battery and firmware version attribute data = unpack( '<xB5s', sensor.readCharacteristic( terrariumMiFloraSensor.__MIFLORA_FIRMWARE_AND_BATTERY)) data = {'battery': data[0], 'firmware': data[1]} #Enable real-time data reading sensor.writeCharacteristic( terrariumMiFloraSensor.__MIFLORA_REALTIME_DATA_TRIGGER, bytearray([0xa0, 0x1f]), True) #Read plant data data['temperature'], data['light'], data['moisture'], data[ 'fertility'] = unpack( '<hxIBHxxxxxx', sensor.readCharacteristic( terrariumMiFloraSensor.__MIFLORA_GET_DATA)) # Close connection... sensor.disconnect() # Clean up data['temperature'] = float(data['temperature']) / 10.0 data['light'] = float(data['light']) data['moisture'] = float(data['moisture']) data['fertility'] = float(data['fertility']) data['battery'] = float(data['battery']) data['firmware'] = data['firmware'].decode('utf8') except Exception as ex: logger.warning( 'Error getting new data from {} sensor \'{}\'. Error message: {}' .format(self.get_type(), self.get_name(), ex)) return data
def handleDiscovery(self, dev, isNewDev, isNewData): """ If a newly discovered device is the expected one, we subscribe a callback to handle the notifications. We also get the desired characteristic and start the notification process. """ if isNewDev and (9 in dev.scanData.keys() ) and dev.scanData[9] == "Suunto Smart Sensor": per = Peripheral(dev.addr).withDelegate( NotificationDelegate(dev.addr)) svc = per.getServiceByUUID("0000180d-0000-1000-8000-00805f9b34fb") char = svc.getCharacteristics( "00002a37-0000-1000-8000-00805f9b34fb")[0] ch_handle = char.getHandle() per.writeCharacteristic(ch_handle + 1, struct.pack("<bb", 0x01, 0x00)) while True: if per.waitForNotifications(1.0): continue
def get_beacon_key(mac, product_id): reversed_mac = reverseMac(mac) token = generateRandomToken() # Pairing input(f"Activate pairing on your '{mac}' device, then press Enter: ") # Connect print("Connection in progress...") peripheral = Peripheral(deviceAddr=mac) print("Successful connection!") # Auth (More information: https://github.com/archaron/docs/blob/master/BLE/ylkg08y.md) print("Authentication in progress...") auth_service = peripheral.getServiceByUUID(UUID_SERVICE) auth_descriptors = auth_service.getDescriptors() peripheral.writeCharacteristic(HANDLE_AUTH_INIT, MI_KEY1, "true") auth_descriptors[1].write(SUBSCRIBE_TRUE, "true") peripheral.writeCharacteristic( HANDLE_AUTH, cipher(mixA(reversed_mac, product_id), token), "true") peripheral.waitForNotifications(10.0) peripheral.writeCharacteristic(3, cipher(token, MI_KEY2), "true") print("Successful authentication!") # Read beacon_key = cipher( token, peripheral.readCharacteristic(HANDLE_BEACON_KEY)).hex() firmware_version = cipher( token, peripheral.readCharacteristic(HANDLE_FIRMWARE_VERSION)).decode() print(f"beaconKey: '{beacon_key}'") print(f"firmware_version: '{firmware_version}'")
class Light: def __init__(self, name, addr): self.device = Peripheral(deviceAddr=addr) self.name = name self.address = addr def to_json(self): return "{" + f'"name": "{self.name}", "address": "{self.address}"' + "}" def to_object(self): return {'name': self.name, 'address': self.address} def setLight(self, blue, white): self.device.writeCharacteristic(SERVICE_HANDLE, getBrightnessCommand(blue, white)) def getLight(self): c = bytes.hex(self.device.readCharacteristic(SERVICE_HANDLE)) return {'blue': int(c[8:10], 16), 'white': int(c[10:12], 16)} def turn_on(self): self.device.writeCharacteristic(SERVICE_HANDLE, bytes.fromhex("FBF0 FA")) def turn_off(self): self.device.writeCharacteristic(SERVICE_HANDLE, bytes.fromhex("FB0F FA"))
class Switch(object): """ A switch class for switchmate switches """ def __init__(self, mac_address='c1:59:2c:b2:8d:33'): """ return a switch object with the right mac_address""" self.mac_address = mac_address try: self.device = Peripheral(mac_address, ADDR_TYPE_RANDOM) self.state_handle = get_state_handle(self.device) self.curr_val = self.device.readCharacteristic(self.state_handle) except BTLEException as ex: print('ERROR: ' + ex.message) except OSError as ex: print('ERROR: Failed to connect to device.') @property def status(self, ): return 'off' if self.curr_val == b'\x00' else 'on' def switch(self, state=None): """ Switch the switchmate on or off Usage: switch('on') """ if state == 'on': val = b'\x01' elif state == 'off': val = b'\x00' elif state == None: val = b'\x01' if self.curr_val == b'\x00' else b'\x00' try: self.device.writeCharacteristic(self.state_handle, val, True) self.curr_val = val except BTLEException as ex: print_exception(ex) # Functions for a cleaner interface def turn_on(self): self.switch('on') def turn_off(self): self.switch('off')
def run(self): while True: if not switchqueue.empty(): try: item = switchqueue.get() switch = item['on'] if switch: val = '\x01' else: val = '\x00' macaddress = self.convertMac(item['macaddress']) device = Peripheral(macaddress, ADDR_TYPE_RANDOM, int(os.environ['SCAN_HCI'])) if item['newFirmware'] is False: notifications = NotificationDelegate() device.setDelegate(notifications) auth_key = unhexlify(item['authkey']) device.writeCharacteristic(STATE_NOTIFY_HANDLE, NOTIFY_VALUE, True) device.writeCharacteristic( STATE_HANDLE, sign('\x01' + val, auth_key)) while True: if device.waitForNotifications(1.0): device.disconnect() print('Ending session') break print('Waiting for notification. Old Firmware.') else: # new firmware. No notifcation and no auth device.writeCharacteristic(NEW_STATE_HANDLE, val, True) device.disconnect() except Exception as e: print(e) time.sleep(1)
# p = Peripheral("D9:35:6A:75:9F:9D", "random") # Rfduino sur usb continuer = True while(continuer): try: p = Peripheral("D1:7F:06:ED:66:DC", "random") # Rfduino sur pcb continuer = False except: print "Module bluetooth deja connecte, nouvel essai dans 3 sec..." time.sleep(3) p.withDelegate(MyDelegate()) Analyser.set_p(p) print " device connected..." try: p.getServices() ch = p.getCharacteristics(uuid=rx_uuid)[0] print ("notify characteristic with uuid 0x" + rx_uuid.getCommonName()) cccid = btle.AssignedNumbers.client_characteristic_configuration # Ox000F : handle of Client Characteristic Configuration descriptor Rx - (generic uuid 0x2902) p.writeCharacteristic(0x000F, struct.pack('<bb', 0x01, 0x00), False) if ch.supportsRead(): while 1: p.waitForNotifications(604800) # 1 semaine d'attente # handleNotification() was called continue finally: Analyser.ls.close() p.disconnect()
def onBtleData(data): print "got data: " + data.getName().toUri() el = BtleNode(onBtleData, None, None) em = ElementReader(el) class MyDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) def handleNotification(self, cHandle, data): em.onReceivedData(data[2:]) p.setDelegate(MyDelegate()) p.writeCharacteristic(p.getCharacteristics(uuid=my_uuid)[0].valHandle + 1, "\x01\x00") while True: if p.waitForNotifications(1.0): continue """ try: #p.writeCharacteristic(0x2221, bytes(0x01), True) #print p.getCharacteristics() ch = p.getCharacteristics(uuid=my_uuid)[0] if (ch.supportsRead()): while True: val = ch.read() print binascii.hexlify(bytearray(val)) if len(val) > 5:
class BtlePeripheral(): def __init__(self, addr, producer, loop, receive_uuid = 0x2221, send_uuid = 0x2222, security = False): self._addr = addr self._producer = producer self._receive_uuid = receive_uuid self._send_uuid = send_uuid self._loop = loop self._security = security self._p = None def start(self): # init btle ElementReader el = BtleNode(self._producer.onBtleData, None, None) em = ElementReader(el) class MyDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) def handleNotification(self, cHandle, data): # TODO: this should handle incorrect format caused by packet losses try: em.onReceivedData(data[2:]) except ValueError as e: print "Decoding value error: " + str(e) # connect ble while not self._p: try: self._p = Peripheral(self._addr, "random") except BTLEException as e: print "Failed to connect: " + str(e) + "; trying again" self._p = None # tell rfduino we are ready for notifications self._p.setDelegate(MyDelegate()) self._p.writeCharacteristic(self._p.getCharacteristics(uuid = self._receive_uuid)[0].valHandle + 1, "\x01\x00") self._loop.create_task(self.btleNotificationListen()) if self._security: # send our public key if configured to do so print "security on, sending our public key" interest = self._producer.makePublicKeyInterest() # write characteristics data = interest.wireEncode().toRawStr() num_fragments = int(math.ceil(float(len(data)) / 18)) print "length of data: " + str(len(data)) + "; number of fragments: " + str(num_fragments) current = 0 for i in range(0, num_fragments - 1): fragment = struct.pack(">B", i) + struct.pack(">B", num_fragments) + data[current:current + 18] current += 18 self._p.writeCharacteristic(self._p.getCharacteristics(uuid = self._send_uuid)[0].valHandle, fragment) print " ".join(x.encode('hex') for x in fragment) fragment = struct.pack(">B", num_fragments - 1) + struct.pack(">B", num_fragments) + data[current:] self._p.writeCharacteristic(self._p.getCharacteristics(uuid = self._send_uuid)[0].valHandle, fragment) print " ".join(x.encode('hex') for x in fragment) @asyncio.coroutine def btleNotificationListen(self): try: while True: if self._p.waitForNotifications(0.2): pass time.sleep(0.01) yield None except BTLEException as e: print("Btle exception: " + str(e) + "; try to restart") self._p = None self.start()
class Yeelight(DefaultDelegate): WRITE_CHAR_UUID = b"aa7d3f34" # -2d4f-41e0-807f-52fbf8cf7443" COMMAND_STX = "43" COMMAND_ETX = "00" AUTH_CMD = "67" AUTH_ON = "02" POWER_CMD = "40" POWER_ON = "01" POWER_OFF = "02" COLOR_CMD = "41" RGB_MODE = "65" BRIGHT_CMD = "42" COLORTEMP_CMD = "43" TEMP_MODE = "65" STATUS_CMD = "44" COLORFLOW_CMD = "4a" SLEEP_CMD = "7f03" def __init__(self, address): DefaultDelegate.__init__(self) self.__address = address self.__connect() # Override def handleNotification(self, handle, data): if handle == 21: format = ( '!xx' # 4345 header 'B' # switch: 01=on 02=off 'B' # mode: 01=rgb 02=warm 'BBBx' # RGB 'B' # Brightness 'H' # temp 2byte 1700 ~ 6500 'xxxxxxx' ) (switch, mode, r, g, b, brightness, temp) = struct.unpack(format, data) if switch != 4: self._switch = switch self._mode = mode self._rgb = '{:02x}{:02x}{:02x}'.format(r, g, b) self._temp = temp self._brightness = brightness def disconnect(self, *args, **kwargs): return self.__peripheral.disconnect(*args, **kwargs) def __connect(self): self.__peripheral = Peripheral(self.__address) self.__peripheral.setDelegate(self) characteristics = self.__peripheral.getCharacteristics() self.__ch = next(iter(filter(lambda x: binascii.b2a_hex(x.uuid.binVal) .startswith(self.WRITE_CHAR_UUID), characteristics))) # Register notification self.__peripheral.writeCharacteristic( 0x16, binascii.a2b_hex('0100')) # Auth self.__write_cmd( self.COMMAND_STX + self.AUTH_CMD + self.AUTH_ON + self.COMMAND_ETX * 15) # Get status self.__request_status() def __write_cmd(self, value): for _ in range(3): try: self.__ch.write(binascii.a2b_hex(value)) self.__peripheral.waitForNotifications(1.0) except BTLEException as e: error = e self.__connect() else: break else: raise error def __request_status(self): self.__write_cmd( self.COMMAND_STX + self.STATUS_CMD + self.COMMAND_ETX * 16 ) @property def switch(self): self.update_status() return self._switch @property def brightness(self): self.update_status() return self._brightness @property def temp(self): self.update_status() return self._temp @property def rgb(self): self.update_status() return self._rgb @property def mode(self): self.update_status() return self._mode def poweron(self): self.__write_cmd( self.COMMAND_STX + self.POWER_CMD + self.POWER_ON + self.COMMAND_ETX * 15) def poweroff(self): self.__write_cmd( self.COMMAND_STX + self.POWER_CMD + self.POWER_OFF + self.COMMAND_ETX * 15) def set_rgb(self, rgb): self.__write_cmd( self.COMMAND_STX + self.COLOR_CMD + rgb + '00' + self.RGB_MODE + self.COMMAND_ETX * 11) def set_brightness(self, value): self.__write_cmd( self.COMMAND_STX + self.BRIGHT_CMD + ('%02x' % value) + self.COMMAND_ETX * 15) # Bypass bug self.__request_status() def set_temp(self, value): if not 1700 <= value <= 6500 and 0.0 <= value <= 1.0: value = int(1700 + value * 4800) self.__write_cmd( self.COMMAND_STX + self.COLORTEMP_CMD + ('%04x' % value) + self.TEMP_MODE + self.COMMAND_ETX * 13) def set_sleep(self, minute): self.__write_cmd( self.COMMAND_STX + self.SLEEP_CMD + ('%02x' % minute) + self.COMMAND_ETX * 14 ) def update_status(self): self.__peripheral.waitForNotifications(0.01)
print "Fatal, must pass device address:", sys.argv[0], "<device address>" quit() try: print "Info, trying to connect to:", sys.argv[1] p = Peripheral(sys.argv[1]) print "Info, connected and turning notify and sensor on!" ch = p.getCharacteristics(uuid=config_uuid)[0] ch.write(sensorOn, withResponse=True) # With bluepy if you need to read or write a Descriptor you have to # access it using Peripheral readCharacteristic or writeCharacteristic # and the appropriate handle p.setDelegate( MyDelegate("keys") ) p.writeCharacteristic(notifyHnd, notifyOn) while True: try: if p.waitForNotifications(1.0): # handleNotification() was called if keys & 0x01: print "Info, Right Button" if keys & 0x02: print "Info, Left Button" if keys & 0x04: print "Info, Reed Switch" except KeyboardInterrupt: print "exiting..." ctrl_c=True
# noinspection PyUnresolvedReferences from bluepy.btle import Scanner, DefaultDelegate, Peripheral # perf = Peripheral("00:07:80:BD:23:BE") perf = Peripheral("00:07:80:BD:1C:3A") print("Firmware: ", perf.readCharacteristic(0x000a)) print("Hardware: ", perf.readCharacteristic(0x000c)) val = perf.writeCharacteristic(0x001a, chr(20), withResponse=False) print("test: ", perf.readCharacteristic(0x001a), val) # perf.writeCharacteristic(0x001a,chr(1) + chr(0) + chr(1) + chr(100) + chr(1) + chr(0) + # chr(200)+ chr(2) + chr(0) + chr(200)+ chr(3) + chr(0) + chr(200)) # perf.writeCharacteristic(0x001a,chr(0) + chr(0) + chr(1) + chr(2) + chr(3))
class LightBlueBean(DefaultDelegate): # https://github.com/PunchThrough/bean-documentation/blob/master/app_message_types.md MSG_ID_SERIAL_DATA = 0x0000 MSG_ID_BT_SET_ADV = 0x0500 MSG_ID_BT_SET_CONN = 0x0502 MSG_ID_BT_SET_LOCAL_NAME = 0x0504 MSG_ID_BT_SET_PIN = 0x0506 MSG_ID_BT_SET_TX_PWR = 0x0508 MSG_ID_BT_GET_CONFIG = 0x0510 MSG_ID_BT_ADV_ONOFF = 0x0512 MSG_ID_BT_SET_SCRATCH = 0x0514 MSG_ID_BT_GET_SCRATCH = 0x0515 MSG_ID_BT_RESTART = 0x0520 MSG_ID_GATING = 0x0550 MSG_ID_BL_CMD = 0x1000 MSG_ID_BL_FW_BLOCK = 0x1001 MSG_ID_BL_STATUS = 0x1002 MSG_ID_CC_LED_WRITE = 0x2000 MSG_ID_CC_LED_WRITE_ALL = 0x2001 MSG_ID_CC_LED_READ_ALL = 0x2002 MSG_ID_CC_LED_DATA = 0x2082 MSG_ID_CC_ACCEL_READ = 0x2010 MSG_ID_CC_ACCEL_DATA = 0x2090 MSG_ID_CC_TEMP_READ = 0x2011 MSG_ID_CC_TEMP_DATA = 0x2091 MSG_ID_CC_BATT_READ = 0x2015 MSG_ID_CC_BATT_DATA = 0x2095 MSG_ID_AR_SET_POWER = 0x3000 MSG_ID_AR_GET_CONFIG = 0x3006 MSG_ID_DB_LOOPBACK = 0xFE00 MSG_ID_DB_COUNTER = 0xFE01 def __init__(self, mac): self.conn = Peripheral(mac) self.conn.setDelegate(self) self.count = 0 self.buffin = [None]*10 self.got1 = False print('connected') self.service = self.conn.getServiceByUUID(_LBN_UUID(0x10)) self.serial = self.service.getCharacteristics(_LBN_UUID(0x11)) [0] #print(self.serial.propertiesToString()) # Turn on notificiations self.conn.writeCharacteristic(0x2f, '\x01\x00', False) i = 0 while True: #print(self.serial.read()) self.write("a" * 60) #self.write("a" * 5) #self.sendCmd(LightBlueBean.MSG_ID_CC_ACCEL_READ) self.conn.waitForNotifications(1) time.sleep(1) self.conn.disconnect() def write(self, data): self.sendCmd(LightBlueBean.MSG_ID_SERIAL_DATA, data) def sendCmd(self, cmd, data = ""): # https://github.com/PunchThrough/bean-documentation/blob/master/serial_message_protocol.md gst = struct.pack("!BxH", len(data)+2, cmd) + data crc = struct.pack("<H", crc16(gst, 0xFFFF)) gst += crc gt_qty = len(gst)/19 if len(gst) % 19 != 0: gt_qty += 1 #amnt = len(gst) / gt_qty optimal_packet_size = 19 for ch in xrange(0, gt_qty): data = gst[:optimal_packet_size] gst = gst[optimal_packet_size:] gt = 0 if ch == 0: gt = 0x80 gt |= self.count << 5 gt |= gt_qty - ch - 1 gt = struct.pack("B", gt) + data #print("<", hexdump(gt)) self.serial.write(gt) #time.sleep(0.1) self.count = (self.count + 1) % 4 def writeRaw(self, data): self.conn.writeCharacteristic(0x0b, data, False) def handleNotification(self, cHandle, data): #print(">", hexdump(data)) gt = struct.unpack("B", data[0]) [0] #gt_cntr = gt & 0x60 gt_left = gt & 0x1F if gt & 0x80: self.got1 = True self.buffin = self.buffin[:gt_left+1] self.buffin[gt_left] = data[1:] if self.got1 and not self.buffin.count(None): #print("Got ", len(self.buffin), "packets") self.buffin.reverse() self.buffin = ''.join(self.buffin) crc_ = crc16(self.buffin[:-2], 0xFFFF) dlen, cmd = struct.unpack("!BxH", self.buffin[:4]) crc = struct.unpack("<H", self.buffin[-2:]) [0] if crc == crc_: print(self.buffin[4:-2]) else: print("CRC check failure") self.buffin = [None]*10 self.got1 = False