Example #1
1
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()
Example #3
0
  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
Example #4
0
	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);
Example #5
0
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")
Example #6
0
 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)
Example #7
0
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
Example #9
0
    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
Example #10
0
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)
Example #11
0
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
Example #12
0
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)
Example #15
0
    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()
Example #16
0
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()
Example #17
0
 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
Example #18
0
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
Example #19
0
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)
Example #20
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')
Example #21
0
    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
Example #22
0
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()
Example #23
0
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...")
Example #25
0
 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)
Example #26
0
	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
Example #29
0
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"))
Example #31
0
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')
Example #32
0
 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)
Example #33
0
    # 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()
Example #34
0
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:
Example #35
0
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()    
Example #36
0
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)
Example #37
0
  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