def response_roller_updated(self, message): """Receive change of roller information.""" ptr = 2 # sequence? ptr += 4 ptr += 2 # unknown field ptr += 2 # unknown field room_id, ptr = utils.unpack_bytes(message, ptr) ptr += 4 # unknown field roller_type, ptr = utils.unpack_int(message, ptr, 1) ptr += 2 # unknown field roller_name, ptr = utils.unpack_string(message, ptr) ptr += 10 # unknown field roller_id, ptr = utils.unpack_int(message, ptr, 6) ptr += 5 # unknown field ptr += 5 # unknown field roller_percent, ptr = utils.unpack_int(message, ptr, 1) roller_flags, ptr = utils.unpack_int(message, ptr, 1) ptr += 2 # checksum if roller_id not in self.rollers: self.rollers[roller_id] = elements.Roller(self, roller_id) roller = self.rollers[roller_id] roller.name = roller_name # doesn't seem to come through in update # roller.serial = roller_serial roller.room_id = room_id roller.type = roller_type if room_id in self.rooms: roller.room = self.rooms[room_id] else: roller.room = None roller.closed_percent = roller_percent roller.flags = roller_flags roller.notify_callback() self.notify_callback(const.UpdateType.rollers)
def response_rollerhealth(self, message): """Receive change of roller health information.""" ptr = 12 roller_id, ptr = utils.unpack_int(message, ptr, 6) # letter A and then 4 bytes unknown, ptr = utils.unpack_bytes(message, ptr, 5) _LOGGER.debug(f"{binascii.hexlify(unknown)}") # letter B and then 4 bytes unknown, ptr = utils.unpack_bytes(message, ptr, 5) _LOGGER.debug(f"{binascii.hexlify(unknown)}") # letter C and then 4 bytes unknown, ptr = utils.unpack_bytes(message, ptr, 5) _LOGGER.debug(f"{binascii.hexlify(unknown)}") # unknown unknown, ptr = utils.unpack_bytes(message, ptr, 3) _LOGGER.debug(f"{binascii.hexlify(unknown)}") # battery level charge, ptr = utils.unpack_int(message, ptr, 1) charge_fraction, ptr = utils.unpack_int(message, ptr, 1) charge += charge_fraction / 256.0 roller_battery = round( min(100, max(0, 100.0 * (charge - 9.45) / (12.375 - 9.45)))) _LOGGER.debug(f"Battery: {charge} {roller_battery}") # unknown unknown, ptr = utils.unpack_bytes(message, ptr, 8) _LOGGER.debug(f"{binascii.hexlify(unknown)}") ptr += 2 # checksum if roller_id in self.rollers: self.rollers[roller_id].battery = roller_battery self.rollers[roller_id].health_updated() self.rollers[roller_id].notify_callback() if self.health_lock.locked(): self.health_lock.release()
def response_position(self, message): """Receive change of roller position information.""" ptr = 12 roller_id, ptr = utils.unpack_int(message, ptr, 6) ptr += 10 roller_percent, ptr = utils.unpack_int(message, ptr, 1) roller_flags, ptr = utils.unpack_int(message, ptr, 1) if roller_id in self.rollers: self.rollers[roller_id].closed_percent = roller_percent self.rollers[roller_id].flags = roller_flags self.rollers[roller_id].notify_callback()
def rec_message(self, message): """Receive and decode a message from the hub.""" if message: if message[0] != 6: _LOGGER.error(f"{self.host}: First message byte not 0x06") raise errors.InvalidResponseException if message[1:(1 + len(self.topic))] != self.topic: _LOGGER.error(f"{self.host}: Received invalid topic: " f"{message[1 : (1 + len(self.topic))]}, " f"expected: {self.topic}") raise errors.InvalidResponseException ptr = 1 + len(self.topic) _, ptr = utils.unpack_int(message, ptr, 2) mtype = message[ptr:(ptr + 2)] ptr = ptr + 2 if mtype in self.msgmap: _LOGGER.info(f"{self.host}: Parsing {self.msgmap[mtype].name}") self.msgmap[mtype].execute(self, message[ptr:]) else: _LOGGER.warning( f"{self.host}: Unable to parse message %s message %s", binascii.hexlify(mtype), binascii.hexlify(message), )
def response_roomlist(self, message): """Receive room list.""" ptr = 12 room_count, ptr = utils.unpack_int(message, ptr, 1) for _ in range(room_count): _, ptr = utils.unpack_bytes(message, ptr, 2) room_id, ptr = utils.unpack_bytes(message, ptr) _, ptr = utils.unpack_bytes(message, ptr, 4) icon, ptr = utils.unpack_int(message, ptr, 1) _, ptr = utils.unpack_bytes(message, ptr, 2) room_name, ptr = utils.unpack_string(message, ptr) if room_id not in self.rooms: self.rooms[room_id] = elements.Room(self, room_id) self.rooms[room_id].icon = icon self.rooms[room_id].name = room_name self.notify_callback(const.UpdateType.rooms)
def response_parse(self, response): """Decode response.""" while response: ptr = 0 header, ptr = utils.unpack_bytes(response, ptr, 4) if header != bytes.fromhex("00000003"): _LOGGER.warning( f"{self.host}: Unknown response: {binascii.hexlify(response[0:4])}" ) raise errors.InvalidResponseException try: msg_len, ptr = utils.unpack_int(response, ptr, 1) msg_blocks = 1 if msg_len > 127: msg_blocks, ptr = utils.unpack_int(response, ptr, 1) msg_end = ptr + msg_len + 128 * (msg_blocks - 1) if msg_end > len(response): raise errors.InvalidResponseException _, ptr = utils.unpack_bytes(response, ptr, 2) mtype, ptr = utils.unpack_int(response, ptr, 1) message = response[ptr:msg_end] response = response[msg_end:] if mtype in Hub.respmap: _LOGGER.debug( f"{self.host}: Received response: {mtype} " f"{Hub.respmap[mtype].name} content: {message}") Hub.respmap[mtype].execute(self, message) else: _LOGGER.warning( f"{self.host}: Received unknown response type: " f"{mtype}, " f"trying to decode anyway. Message: {binascii.hexlify(message)}" ) self.rec_message(message) except Exception: logging.exception( f"{self.host}: Exception raised when parsing response: " f"{binascii.hexlify(response)}") raise errors.InvalidResponseException
def response_timerlist(self, message): """Receive timer list.""" ptr = 0 _, ptr = utils.unpack_bytes(message, ptr, 12) timer_count, ptr = utils.unpack_int(message, ptr, 1) for _ in range(timer_count): _, ptr = utils.unpack_bytes(message, ptr, 2) timer_id, ptr = utils.unpack_bytes(message, ptr) _, ptr = utils.unpack_bytes(message, ptr, 4) icon, ptr = utils.unpack_int(message, ptr, 1) _, ptr = utils.unpack_bytes(message, ptr, 2) timer_name, ptr = utils.unpack_string(message, ptr) _, ptr = utils.unpack_bytes(message, ptr, 4) # ' !\x02\x01\x00' state, ptr = utils.unpack_int(message, ptr, 1) _, ptr = utils.unpack_bytes(message, ptr, 4) # ' ;\x02\x01\x00' hour, ptr = utils.unpack_int(message, ptr, 1) _, ptr = utils.unpack_bytes(message, ptr, 4) # ' <\x02\x01\x00' minute, ptr = utils.unpack_int(message, ptr, 1) _, ptr = utils.unpack_bytes(message, ptr, 4) # ' "\x02\x04\x00' days, ptr = utils.unpack_int(message, ptr, 1) _, ptr = utils.unpack_bytes(message, ptr, 4) # '\x00\x00\x00 =' _, ptr = utils.unpack_bytes(message, ptr, 2) # '\x02\x01' timer_type, ptr = utils.unpack_bytes(message, ptr, 4) entity = None if timer_type == b"\x00\x01\x03\x01": # Device Timer _, ptr = utils.unpack_bytes(message, ptr, 8) percent, ptr = utils.unpack_int(message, ptr, 1) _, ptr = utils.unpack_bytes(message, ptr, 5) roller_id, ptr = utils.unpack_int(message, ptr, 6) if roller_id in self.rollers: entity = self.rollers[roller_id] elif timer_type == b"\x00\x00\x10\x02": # Scene Timer scene_id, ptr = utils.unpack_bytes(message, ptr) if scene_id in self.scenes: entity = self.scenes[scene_id] else: _LOGGER.error(f"{self.host}: Unexpected timer type received: " f"{binascii.hexlify(timer_type)}") return if timer_id not in self.timers: self.timers[timer_id] = elements.Timer(self, timer_id) self.timers[timer_id].icon = icon self.timers[timer_id].name = timer_name self.timers[timer_id].state = state self.timers[timer_id].hour = hour self.timers[timer_id].minute = minute self.timers[timer_id].days = days self.timers[timer_id].entity = entity _, ptr = utils.unpack_bytes(message, ptr, 2) self.notify_callback(const.UpdateType.timers)
def response_rollerlist(self, message): """Receive roller blind list.""" ptr = 2 # sequence? ptr += 10 roller_count, ptr = utils.unpack_int(message, ptr, 1) for _ in range(roller_count): start = ptr ptr += 4 # unknown field roller_id, ptr = utils.unpack_int(message, ptr, 6) ptr += 2 # unknown field room_id, ptr = utils.unpack_bytes(message, ptr) ptr += 4 # unknown field roller_type, ptr = utils.unpack_int(message, ptr, 1) ptr += 2 # unknown field roller_name, ptr = utils.unpack_string(message, ptr) ptr += 8 # unknown field roller_serial, ptr = utils.unpack_string(message, ptr) ptr += 5 # unknown field ptr += 5 # unknown field roller_percent, ptr = utils.unpack_int(message, ptr, 1) roller_flags, ptr = utils.unpack_int(message, ptr, 1) _LOGGER.debug(f"{binascii.hexlify(message[start:ptr])}") if roller_id not in self.rollers: self.rollers[roller_id] = elements.Roller(self, roller_id) roller = self.rollers[roller_id] roller.name = roller_name roller.serial = roller_serial roller.room_id = room_id roller.type = roller_type if room_id in self.rooms: roller.room = self.rooms[room_id] else: roller.room = None roller.closed_percent = roller_percent roller.flags = roller_flags roller.notify_callback() self.notify_callback(const.UpdateType.rollers)
def response_scenelist(self, message): """Receive scene list.""" ptr = 0 _, ptr = utils.unpack_bytes(message, ptr, 12) scene_count, ptr = utils.unpack_int(message, ptr, 1) for _ in range(scene_count): _, ptr = utils.unpack_bytes(message, ptr, 2) scene_id, ptr = utils.unpack_bytes(message, ptr) _, ptr = utils.unpack_bytes(message, ptr, 4) icon, ptr = utils.unpack_int(message, ptr, 1) _, ptr = utils.unpack_bytes(message, ptr, 2) scene_name, ptr = utils.unpack_string(message, ptr) _, ptr = utils.unpack_bytes(message, ptr, 5) # Not sure what is being read next but it seems to be variable while message[ptr:ptr + 2] == b"R\x02": _, ptr = utils.unpack_bytes(message, ptr, 2) _, ptr = utils.unpack_bytes(message, ptr) if scene_id not in self.scenes: self.scenes[scene_id] = elements.Scene(self, scene_id) self.scenes[scene_id].icon = icon self.scenes[scene_id].name = scene_name _, ptr = utils.unpack_bytes(message, ptr, 2) self.notify_callback(const.UpdateType.scenes)