def list_pairings(self): """ This method returns all pairings of a HomeKit accessory. This always includes the local controller and can only be done by an admin controller. The keys in the resulting dicts are: * pairingId: the pairing id of the controller * publicKey: the ED25519 long-term public key of the controller * permissions: bit value for the permissions * controllerType: either admin or regular :return: a list of dicts :raises: UnknownError: if it receives unexpected data :raises: UnpairedError: if the polled accessory is not paired """ if not self.session: self.session = IpSession(self.pairing_data) request_tlv = TLV.encode_list([(TLV.kTLVType_State, TLV.M1), (TLV.kTLVType_Method, TLV.ListPairings) ]) try: response = self.session.sec_http.post('/pairings', request_tlv.decode()) data = response.read() except (AccessoryDisconnectedError, EncryptionError): self.session.close() self.session = None raise data = TLV.decode_bytes(data) if not (data[0][0] == TLV.kTLVType_State and data[0][1] == TLV.M2): raise UnknownError('unexpected data received: ' + str(data)) elif data[1][0] == TLV.kTLVType_Error and data[1][ 1] == TLV.kTLVError_Authentication: raise UnpairedError('Must be paired') else: tmp = [] r = {} for d in data[1:]: if d[0] == TLV.kTLVType_Identifier: r = {} tmp.append(r) r['pairingId'] = d[1].decode() if d[0] == TLV.kTLVType_PublicKey: r['publicKey'] = d[1].hex() if d[0] == TLV.kTLVType_Permissions: controller_type = 'regular' if d[1] == b'\x01': controller_type = 'admin' r['permissions'] = int.from_bytes(d[1], byteorder='little') r['controllerType'] = controller_type return tmp
def list_pairings(self): """ This method returns all pairings of a HomeKit accessory. This always includes the local controller and can only be done by an admin controller. The keys in the resulting dicts are: * pairingId: the pairing id of the controller * publicKey: the ED25519 long-term public key of the controller * permissions: bit value for the permissions * controllerType: either admin or regular :return: a list of dicts :raises: UnknownError: if it receives unexpected data :raises: UnpairedError: if the polled accessory is not paired """ if not self.session: self.session = IpSession(self.pairing_data) request_tlv = tlv8.encode([ tlv8.Entry(TlvTypes.State, States.M1), tlv8.Entry(TlvTypes.Method, Methods.ListPairings) ]) try: response = self.session.sec_http.post('/pairings', request_tlv) data = response.read() except (AccessoryDisconnectedError, EncryptionError): self.session.close() self.session = None raise data = tlv8.decode( data, { TlvTypes.State: tlv8.DataType.INTEGER, TlvTypes.Error: tlv8.DataType.INTEGER, TlvTypes.Identifier: tlv8.DataType.BYTES, TlvTypes.PublicKey: tlv8.DataType.BYTES, TlvTypes.Permissions: tlv8.DataType.BYTES }) error = data.first_by_id(TlvTypes.Error) if not (data.first_by_id(TlvTypes.State).data == States.M2): raise UnknownError('unexpected data received: ' + tlv8.format_string(data)) elif error and error.data == Errors.Authentication: raise UnpairedError('Must be paired') else: tmp = [] r = {} for d in data[1:]: if d.type_id == TlvTypes.Identifier: r = {} tmp.append(r) r['pairingId'] = d.data.decode() if d.type_id == TlvTypes.PublicKey: r['publicKey'] = d.data.hex() if d.type_id == TlvTypes.Permissions: controller_type = 'regular' if d.data == b'\x01': controller_type = 'admin' r['permissions'] = int.from_bytes(d.data, byteorder='little') r['controllerType'] = controller_type tmp.sort(key=lambda x: x['pairingId']) return tmp