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
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
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