def receive_data(self, sender, data): logger.debug( f"State: {self.state}, received from '{sender}': {hexlify(bytes(data))}" ) packet = Packet.from_bytes(data) logger.debug(f"Parsed: {packet}") if self.state == BandState.RequestedLinkParams: if packet.service_id != DeviceConfig.id and packet.command_id != DeviceConfig.LinkParams.id: raise RuntimeError("unexpected packet") self.parse_link_params(packet.command) elif self.state == BandState.RequestedAuthentication: if packet.service_id != DeviceConfig.id and packet.command_id != DeviceConfig.Auth.id: raise RuntimeError("unexpected packet") self.parse_authentication(packet.command) elif self.state == BandState.RequestedBondParams: if packet.service_id != DeviceConfig.id and packet.command_id != DeviceConfig.BondParams.id: raise RuntimeError("unexpected packet") self.parse_bond_params(packet.command) elif self.state == BandState.RequestedBond: if packet.service_id != DeviceConfig.id and packet.command_id != DeviceConfig.Bond.id: raise RuntimeError("unexpected packet") self.parse_bond(packet.command) self._event.set()
def _receive_data(self, sender: str, data: bytes): logger.debug(f"Current state: {self.state}, received from '{sender}': {hexlify(bytes(data))}") self._packet = Packet.from_bytes(data) logger.debug(f"Parsed response packet: {self._packet}") assert self.state.name.startswith("Requested"), "unexpected packet" self.loop.call_soon_threadsafe(self._event.set())
def request_set_time(self): zone_hours, zone_minutes = divmod(time.timezone / -3600, 1) zone_minutes *= 60 offset = encode_int(int(zone_hours), length=1) + encode_int( int(zone_minutes), length=1) plain_command = Command(tlvs=[ TLV(tag=DeviceConfig.SetTime.Tags.Timestamp, value=encode_int(int(time.time()), length=4)), TLV(tag=DeviceConfig.SetTime.Tags.ZoneOffset, value=offset), ]) self.encryption_counter += 1 # TODO: overflow iv = generate_nonce()[:-4] + encode_int(self.encryption_counter, length=4) packet = Packet( service_id=DeviceConfig.id, command_id=DeviceConfig.SetTime.id, command=Command(tlvs=[ TLV(tag=124, value=b"\x01"), TLV(tag=125, value=iv), TLV(tag=126, value=encrypt(bytes(plain_command), self.secret, iv)), ]), ) return packet
def request_link_params(self) -> Packet: self.state = BandState.RequestedLinkParams return Packet(service_id=DeviceConfig.id, command_id=DeviceConfig.LinkParams.id, command=Command(tlvs=[ TLV(DeviceConfig.LinkParams.Tags.ProtocolVersion), TLV(DeviceConfig.LinkParams.Tags.MaxFrameSize), TLV(DeviceConfig.LinkParams.Tags.MaxLinkSize), TLV(DeviceConfig.LinkParams.Tags.ConnectionInterval), ]))
def request_authentication(self): packet = Packet(service_id=DeviceConfig.id, command_id=DeviceConfig.Auth.id, command=Command(tlvs=[ TLV(tag=DeviceConfig.Auth.Tags.Challenge, value=digest_challenge(self.server_nonce, self.client_nonce)), TLV(tag=DeviceConfig.Auth.Tags.Nonce, value=(encode_int(self.auth_version) + self.client_nonce)), ])) self.state = BandState.RequestedAuthentication return packet
def request_bond_params(self): packet = Packet( service_id=DeviceConfig.id, command_id=DeviceConfig.BondParams.id, command=Command(tlvs=[ TLV(tag=DeviceConfig.BondParams.Tags.Status), TLV(tag=DeviceConfig.BondParams.Tags.ClientSerial, value=self.client_serial), TLV(tag=DeviceConfig.BondParams.Tags.BTVersion, value=b"\x02"), TLV(tag=DeviceConfig.BondParams.Tags.MaxFrameSize), TLV(tag=DeviceConfig.BondParams.Tags.ClientMacAddress, value=self.client_mac.encode()), TLV(tag=DeviceConfig.BondParams.Tags.EncryptionCounter), ])) self.state = BandState.RequestedBondParams return packet
def request_bond(self): # TODO: extract self.encryption_counter += 1 iv = generate_nonce()[:-4] + encode_int(self.encryption_counter, length=4) packet = Packet(service_id=DeviceConfig.id, command_id=DeviceConfig.Bond.id, command=Command(tlvs=[ TLV(tag=1), TLV(tag=3, value=b"\x00"), TLV(tag=5, value=self.client_serial), TLV(tag=6, value=create_bonding_key( self.device_mac, self.secret, iv)), TLV(tag=7, value=iv), ])) self.state = BandState.RequestedBond return packet