Example #1
0
 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)
Example #2
0
 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()
Example #3
0
 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()
Example #4
0
    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),
                )
Example #5
0
 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)
Example #6
0
    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
Example #7
0
    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)
Example #8
0
    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)
Example #9
0
    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)