コード例 #1
0
 def set_aspect_mode(self, mode):
     """
     Args:
         mode (str): One of ("letterbox" | "fill" | "stretch")
     """
     self._get_player_interface().SetAspectMode(ObjectPath('/not/used'),
                                                String(mode))
コード例 #2
0
 def set_alpha(self, alpha):
     """
     Args:
         alpha (float): The transparency (0..255)
     """
     self._get_player_interface().SetAlpha(ObjectPath('/not/used'),
                                           Int64(alpha))
コード例 #3
0
    def __init__(self, iface: str = 'hci0', ioc: str = 'NoInputNoOutput'):
        super().__init__(iface=iface)

        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
        sys_bus = SystemBus()

        self.agent_registered = False

        def register_agent_callback():
            logger.info('Agent object registered')
            print(INFO_INDENT,
                  "IO capability: {}".format(
                      self.bluescan_agent.io_capability),
                  sep='')
            self.agent_registered = True

        def register_agent_error_callback(error):
            logger.error("Failed to register agent object")
            print(ERROR_INDENT, "{}".format(error), sep='')
            print(ERROR_INDENT,
                  "IO capability: {}".format(
                      self.bluescan_agent.io_capability),
                  sep='')
            self.agent_registered = False

        self.bluescan_agent = BluescanAgent(sys_bus, 0, ioc)
        self.agent_mgr_1_iface = dbus.Interface(
            sys_bus.get_object(BLUEZ_NAME, '/org/bluez'), IFACE_AGENT_MGR_1)
        self.agent_mgr_1_iface.RegisterAgent(
            ObjectPath(self.bluescan_agent.path),
            self.bluescan_agent.io_capability,
            reply_handler=register_agent_callback,
            error_handler=register_agent_error_callback)
コード例 #4
0
 def video_pos(self):
     """
     Returns:
     """
     position_string = self._player_interface.VideoPos(
         ObjectPath('/not/used'), String(position))
     return list(map(int, position_string.split(" ")))
コード例 #5
0
ファイル: CameraStream.py プロジェクト: scepter7/rpisurv
 def unhide_stream(self):
     logger.debug('CameraStream: Unhide stream instruction ' + self.name + ' received from dbus interface')
     if platform.system() == "Linux":
         if self.dbusconnection is not None:
             self.dbusconnection.player_interface.SetAlpha(ObjectPath('/not/used'), Int64(255))
         else:
             logger.error('CameraStream: ' + self.name + ' has no dbus connection, probably because omxplayer crashed because it can not connect to this stream. As a result we could not unhide this stream at this time.')
コード例 #6
0
ファイル: CameraStream.py プロジェクト: scepter7/rpisurv
 def set_videopos(self,new_coordinates):
     logger.debug('CameraStream: ' + self.name + ' Set new position for ' + self.name + ' with new coordinates: + ' + str(new_coordinates) + ' on dbus interface')
     if platform.system() == "Linux":
         if self.dbusconnection is not None:
             self.dbusconnection.VideoPosWrapper((ObjectPath('/not/used'), String(" ".join(map(str,new_coordinates)))))
         else:
             logger.error('CameraStream: ' + self.name + ' has no dbus connection, probably because omxplayer crashed because it can not connect to this stream. As a result we could not change its videopos dynamically for this stream at this time.')
コード例 #7
0
    def __init__(self, iface: str = 'hci0', ioc: str = 'NoInputNoOutput'):
        super().__init__(iface=iface)

        self.result = GattScanResult()
        self.gatt_client = None
        self.spinner = Halo()

        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
        sys_bus = SystemBus()

        self.agent_registered = False

        def register_agent_callback():
            logger.debug('Agent object registered\n'
                         "IO capability: {}".format(
                             self.bluescan_agent.io_capability))
            self.agent_registered = True

        def register_agent_error_callback(error):
            logger.error(
                "Failed to register agent object.\n" + "{}\n".format(error) +
                "IO capability: {}".format(self.bluescan_agent.io_capability))
            self.agent_registered = False

        self.bluescan_agent = BluescanAgent(sys_bus, 0, ioc)
        self.agent_mgr_1_iface = dbus.Interface(
            sys_bus.get_object(BLUEZ_NAME, '/org/bluez'), IFACE_AGENT_MGR_1)
        self.agent_mgr_1_iface.RegisterAgent(
            ObjectPath(self.bluescan_agent.path),
            self.bluescan_agent.io_capability,
            reply_handler=register_agent_callback,
            error_handler=register_agent_error_callback)
コード例 #8
0
ファイル: player.py プロジェクト: msearra/edus2
    def set_alpha(self, alpha):
        """
        Set the transparency of the video overlay

        Args:
            alpha (float): The transparency (0..255)
        """
        self._player_interface.SetAlpha(ObjectPath('/not/used'), Int64(alpha))
コード例 #9
0
 def set_position(self, position):
     """
     Args:
         position (float): The position in seconds.
     """
     self._get_player_interface().SetPosition(ObjectPath("/not/used"),
                                              Int64(position * 1000 * 1000))
     self.positionEvent(self, position)
コード例 #10
0
 def set_video_crop(self, x1, y1, x2, y2):
     """
     Args:
         Image position (int, int, int, int):
     """
     crop = "%s %s %s %s" % (str(x1), str(y1), str(x2), str(y2))
     self._get_player_interface().SetVideoCropPos(ObjectPath('/not/used'),
                                                  String(crop))
コード例 #11
0
 def set_video_pos(self, x1, y1, x2, y2):
     """
     Args:
         Image position (int, int, int, int):
     """
     position = "%s %s %s %s" % (str(x1), str(y1), str(x2), str(y2))
     self._get_player_interface().VideoPos(ObjectPath('/not/used'),
                                           String(position))
コード例 #12
0
ファイル: player.py プロジェクト: msearra/edus2
 def video_pos(self):
     """
     Returns:
         (int, int, int, int): Video spatial position (x1, y1, x2, y2) where (x1, y1) is top left,
                               and (x2, y2) is bottom right. All values in px.
     """
     position_string = self._player_interface.VideoPos(
         ObjectPath('/not/used'))
     return list(map(int, position_string.split(" ")))
コード例 #13
0
ファイル: player.py プロジェクト: msearra/edus2
    def set_position(self, position):
        """
        Set the video to playback position to `position` seconds from the start of the video

        Args:
            position (float): The position in seconds.
        """
        self._player_interface.SetPosition(ObjectPath("/not/used"),
                                           Int64(position * 1000.0 * 1000))
        self.positionEvent(self, position)
コード例 #14
0
ファイル: player.py プロジェクト: msearra/edus2
 def set_video_crop(self, x1, y1, x2, y2):
     """
     Args:
         x1 (int): Top left x coordinate (px)
         y1 (int): Top left y coordinate (px)
         x2 (int): Bottom right x coordinate (px)
         y2 (int): Bottom right y coordinate (px)
     """
     crop = "%s %s %s %s" % (str(x1), str(y1), str(x2), str(y2))
     self._player_interface.SetVideoCropPos(ObjectPath('/not/used'),
                                            String(crop))
コード例 #15
0
ファイル: player.py プロジェクト: msearra/edus2
    def set_video_pos(self, x1, y1, x2, y2):
        """
        Set the video position on the screen

        Args:
            x1 (int): Top left x coordinate (px)
            y1 (int): Top left y coordinate (px)
            x2 (int): Bottom right x coordinate (px)
            y2 (int): Bottom right y coordinate (px)
        """
        position = "%s %s %s %s" % (str(x1), str(y1), str(x2), str(y2))
        self._player_interface.VideoPos(ObjectPath('/not/used'),
                                        String(position))
コード例 #16
0
    def _message_cb(self, connection, message):
        if not isinstance(message, MethodCallMessage):
            return

        try:
            # lookup candidate method and parent method
            method_name = message.get_member()
            interface_name = message.get_interface()
            (candidate_method,
             parent_method) = _method_lookup(self, method_name, interface_name)

            # set up method call parameters
            args = message.get_args_list(
                **parent_method._dbus_get_args_options)
            keywords = {}

            if parent_method._dbus_out_signature is not None:
                signature = Signature(parent_method._dbus_out_signature)
            else:
                signature = None

            # set up async callback functions
            if parent_method._dbus_async_callbacks:
                (return_callback,
                 error_callback) = parent_method._dbus_async_callbacks
                keywords[
                    return_callback] = lambda *retval: _method_reply_return(
                        connection, message, method_name, signature, *retval)
                keywords[
                    error_callback] = lambda exception: _method_reply_error(
                        connection, message, exception)

            # include the sender etc. if desired
            if parent_method._dbus_sender_keyword:
                keywords[
                    parent_method._dbus_sender_keyword] = message.get_sender()
            if parent_method._dbus_path_keyword:
                keywords[parent_method._dbus_path_keyword] = message.get_path()
            if parent_method._dbus_rel_path_keyword:
                path = message.get_path()
                rel_path = path
                for exp in self._locations:
                    # pathological case: if we're exported in two places,
                    # one of which is a subtree of the other, then pick the
                    # subtree by preference (i.e. minimize the length of
                    # rel_path)
                    if exp[0] is connection:
                        if path == exp[1]:
                            rel_path = '/'
                            break
                        if exp[1] == '/':
                            # we already have rel_path == path at the beginning
                            continue
                        if path.startswith(exp[1] + '/'):
                            # yes we're in this exported subtree
                            suffix = path[len(exp[1]):]
                            if len(suffix) < len(rel_path):
                                rel_path = suffix
                rel_path = ObjectPath(rel_path)
                keywords[parent_method._dbus_rel_path_keyword] = rel_path

            if parent_method._dbus_destination_keyword:
                keywords[
                    parent_method.
                    _dbus_destination_keyword] = message.get_destination()
            if parent_method._dbus_message_keyword:
                keywords[parent_method._dbus_message_keyword] = message
            if parent_method._dbus_connection_keyword:
                keywords[parent_method._dbus_connection_keyword] = connection

            # call method
            retval = candidate_method(self, *args, **keywords)

            # we're done - the method has got callback functions to reply with
            if parent_method._dbus_async_callbacks:
                return

            # otherwise we send the return values in a reply. if we have a
            # signature, use it to turn the return value into a tuple as
            # appropriate
            if signature is not None:
                signature_tuple = tuple(signature)
                # if we have zero or one return values we want make a tuple
                # for the _method_reply_return function, otherwise we need
                # to check we're passing it a sequence
                if len(signature_tuple) == 0:
                    if retval is None:
                        retval = ()
                    else:
                        raise TypeError(
                            '%s has an empty output signature but did not return None'
                            % method_name)
                elif len(signature_tuple) == 1:
                    retval = (retval, )
                else:
                    if isinstance(retval, Sequence):
                        # multi-value signature, multi-value return... proceed
                        # unchanged
                        pass
                    else:
                        raise TypeError(
                            '%s has multiple output values in signature %s but did not return a sequence'
                            % (method_name, signature))

            # no signature, so just turn the return into a tuple and send it as normal
            else:
                if retval is None:
                    retval = ()
                elif (isinstance(retval, tuple)
                      and not isinstance(retval, Struct)):
                    # If the return is a tuple that is not a Struct, we use it
                    # as-is on the assumption that there are multiple return
                    # values - this is the usual Python idiom. (fd.o #10174)
                    pass
                else:
                    retval = (retval, )

            _method_reply_return(connection, message, method_name, signature,
                                 *retval)
        except Exception as exception:
            # send error reply
            _method_reply_error(connection, message, exception)
コード例 #17
0
    def scan(self, bdaddr, addr_type, include_descriptor: bool):
        """
        bdaddr - Remote BD_ADDR
        """
        def run_mainloop():
            mainloop.run()

        mainloop_thread = threading.Thread(target=run_mainloop, args=[])
        mainloop_thread.start()

        try:
            try:
                target = Peripheral(bdaddr,
                                    iface=self.devid,
                                    addrType=addr_type)
            except BTLEDisconnectError as e:
                logger.error("BTLEDisconnectError")
                print(ERROR_INDENT, e, sep='')
                return

            services = target.getServices()
            print("Number of services: %s\n\n" % len(services))

            # Show service
            for service in services:
                logger.debug('Start handle: {}'.format(service.hndStart))
                logger.debug('End handle: {}'.format(service.hndEnd))

                try:
                    characteristics = []
                    characteristics = service.getCharacteristics()
                except BTLEException as e:
                    logger.warning("BTLEException")
                    print(WARNING_INDENT, e, sep='')
                    # continue

                print(
                    blue('Service'), '(0x%04x - 0x%04x, %s characteristics)' %
                    (service.hndStart, service.hndEnd, len(characteristics)))
                print(
                    indent + 'Handle: 0x%04x' % service.hndStart
                )  # ", "\"attr handle\" by using gatttool -b <BD_ADDR> --primary
                print(indent + 'Type: (May be primary service 0x2800)')
                print(indent + 'Value (Service UUID): ',
                      blue(str(service.uuid).replace(sig_uuid_suffix, '')),
                      end=' ')
                try:
                    print(
                        '(' +
                        services_spec['0x' +
                                      ("%s" %
                                       service.uuid)[4:8].upper()]['Name'] +
                        ')', '\x1B[0m')
                except KeyError:
                    print('(' + red('unknown') + ')', '\x1B[0m')
                print(
                    indent +
                    'Permission: Read Only, No Authentication, No Authorization\n'
                )

                # Show characteristic
                for characteristic in characteristics:
                    descriptors = []
                    # 对每个 characteristic 都获取 descriptor 会很耗时
                    # 有些设备会因此断开连接。于是这里提供了一个是否获取 descriptor 的选项
                    if include_descriptor:
                        descriptors = characteristic.getDescriptors()

                    try:
                        print(indent + yellow('Characteristic'),
                              '(%s descriptors)' % len(descriptors))
                        #print('-'*8)
                        print(indent * 2 + 'Handle: %#06x' %
                              (characteristic.getHandle() - 1))
                        print(indent * 2 + 'Type: 0x2803 (Characteristic)')
                        print(indent * 2 + 'Value:')
                        print(indent * 3 + 'Characteristic properties:',
                              green(characteristic.propertiesToString()))
                        print(indent * 3 +
                              'Characteristic value handle: %#06x' %
                              characteristic.getHandle())
                        print(
                            indent * 3 + 'Characteristic UUID: ',
                            green(
                                str(characteristic.uuid).replace(
                                    sig_uuid_suffix, '')),
                            end=' '
                        )  # This UUID is also the type field of characteristic value declaration attribute.
                        try:
                            print('(' + characteristics_spec['0x' + (
                                "%s" %
                                characteristic.uuid)[4:8].upper()]['Name'] +
                                  ')')
                        except KeyError:
                            print('(' + red('unknown') + ')')
                        print(
                            indent * 3 +
                            'Permission: Read Only, No Authentication, No Authorization'
                        )

                        if characteristic.supportsRead():
                            print(indent + yellow('Characteristic value'))
                            print(indent * 2 + 'Handle:',
                                  green('%#06x' % characteristic.getHandle()))
                            print(
                                indent * 2 + 'Type:',
                                str(characteristic.uuid).replace(
                                    sig_uuid_suffix, ''))
                            print(indent * 2 + 'Value:',
                                  green(str(characteristic.read())))
                            print(
                                indent * 2 +
                                'Permission: Higher layer profile or implementation-specific'
                            )
                    except BTLEException as e:
                        print('        ' + str(e))

                    # Show descriptor
                    for descriptor in descriptors:
                        try:
                            print(indent + yellow('Descriptor'))
                            print(indent * 2 + 'Handle:',
                                  green('%#06x' % descriptor.handle))
                            print(indent * 2 + 'Type:',
                                  str(descriptor.uuid).replace(
                                      sig_uuid_suffix, ''),
                                  end=' ')
                            try:
                                print('(' + descriptors_spec['0x' + (
                                    "%s" %
                                    descriptor.uuid)[4:8].upper()]['Name'] +
                                      ')')
                            except KeyError:
                                print('(Unknown descriptor)')
                            print(indent * 2 + 'Value:',
                                  green(str(descriptor.read())))
                            print(indent * 2 + 'Permissions:')
                        except BTLEException as e:
                            print(indent * 2 + str(e))
                    print()
                print()

            # Set remote device untursted
            output = subprocess.check_output(' '.join(
                ['bluetoothctl', 'untrust', bdaddr]),
                                             stderr=STDOUT,
                                             timeout=60,
                                             shell=True)
            logger.info(output.decode())

            # output = subprocess.check_output(
            #     ' '.join(['sudo', 'systemctl', 'stop', 'bluetooth.service']),
            #     stderr=STDOUT, timeout=60, shell=True)

            # output = subprocess.check_output(
            #     ' '.join(['sudo', 'rm', '-rf', '/var/lib/bluetooth/' + \
            #               self.hci_bdaddr + '/' + bdaddr.upper()]),
            #     stderr=STDOUT, timeout=60, shell=True)

            # output = subprocess.check_output(
            #     ' '.join(['sudo', 'systemctl', 'start', 'bluetooth.service']),
            #     stderr=STDOUT, timeout=60, shell=True)
        finally:
            if self.agent_registered:
                self.agent_mgr_1_iface.UnregisterAgent(
                    ObjectPath(self.bluescan_agent.path))
                logger.info('Unregistered Agent object')

                mainloop.quit()
コード例 #18
0
    def scan(self, addr: str, addr_type: str) -> GattScanResult:
        logger.debug("Entered scan()")

        try:

            def run_mainloop():
                # logger.info('mainloop run\n'
                # "mainloop: {}".format(mainloop))
                mainloop.run()
                # logger.info('mainloop stop')

            mainloop_thread = threading.Thread(target=run_mainloop, args=[])
            mainloop_thread.start()

            self.result.addr = addr.upper()
            self.result.addr_type = addr_type

            if self.result.addr_type is None:
                self.result.addr_type = self.determine_addr_type()

            self.gatt_client = GattClient(self.iface)

            logger.debug("Address:      {}\n".format(self.result.addr) +
                         "Address type: {}".format(self.result.addr_type))

            try:
                self.spinner.start("Connecting...")
                self.gatt_client.connect(self.result.addr,
                                         self.result.addr_type)
            except TimeoutError:
                raise RuntimeError(
                    "Failed to connect remote device {}".format(addr))

            try:
                self.spinner.text = "Discovering all primary services..."
                services = self.gatt_client.discover_all_primary_services()
            except TimeoutError:
                self.spinner.text = "Reconnecting..."
                self.gatt_client.reconnect()

                try:
                    self.spinner.text = "Discovering all primary services..."
                    services = self.gatt_client.discover_all_primary_services()
                except TimeoutError:
                    raise RuntimeError(
                        "Can't discover primary service, the remote device may be not connectable"
                    )

            logger.debug("number of services: {}".format(len(services)))
            for service in services:
                self.result.add_service(service)
                logger.debug(
                    "Service\n" +
                    "start_handle: 0x{:04x}\n".format(service.start_handle) +
                    "end_handle:   0x{:04x}\n".format(service.end_handle) +
                    "UUID:         {}".format(service.uuid))

            self.spinner.text = "Discovering all characteristics of each service..."

            for service in services:
                try:
                    self.spinner.text = "Discovering all characteristics of service 0x{:04x}...".format(
                        service.start_handle)
                    characts = self.gatt_client.discover_all_characts_of_a_service(
                        service)
                    logger.debug("characts: {}".format(characts))

                    for charact in characts:
                        logger.debug("Characteristics\n" +
                                     "Handle:       0x{:04x}\n".format(
                                         charact.declar.handle) +
                                     "Properties:   0x{:02X}\n".format(
                                         charact.declar.value.properties) +
                                     "Value handle: 0x{:04x}\n".format(
                                         charact.declar.value.handle) +
                                     "UUID:         {}".format(
                                         charact.declar.value.uuid))
                        service.add_charact(charact)
                except TimeoutError as e:
                    # When discovering all characteristics fo a service encounters a timeout,
                    # reconnect and try once again
                    self.spinner.text = "Reconnecting..."
                    self.gatt_client.reconnect()

                    try:
                        characts = self.gatt_client.discover_all_characts_of_a_service(
                            service)
                        for charact in characts:
                            service.add_charact(charact)
                    except TimeoutError as e:
                        logger.error(
                            "scan() \n" + "{}\n".format(e.__class__.__name__) +
                            "Discover all characteristics of a service (start 0x{:04x} - end 0x{:04x}"
                            .format(service.start_handle, service.end_handle))

            # 这里如果不重连,wireshark 会显示 server 返回的
            # 第一个 ATT_READ_RSP PDU 为 malformed packet。
            # 但是本身并不是 malformed packet,不知道为什么。
            self.spinner.text = "Reconnecting..."
            self.gatt_client.reconnect()

            self.spinner.text = "Reading value of each characteristic..."

            for service in services:
                for charact in service.get_characts():
                    if CharactProperties.READ.name in charact.declar.get_property_names(
                    ):
                        try:
                            self.spinner.text = "Reading value of a characteristic, value handle = 0x{:04x}...".format(
                                charact.declar.value.handle)
                            value = self.gatt_client.read_charact_value(
                                charact)
                            charact.set_value_declar(
                                CharactValueDeclar(charact.declar.value.handle,
                                                   charact.declar.value.uuid,
                                                   value))
                            # logger.info("Characteristics Value")
                            # print("Handle: 0x{:04x}".format(charact.value_declar.handle))
                            # print("Type:   {}".format(charact.value_declar.type))
                            # print("Value:  {}".format(charact.value_declar.value))
                        except TimeoutError:
                            # When reading the characteristic value encounters a timeout,
                            # reconnect and try to read once again
                            self.spinner.text = "Reconnecting..."
                            self.gatt_client.reconnect()

                            try:
                                value = self.gatt_client.read_charact_value(
                                    charact)
                                charact.set_value_declar(
                                    CharactValueDeclar(
                                        charact.declar.value.handle,
                                        charact.declar.value.uuid, value))
                            except TimeoutError:
                                value_declar = CharactValueDeclar(
                                    charact.declar.value.handle,
                                    charact.declar.value.uuid, None)
                                value_declar.set_read_error(
                                    ReadCharactValueError("Read Timeout"))
                                charact.set_value_declar(value_declar)
                            except ReadCharactValueError as e:
                                value_declar = CharactValueDeclar(
                                    charact.declar.value.handle,
                                    charact.declar.value.uuid, None)
                                value_declar.set_read_error(e)
                                charact.set_value_declar(value_declar)

                        except ReadCharactValueError as e:
                            value_declar = CharactValueDeclar(
                                charact.declar.value.handle,
                                charact.declar.value.uuid, None)
                            value_declar.set_read_error(e)
                            charact.set_value_declar(value_declar)

            self.spinner.text = "Discovering descriptors of each characteristic..."

            for service in services:
                characts = service.get_characts()
                if len(characts) == 0:
                    continue

                for idx in range(0, len(characts) - 1):
                    start_handle = characts[idx].declar.value.handle + 1
                    end_handle = characts[idx + 1].declar.value.handle - 1
                    if end_handle < start_handle:
                        continue

                    try:
                        self.spinner.text = "Discovering all descriptors of characteristic 0x{:04x}...".format(
                            characts[idx].declar.handle)
                        descriptors = self.gatt_client.discover_all_charact_descriptors(
                            start_handle, end_handle)
                        logger.debug(
                            "Number of discovered descriptors: {}".format(
                                len(descriptors)))
                        for descriptor in descriptors:
                            characts[idx].add_descriptor_declar(descriptor)
                    except TimeoutError:
                        self.spinner.text = "Reconnecting..."
                        self.gatt_client.reconnect()

                        try:
                            descriptors = self.gatt_client.discover_all_charact_descriptors(
                                start_handle, end_handle)
                            for descriptor in descriptors:
                                characts[idx].add_descriptor_declar(descriptor)
                        except TimeoutError:
                            pass

                # Find descriptor of the last charactertisc in current service.
                start_handle = characts[-1].declar.value.handle + 1
                end_handle = service.end_handle
                if end_handle < start_handle:
                    continue

                try:
                    self.spinner.text = "Discovering all descriptors of characteristic 0x{:04x}...".format(
                        characts[-1].declar.handle)
                    descriptors = self.gatt_client.discover_all_charact_descriptors(
                        start_handle, end_handle)
                    for descriptor in descriptors:
                        characts[-1].add_descriptor_declar(descriptor)
                except TimeoutError:
                    self.spinner.text = "Reconnecting..."
                    self.gatt_client.reconnect()

                    try:
                        self.spinner.text = "Discovering all descriptors of characteristic 0x{:04x}...".format(
                            characts[-1].declar.handle)
                        descriptors = self.gatt_client.discover_all_charact_descriptors(
                            start_handle, end_handle)
                        for descriptor in descriptors:
                            characts[-1].add_descriptor_declar(descriptor)
                    except TimeoutError:
                        pass

            self.spinner.text = "Reading value of each descriptor..."

            for service in services:
                for characts in service.get_characts():
                    for descriptor in characts.get_descriptors():
                        try:
                            self.spinner.text = "Reading value of the descriptor 0x{:04x}... ".format(
                                descriptor.handle)
                            value = self.gatt_client.read_charact_descriptor(
                                descriptor.handle)
                            descriptor.set_value(value)
                        except TimeoutError:
                            # When reading the descriptor encounters a timeout,
                            # reconnect and try to read once again
                            self.spinner.text = "Reconnecting..."
                            self.gatt_client.reconnect()

                            try:
                                value = self.gatt_client.read_charact_descriptor(
                                    descriptor.handle)
                                descriptor.set_value(value)
                            except TimeoutError:
                                descriptor.set_read_error(
                                    ReadCharactDescriptorError("Read Timeout"))
                                descriptor.set_value(None)
                            except ReadCharactDescriptorError as e:
                                descriptor.set_read_error(e)
                                descriptor.set_value(None)
                        except ReadCharactDescriptorError as e:
                            descriptor.set_read_error(e)
                            descriptor.set_value(None)

            # secondary_service_groups = req_groups(addr, addr_type, GattAttrTypes.SECONDARY_SERVICE)
            # include_groups = req_groups(addr, addr_type, GattAttrTypes.INCLUDE)

            # print(secondary_service_groups)
            # print(include_groups)

        except RuntimeError as e:
            logger.error("scan()\n" + "{}\n".format(e.__class__.__name__) +
                         "{}".format(e))
        finally:
            self.spinner.stop()

            if self.gatt_client is not None:
                self.gatt_client.close()

            if self.agent_registered:
                self.agent_mgr_1_iface.UnregisterAgent(
                    ObjectPath(self.bluescan_agent.path))
                logger.debug("Unregistered agent object")

                mainloop.quit()
                self.agent_registered = False
            try:
                # Reset and clean bluetooth service
                output = subprocess.check_output(
                    ' '.join(['bluetoothctl', 'untrust', addr]),
                    stderr=STDOUT,
                    timeout=60,
                    shell=True)  # 这个 untrust 用于解决本地自动重连被扫描设备的问题
                logger.debug(output.decode())
            except subprocess.CalledProcessError:
                pass

            output = subprocess.check_output(' '.join(
                ['sudo', 'systemctl', 'stop', 'bluetooth.service']),
                                             stderr=STDOUT,
                                             timeout=60,
                                             shell=True)

            output = subprocess.check_output(
                ' '.join(['sudo', 'rm', '-rf', '/var/lib/bluetooth/' + \
                        self.hci_bdaddr + '/' + addr.upper()]),
                stderr=STDOUT, timeout=60, shell=True)

            output = subprocess.check_output(' '.join(
                ['sudo', 'systemctl', 'start', 'bluetooth.service']),
                                             stderr=STDOUT,
                                             timeout=60,
                                             shell=True)

        return self.result