Пример #1
0
 def _func_wrapper(*args, **kwargs):
     try:
         return func(*args, **kwargs)
     except BGAPIError as exception:
         raise BluetoothBackendException() from exception
     except NotConnectedError as exception:
         raise BluetoothBackendException() from exception
Пример #2
0
    def write_handle(self, handle, value):
        """Read from a BLE address.

        @param: mac - MAC address in format XX:XX:XX:XX:XX:XX
        @param: handle - BLE characteristics handle in format 0xXX
        @param: value - value to write to the given handle
        @param: timeout - timeout in seconds
        """

        if not self.is_connected():
            raise BluetoothBackendException('Not connected to any device.')

        attempt = 0
        delay = 10
        _LOGGER.debug("Enter write_ble (%s)", current_thread())

        while attempt <= self.retries:
            cmd = "gatttool --device={} --char-write-req -a {} -n {} --adapter={}".format(
                self._mac, self.byte_to_handle(handle),
                self.bytes_to_string(value), self.adapter)
            _LOGGER.debug("Running gatttool with a timeout of %d: %s",
                          self.timeout, cmd)

            with Popen(cmd,
                       shell=True,
                       stdout=PIPE,
                       stderr=PIPE,
                       preexec_fn=os.setsid) as process:
                try:
                    result = process.communicate(timeout=self.timeout)[0]
                    _LOGGER.debug("Finished gatttool")
                except TimeoutExpired:
                    # send signal to the process group
                    os.killpg(process.pid, signal.SIGINT)
                    result = process.communicate()[0]
                    _LOGGER.debug("Killed hanging gatttool")

            result = result.decode("utf-8").strip(' \n\t')
            if "Write Request failed" in result:
                raise BluetoothBackendException(
                    'Error writing handls to sensor: {}'.format(result))
            _LOGGER.debug("Got %s from gatttool", result)
            # Parse the output
            if "successfully" in result:
                _LOGGER.debug("Exit write_ble with result (%s)",
                              current_thread())
                return True

            attempt += 1
            _LOGGER.debug("Waiting for %s seconds before retrying", delay)
            if attempt < self.retries:
                time.sleep(delay)
                delay *= 2

        raise BluetoothBackendException("Exit write_ble, no data ({})".format(
            current_thread()))
Пример #3
0
    def read_handle(self, handle):
        """Read from a BLE address.

        @param: mac - MAC address in format XX:XX:XX:XX:XX:XX
        @param: handle - BLE characteristics handle in format 0xXX
        @param: timeout - timeout in seconds
        """

        if not self.is_connected():
            raise BluetoothBackendException('Not connected to any device.')

        attempt = 0
        delay = 10
        _LOGGER.debug("Enter read_ble (%s)", current_thread())

        while attempt <= self.retries:
            cmd = "gatttool --device={} --char-read -a {} --adapter={}".format(
                self._mac, self.byte_to_handle(handle), self.adapter)
            _LOGGER.debug("Running gatttool with a timeout of %d: %s",
                          self.timeout, cmd)
            with Popen(cmd,
                       shell=True,
                       stdout=PIPE,
                       stderr=PIPE,
                       preexec_fn=os.setsid) as process:
                try:
                    result = process.communicate(timeout=self.timeout)[0]
                    _LOGGER.debug("Finished gatttool")
                except TimeoutExpired:
                    # send signal to the process group
                    os.killpg(process.pid, signal.SIGINT)
                    result = process.communicate()[0]
                    _LOGGER.debug("Killed hanging gatttool")

            result = result.decode("utf-8").strip(' \n\t')
            _LOGGER.debug("Got \"%s\" from gatttool", result)
            # Parse the output
            if "read failed" in result:
                raise BluetoothBackendException(
                    "Read error from gatttool: {}".format(result))

            res = re.search("( [0-9a-fA-F][0-9a-fA-F])+", result)
            if res:
                _LOGGER.debug("Exit read_ble with result (%s)",
                              current_thread())
                return bytes([int(x, 16) for x in res.group(0).split()])

            attempt += 1
            _LOGGER.debug("Waiting for %s seconds before retrying", delay)
            if attempt < self.retries:
                time.sleep(delay)
                delay *= 2

        raise BluetoothBackendException("Exit read_ble, no data ({})".format(
            current_thread()))
Пример #4
0
    def parameter_value(self, parameter, read_cached=True):
        """Return a value of one of the monitored paramaters.

        This method will try to retrieve the data from cache and only
        request it by bluetooth if no cached value is stored or the cache is
        expired.
        This behaviour can be overwritten by the "read_cached" parameter.
        """
        # Special handling for battery attribute
        if parameter == MI_BATTERY:
            return self.battery_level()

        # Use the lock to make sure the cache isn't updated multiple times
        with self.lock:
            if (read_cached is False) or \
                    (self._last_read is None) or \
                    (datetime.now() - self._cache_timeout > self._last_read):
                self.fill_cache()
            else:
                _LOGGER.debug("Using cache (%s < %s)",
                              datetime.now() - self._last_read,
                              self._cache_timeout)

        if self.cache_available() and (len(self._cache) == 16):
            return self._parse_data()[parameter]
        else:
            raise BluetoothBackendException(
                "Could not read data from Mi Flora sensor %s" % self._mac)
Пример #5
0
 def check_backend(self):
     try:
         call('gatttool', stdout=PIPE, stderr=PIPE)
         return True
     except OSError as e:
         msg = 'gatttool not found: {}'.format(str(e))
         _LOGGER.error(msg)
         raise BluetoothBackendException(msg)
Пример #6
0
    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)
Пример #7
0
    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)
Пример #8
0
    def name(self):
        """Return the name of the sensor."""
        with self._bt_interface.connect(self._mac) as connection:
            name = connection.read_handle(_HANDLE_READ_NAME)  # pylint: disable=no-member

        if not name:
            raise BluetoothBackendException(
                "Could not read data from Mi Flora sensor %s" % self._mac)
        return ''.join(chr(n) for n in name)
Пример #9
0
 def connect(self, mac):
     """Connect to a device."""
     from bluepy.btle import Peripheral
     match_result = re.search(r'hci([\d]+)', self.adapter)
     if match_result is None:
         raise BluetoothBackendException(
             'Invalid pattern "{}" for BLuetooth adpater. '
             'Expetected something like "hci0".'.format(self.adapter))
     iface = int(match_result.group(1))
     self._peripheral = Peripheral(mac, iface=iface)
Пример #10
0
 def _func_wrapper(*args, **kwargs):
     error_count = 0
     last_error = None
     while error_count < RETRY_LIMIT:
         try:
             return func(*args, **kwargs)
         except BTLEException as exception:
             error_count += 1
             last_error = exception
             time.sleep(RETRY_DELAY)
             _LOGGER.debug('Call to %s failed, try %d of %d', func,
                           error_count, RETRY_LIMIT)
     raise BluetoothBackendException() from last_error
Пример #11
0
 def _func_wrapper(*args, **kwargs):
     try:
         return func(*args, **kwargs)
     except IOError as exception:
         raise BluetoothBackendException() from exception
Пример #12
0
 def check_backend(self):
     try:
         import bluepy.btle  # noqa: F401
     except ImportError:
         raise BluetoothBackendException('bluepy not found')
Пример #13
0
 def write_handle(self, handle, value):
     if self._peripheral is None:
         raise BluetoothBackendException('not connected to backend')
     return self._peripheral.writeCharacteristic(handle, value, True)
Пример #14
0
 def read_handle(self, handle):
     if self._peripheral is None:
         raise BluetoothBackendException('not connected to backend')
     return self._peripheral.readCharacteristic(handle)
Пример #15
0
 def connect(self, mac):
     """Raise exception when connecting."""
     raise BluetoothBackendException('always raising exceptions')
Пример #16
0
 def check_backend(self):
     """Check if the backend is available."""
     try:
         import bluepy.btle  # noqa: F401
     except ImportError:
         raise BluetoothBackendException('bluepy not found')
Пример #17
0
 def write_handle(self, handle, value):
     """Write a handle to the device."""
     if not self.is_connected():
         raise BluetoothBackendException('Not connected to device!')
     self._device.char_write_handle(handle, value, True)
     return True
Пример #18
0
 def read_handle(self, handle):
     """Read a handle from the device."""
     if not self.is_connected():
         raise BluetoothBackendException('Not connected to device!')
     return self._device.char_read_handle(handle)
Пример #19
0
 def read_write(self, _, __):  # pylint: disable=no-self-use
     """Writing always fails."""
     raise BluetoothBackendException('always raising')
Пример #20
0
 def read_handle(self, _):
     """Reading always fails."""
     raise BluetoothBackendException('always raising')