예제 #1
0
def find_characteristic_by_uuid(device, service_uuid, char_uuid):
    """
    # TODO document me

    :param device:
    :param service_uuid:
    :param char_uuid:
    :return:
    """
    service_found = None
    logger.debug('services: %s', device.services)
    for possible_service in device.services:
        if ServicesTypes.get_short(
                service_uuid.upper()) == ServicesTypes.get_short(
                    possible_service.uuid.upper()):
            service_found = possible_service
            break
    logger.debug('searched service: %s', service_found)

    if not service_found:
        logging.error('searched service not found.')
        return None, None

    result_char = None
    result_char_id = None
    for characteristic in service_found.characteristics:
        logger.debug(
            'char: %s %s', characteristic.uuid,
            CharacteristicsTypes.get_short(characteristic.uuid.upper()))
        if CharacteristicsTypes.get_short(
                char_uuid.upper()) == CharacteristicsTypes.get_short(
                    characteristic.uuid.upper()):
            result_char = characteristic
            for descriptor in characteristic.descriptors:
                value = descriptor.read_value()
                if descriptor.uuid == CharacteristicInstanceID:
                    cid = int.from_bytes(value, byteorder='little')
                    result_char_id = cid

    if not result_char:
        logging.error('searched char not found.')
        return None, None

    logger.debug('searched char: %s %s', result_char, result_char_id)
    return result_char, result_char_id
예제 #2
0
def read_characteristics(device):
    # TODO document me
    # FIXME: This only works on non secure sessions
    logger.debug('resolved %d services', len(device.services))

    a_data = {'aid': 1, 'services': []}

    resolved_data = {
        'data': [a_data],
    }

    for service in device.services:
        logger.debug('found service with UUID %s (%s)', service.uuid,
                     ServicesTypes.get_short(service.uuid.upper()))

        s_data = {'characteristics': [], 'iid': None}

        for characteristic in service.characteristics:
            logger.debug(
                '\tfound characteristic with UUID %s (%s)',
                characteristic.uuid,
                CharacteristicsTypes.get_short(characteristic.uuid.upper()))

            if characteristic.uuid.upper(
            ) == CharacteristicsTypes.SERVICE_INSTANCE_ID:
                sid = int.from_bytes(characteristic.read_value(),
                                     byteorder='little')
                logger.debug('\t\tread service id %d', sid)
                s_data['iid'] = sid
            else:
                c_data = {
                    'iid': None,
                    'type': characteristic.uuid.upper(),
                    'perms': []
                }
                iid = None
                for descriptor in characteristic.descriptors:
                    value = descriptor.read_value()
                    if descriptor.uuid == CharacteristicInstanceID:
                        iid = int.from_bytes(value, byteorder='little')
                        logger.debug('\t\tread characteristic id %d', iid)
                        c_data['iid'] = iid
                    else:
                        # print('\t\t', 'D', descriptor.uuid, value)
                        pass

                if iid:
                    v = iid.to_bytes(length=2, byteorder='little')
                    tid = random.randrange(0, 255)
                    characteristic.write_value(
                        [0x00, HapBleOpCodes.CHAR_SIG_READ, tid, v[0], v[1]])
                    d = parse_sig_read_response(characteristic.read_value(),
                                                tid)
                    for k in d:
                        if k == 'service_type':
                            s_data['type'] = d[k].upper()
                        elif k == 'sid':
                            s_data['iid'] = d[k]
                        else:
                            c_data[k] = d[k]

                if c_data['iid']:
                    s_data['characteristics'].append(c_data)

        if s_data['iid']:
            a_data['services'].append(s_data)

    logging.debug('data: %s', resolved_data)

    return resolved_data
예제 #3
0
    def __init__(self, pairing_data, adapter):
        self.adapter = adapter
        self.pairing_data = pairing_data
        self.c2a_counter = 0
        self.a2c_counter = 0
        self.c2a_key = None
        self.a2c_key = None
        self.device = None
        mac_address = self.pairing_data['AccessoryMAC']

        manager = DeviceManager(self.adapter)

        self.device = manager.make_device(mac_address)
        logger.debug('connecting to device')
        self.device.connect()
        logger.debug('connected to device')

        uuid_map = {}
        for s in self.device.services:
            for c in s.characteristics:
                uuid_map[(s.uuid.upper(), c.uuid.upper())] = c

        self.uuid_map = {}
        self.iid_map = {}
        self.short_map = {}
        for a in pairing_data['accessories']:
            for s in a['services']:
                s_short = None
                if s['type'].endswith(ServicesTypes.baseUUID):
                    s_short = s['type'].split('-', 1)[0].lstrip('0')

                for c in s['characteristics']:
                    char = uuid_map.get((s['type'], c['type']), None)
                    if not char:
                        continue
                    self.iid_map[c['iid']] = (char, c)
                    self.uuid_map[(s['type'], c['type'])] = (char, c)

                    if s_short and c['type'].endswith(
                            CharacteristicsTypes.baseUUID):
                        c_short = c['type'].split('-', 1)[0].lstrip('0')
                        self.short_map[(s_short, c_short)] = (char, c)

                    service_type_short = ServicesTypes.get_short(s['type'])
                    characteristic_type_short = CharacteristicsTypes.get_short(
                        c['type'])
                    self.short_map[service_type_short,
                                   characteristic_type_short] = (char, c)

        pair_verify_char, pair_verify_char_info = self.short_map.get(
            (ServicesTypes.PAIRING_SERVICE, CharacteristicsTypes.PAIR_VERIFY),
            (None, None))

        if not pair_verify_char:
            print('verify characteristic not found')
            # TODO Have exception here
            sys.exit(-1)

        write_fun = create_ble_pair_setup_write(pair_verify_char,
                                                pair_verify_char_info['iid'])
        state_machine = get_session_keys(self.pairing_data)

        request, expected = state_machine.send(None)
        while True:
            try:
                response = write_fun(request, expected)
                request, expected = state_machine.send(response)
            except StopIteration as result:
                self.c2a_key, self.a2c_key = result.value
                break

        logger.debug('pair_verified, keys: \n\t\tc2a: %s\n\t\ta2c: %s',
                     self.c2a_key.hex(), self.a2c_key.hex())

        self.c2a_counter = 0
        self.a2c_counter = 0