예제 #1
0
    def display(self, buffer: bytes, delay=10):
        """
        Displays the buffer during 10 seconds by default

        Args:
            buffer (bytes): buffer containing the pattern
            delay (int, optional): time during which the pattern is displayed. Defaults to 10.

        Raises:
            BTLEException: is thrown if no glass are connected 
                when the function is called
            BTLEException: is thrown if the writing characteristic 
                hasn't been found when the function is called
        """
        if self.connected:
            if self.write_characteristic:
                print("[" + Fore.CYAN + "*" + Fore.RESET + "] Sending buffer ...")

                for byte in buffer:
                    self.write_characteristic.write(byte)

                print("[" + Fore.CYAN + "*" + Fore.RESET + "] Buffer sent")
                sleep(delay)
            else:
                raise BTLEException("Characteristic not found")
        else:
            raise BTLEException("No glasses are connected")
예제 #2
0
    def writeCharacteristic(self, handle, payload, withResponse=False):
        LOGGER.debug("write(0x{:x}) payload: %a".format(handle, payload))
        if self._connected is False:
            raise BTLEException(BTLEException.INTERNAL_ERROR, "Helper not started (did you call connect()?)")

        if handle == mi.handle_measurement_control and payload[0] == 0xa0:
            self.cache[mi.handle_measurement_read] = VALUE_MEASUREMENT

        if handle == mi.handle_history_control:
            if payload == mi.cmd_history_read_init:
                self.cache[mi.handle_history_read] = (self.history_items).to_bytes(2, BYTEORDER) + \
                                                     (0).to_bytes(14, BYTEORDER)

            elif payload[0] == int.from_bytes(b'\xa1', BYTEORDER):
                address = int.from_bytes(payload[1:3], byteorder=BYTEORDER)
                self.cache[mi.handle_history_read] = \
                    (3600*(self.history_items - address)).to_bytes(4, BYTEORDER) + \
                    int(20.6*10).to_bytes(2, BYTEORDER) + b'\x00' + \
                    (1066).to_bytes(3, BYTEORDER) + b'\x00' + (57).to_bytes(1, BYTEORDER) + \
                    (123).to_bytes(2, BYTEORDER) + b'\x00\x00'

            elif payload == mi.cmd_history_read_success:
                self.cache[mi.handle_history_read] = VALUE_NO_DATA
                self.history_items = 0

            elif payload == mi.cmd_history_read_failed:
                self.cache[mi.handle_history_read] = VALUE_NO_DATA

        return {'resp': 'wr'} if withResponse else None
예제 #3
0
    def test_read_base_throw_exception(self, mocker):
        ble_char_mock = mocker.Mock(spec=btle.Characteristic)
        ble_char_mock.read.side_effect = BTLEException("Test IO Exception")

        ble_service_mock = mocker.Mock(spec=btle.Service)
        ble_service_mock.getCharacteristics.return_value = [ble_char_mock]

        peripheral_mock = mocker.Mock(spec=Peripheral)
        peripheral_mock.getServiceByUUID.return_value = ble_service_mock

        mocker.patch("omron.env_sensor.Peripheral",
                     autospec=True,
                     return_value=peripheral_mock)

        with pytest.raises(BTLEException) as e:
            env_sensor = OmronEnvSensor(TEST_MAC_ADDRESS)
            (ble_chara, raw_data) = env_sensor.read_char_base(0x1800, 0x2a00)

        assert str(e.value) == "Test IO Exception"

        peripheral_mock.getServiceByUUID.assert_called_with(uuidVal=0x1800)
        assert peripheral_mock.getServiceByUUID.call_count == 5

        ble_service_mock.getCharacteristics.assert_called_with(forUUID=0x2a00)
        assert ble_service_mock.getCharacteristics.call_count == 5

        ble_char_mock.read.assert_called_with()
        assert ble_char_mock.read.call_count == 5
예제 #4
0
    def readCharacteristic(self, handle):
        if self._connected is False:
            raise BTLEException(BTLEException.INTERNAL_ERROR, "Helper not started (did you call connect()?)")

        response = self.cache.get(handle, b'\x00\x00')

        self._read_log.append((handle, response))
        LOGGER.debug("read(0x{:x}) value: %a".format(handle, [x for x in response]))
        return response
예제 #5
0
파일: scan.py 프로젝트: zhengxyzw/bleah
    def process(self, timeout=10.0):
        if self._helper is None:
            raise BTLEException(BTLEException.INTERNAL_ERROR,
                                "Helper not started (did you call start()?)")

        start = time.time()
        while True:
            if timeout:
                remain = start + timeout - time.time()
                if remain <= 0.0:
                    break
            else:
                remain = None

            resp = self._waitResp(['scan', 'stat'], remain)
            if resp is None:
                break

            respType = resp['rsp'][0]

            if respType == 'stat':
                # if scan ended, restart it
                if resp['state'][0] == 'disc':
                    self._mgmtCmd("scan")

            elif respType == 'scan':
                # device found
                addr = self._decode_address(resp)
                dev = self._find_or_create(addr)

                isNewData = dev._update(resp)

                if self.delegate is not None:
                    self.delegate.handleDiscovery(dev, (dev.updateCount <= 1),
                                                  isNewData)

                if self.mac is not None and dev.addr == self.mac:
                    break

            else:
                raise BTLEException(BTLEException.INTERNAL_ERROR,
                                    "Unexpected response: " + respType)
예제 #6
0
    def gatherAverageRSSI(self, manufacturer, n_samples, passive=False):
        self.clear()
        self.start(passive=passive)

        rssi_scans = []

        while len(rssi_scans) < n_samples:
            # wait 3 seconds before a timeout
            resp = self._waitResp(['scan', 'stat'], 3.0)
            #                                        ^

            if resp is None:
                break

            respType = resp['rsp'][0]
            if respType == 'stat':
                # if scan ended, restart it
                if resp['state'][0] == 'disc':
                    self._mgmtCmd("scan")

            elif respType == 'scan':
                # device found
                addr = binascii.b2a_hex(resp['addr'][0]).decode('utf-8')
                addr = ':'.join([addr[i:i + 2] for i in range(0, 12, 2)])
                if addr in self.scanned:
                    dev = self.scanned[addr]
                else:
                    dev = ScanEntry(addr, self.iface)
                    self.scanned[addr] = dev
                isNewData = dev._update(resp)

                for (adtype, desc, value) in dev.getScanData():
                    if desc == "Manufacturer" and value == manufacturer:
                        rssi_scans.append(dev.rssi)

            else:
                raise BTLEException(BTLEException.INTERNAL_ERROR,
                                    "Unexpected response: " + respType)

        mean_rssi = mean(rssi_scans)

        std_dev = stdev(rssi_scans)

        cutoff_rssi = []

        lower_cutoff = mean_rssi - std_dev
        upper_cutoff = mean_rssi + std_dev

        for x in rssi_scans:
            if not (x < lower_cutoff or x > upper_cutoff):
                cutoff_rssi.append(x)

        self.stop()
        return mean(cutoff_rssi)
예제 #7
0
 def join(self):
     """Join the thread.
     
     Raises:
         'BTLEException' is raised if this method is not run as root.
     """
     super(_StoppableScanner, self).join()
     if self._exc:
         msg = '\nBluetooth scanning requires root privilege, ' \
               'so please run the script with \"sudo\".'
         raise BTLEException(0, msg)
예제 #8
0
    def disconnect(self):
        """
        Disconnects from the glasses

        Raises:
            BTLEException: is thrown if no glasses are connected
        """
        if self.connected:
            self.peripheral.disconnect()
            print("[" + Fore.RED + "-" + Fore.RESET + "] Glasses disconnected")
        else:
            raise BTLEException("No glasses are connected")
예제 #9
0
    def discover(self,
                 timeout_s=SCANNING_TIME_DEFAULT_s,
                 asynchronous=False,
                 show_warnings=False):
        """Perform the discovery process.

        This method can be run in synchronous (blocking) or asynchronous
        (non-blocking) way. Default is synchronous.

        The discovery process will last *timeout_s* seconds if provided, a
        default timeout otherwise.

        Args:
            timeout_s (int, optional): Time in seconds to wait before stopping
                the discovery process.
            asynchronous (bool, optional): If True the method is run in
                asynchronous way, thus non-blocking the execution of the thread,
                the opposite otherwise.
            show_warnings (bool, optional): If True shows warnings, if any, when
                discovering devices not respecting the BlueSTSDK's advertising
                data format, nothing otherwise.

        Returns:
            bool: True if the synchronous discovery has finished or if the
            asynchronous discovery has started, False if a discovery is already
            running.

        Raises:
            'BTLEException' is raised if this method is not run as root.
        """
        try:
            if not asynchronous:
                # Synchronous version.
                if self.is_discovering():
                    return False
                self._discovered_nodes = []
                self._notify_discovery_change(True)
                self._scanner = \
                    Scanner().withDelegate(_ScannerDelegate(show_warnings))
                self._scanner.scan(timeout_s)
                self._notify_discovery_change(False)
                return True
            else:
                # Asynchronous version.
                if not self.start_discovery(show_warnings):
                    return False
                threading.Timer(timeout_s, self.stop_discovery).start()
                return True
        except BTLEException as e:
            msg = '\nBluetooth scanning requires root privilege, ' \
                  'so please run the script with \"sudo\".'
            raise BTLEException(msg)
예제 #10
0
    def process(self, timeout=10.0):
        if self._helper is None:
            raise BTLEException(BTLEException.INTERNAL_ERROR,
                                "Helper not started (did you call start()?)")
        start = time.time()
        while True:
            if timeout:
                remain = start + timeout - time.time()
                if remain <= 0.0:
                    break
            else:
                remain = None
            resp = self._waitResp(['scan', 'stat'], remain)
            if resp is None:
                break

            respType = resp['rsp'][0]
            if respType == 'stat':
                # if scan ended, restart it
                if resp['state'][0] == 'disc':
                    self._mgmtCmd("scan")

            elif respType == 'scan':
                # device found
                addr = binascii.b2a_hex(resp['addr'][0]).decode('utf-8')
                addr = ':'.join([addr[i:i + 2] for i in range(0, 12, 2)])
                if addr in self.scanned:
                    dev = self.scanned[addr]
                else:
                    dev = ScanEntry(addr, self.iface)
                    self.scanned[addr] = dev
                isNewData = dev._update(resp)
                if self.delegate is not None:
                    self.delegate.handleDiscovery(dev, (dev.updateCount <= 1),
                                                  isNewData)

            else:
                raise BTLEException(BTLEException.INTERNAL_ERROR,
                                    "Unexpected response: " + respType)
예제 #11
0
class TestBluepy(unittest.TestCase):
    """Unit tests for the bluepy backend."""

    # pylint: disable=no-self-use

    @mock.patch('bluepy.btle.Peripheral')
    def test_configuration_default(self, mock_peripheral):
        """Test adapter name pattern parsing."""
        backend = BluepyBackend()
        backend.connect(TEST_MAC)
        mock_peripheral.assert_called_with(TEST_MAC,
                                           addrType='public',
                                           iface=0)

    @mock.patch('bluepy.btle.Peripheral')
    def test_configuration_hci12(self, mock_peripheral):
        """Test adapter name pattern parsing."""
        backend = BluepyBackend(adapter='hci12')
        backend.connect(TEST_MAC)
        mock_peripheral.assert_called_with(TEST_MAC,
                                           addrType='public',
                                           iface=12)

    @mock.patch('bluepy.btle.Peripheral')
    def test_configuration_invalid(self, _):
        """Test adapter name pattern parsing."""
        backend = BluepyBackend(adapter='somestring')
        with self.assertRaises(BluetoothBackendException):
            backend.connect(TEST_MAC)

    def test_check_backend_ok(self):
        """Test check_backend successfully."""
        self.assertTrue(BluepyBackend.check_backend())

    @mock.patch('bluepy.btle.Peripheral',
                **{'side_effect': BTLEException(1, 'text')})
    def test_connect_exception(self, _):
        """Test exception wrapping."""
        backend = BluepyBackend()
        with self.assertRaises(BluetoothBackendException):
            backend.connect(TEST_MAC)

    @mock.patch('bluepy.btle.Peripheral')
    def test_wait_for_notification(self, mock_peripheral):
        """Test writing to a handle successfully."""
        backend = BluepyBackend()
        backend.connect(TEST_MAC)
        self.assertTrue(backend.wait_for_notification(0xFF, None, 10))
        mock_peripheral.assert_called_with(TEST_MAC,
                                           addrType='public',
                                           iface=0)
예제 #12
0
    def _waitResp(self, wantType, timeout=None):
        self._log.debug("Z1: _waitResp override method in timeout:" +
                        str(timeout))
        while True:
            if self._helper.poll() is not None:
                raise BTLEInternalError("Helper exited")

            if timeout:
                fds = self._poller.poll(timeout * 1000)
                if len(fds) == 0:
                    self._log.info("Select timeout:" + str(timeout))
                    return None

            rv = self._helper.stdout.readline()
            self._log.debug("Got:" + str(repr(rv)))
            if rv.startswith('#') or rv == '\n' or len(rv) == 0:
                continue

            resp = BluepyHelper.parseResp(rv)
            if 'rsp' not in resp:
                raise BTLEInternalError("No response type indicator", resp)

            respType = resp['rsp'][0]
            if respType in wantType:
                return resp
            elif respType == 'stat':
                if 'state' in resp and len(
                        resp['state']) > 0 and resp['state'][0] == 'disc':
                    self._stopHelper()
                    raise BTLEDisconnectError("Device disconnected", resp)
            elif respType == 'err':
                errcode = resp['code'][0]
                if errcode == 'nomgmt':
                    raise BTLEManagementError(
                        "Management not available (permissions problem?)",
                        resp)
                elif errcode == 'atterr':
                    raise BTLEGattError("Bluetooth command failed", resp)
                else:
                    raise BTLEException(
                        "Error from bluepy-helper (%s)" % errcode, resp)
            elif respType == 'scan':
                # Scan response when we weren't interested. Ignore it
                continue
            else:
                raise BTLEInternalError("Unexpected response (%s)" % respType,
                                        resp)
예제 #13
0
    def __init__(self, peripheral, callback):
        try:
            service = peripheral.getServiceByUUID(self._UUID_SERVICE)

            self._char_tx = service.getCharacteristics(
                forUUID=self._UUID_CHARACTERISTIC_TX)[0]
            self._char_rx = service.getCharacteristics(
                forUUID=self._UUID_CHARACTERISTIC_RX)[0]
            self._desc_tx = service.getDescriptors(
                forUUID=self._UUID_DESCRIPTOR_TX)[0]
        except (BTLEException, IndexError) as exception:
            raise BTLEException(
                "Transparent UART service not found") from exception

        # Set up the notification delegate and turn them on
        delegate = self._TransparentDelegate(callback)
        peripheral.setDelegate(delegate)
        self._desc_tx.write(b'\x01\x00')
예제 #14
0
    def discover(self, show_warnings=False, timeout_s=0):
        """Perform the discovery process.

        The discovery process will last *timeout_s* seconds if provided, a
        default timeout otherwise.

        Synchronous method.

        Args:
            show_warnings (bool, optional): If True shows warnings, if any, when
                discovering devices not respecting the BlueSTSDK's advertising
                data format, nothing otherwise.
            timeout_s (int, optional): Time in seconds to wait before stopping
                the discovery process.

        Returns:
            bool: True if the discovery has finished, False if a discovery is
            already running.

        Raises:
            'BTLEException' is raised if this method is not run as root.
        """
        try:
            if self.is_discovering():
                return False
            if timeout_s == 0:
                timeout_s = _ScannerDelegate.SCANNING_TIME_DEFAULT_s
            self._notify_discovery_change(True)
            self._scanner = Scanner().withDelegate(
                _ScannerDelegate(show_warnings))
            self._scanner.scan(timeout_s)
            self._notify_discovery_change(False)
            return True
        except BTLEException as e:
            msg = '\nBluetooth scanning requires root privilege, ' \
                  'so please run the script with \"sudo\".'
            raise BTLEException(e.code, msg)
예제 #15
0
 def process(self, timeout=300.0):
     """
         Method receives advertisements from nodes. Variable timeout has default value 300 seconds, it define time 
         after which method will end. 
     """
     if self._helper is None:
         raise BTLEException(BTLEException.INTERNAL_ERROR,
                             "Helper not started (did you call start()?)")
     start = time.time()
     while True:
         if timeout:
             remain = start + timeout - time.time()
             if remain <= 0.0:
                 break
         else:
             remain = None
         resp = self._waitResp(['scan', 'stat'], remain)
         if resp is None:
             break
         respType = resp['rsp'][0]
         if respType == 'stat':
             logging.info("STAT message,")
             # if scan ended, restart it
             if resp['state'][0] == 'disc':
                 logging.warning("Executing SCAN cmd!")
                 self._mgmtCmd("scan")
         elif respType == 'scan':
             # device found
             addr = binascii.b2a_hex(resp['addr'][0]).decode('utf-8')
             addr = ':'.join([addr[i:i + 2] for i in range(0, 12, 2)])
             addr = addr.upper()
             if not Device.select(lambda d: d.id.upper() == addr).first(
             ) and not settings.ALLOW_ANY:
                 logging.warning(
                     "Unknown device {} send message, skipping...".format(
                         addr))
                 continue
             dev = ScanEntry(addr, self.iface)
             logging.info("SCAN message from {}".format(addr))
             dev._update(resp)
             if not settings.ALLOW_ANY:
                 name = ''
                 for data in dev.getScanData():
                     for x in data:
                         if type("Name") == type(x) and "Name" in x:
                             name = data[-1]
                 if not settings.NAME_VALIDATION:
                     logging.warning(
                         "Accepting device without name validation...")
                 elif Device[addr].name != name and Device[
                         addr].name != None:
                     logging.warning(
                         "{} invalid name valid: {}, received: {}, skipping..."
                         .format(addr, name, Device[addr].name))
                     continue
             if self.delegate is not None:
                 self.delegate.handleDiscovery(dev, (dev.updateCount <= 1),
                                               True)
         else:
             raise BTLEException(BTLEException.INTERNAL_ERROR,
                                 "Unexpected response: " + respType)
예제 #16
0
 def test_connect_exception(self, mock_peripheral):
     """Test exception wrapping."""
     mock_peripheral.side_effect = BTLEException("Test")
     backend = BluepyBackend()
     with self.assertRaises(BluetoothBackendException):
         backend.connect(TEST_MAC)
예제 #17
0
 def _fail_for_n(self, n):
     self.failcount += 1
     if self.failcount < n:
         raise BTLEException(0, 'test exception')
     return self.failcount
예제 #18
0
 def __init__(self, peripheral):
     try:
         self._service = peripheral.getServiceByUUID(self._UUID_SERVICE)
     except (BTLEException, IndexError) as exception:
         raise BTLEException("DeviceInfo service not found") from exception