def process_enocean_fsb61_message(self, message: EnoceanMessage): packet = message.payload # type: RadioPacket try: packet.parse() status = Fsb61StateConverter.extract_packet(packet) except Exception as ex: self._logger.exception(ex) EnoceanTools.log_pickled_enocean_packet( self._logger.error, packet, "process_enocean_fsb61_message - {}".format(str(ex))) return if status.type == Fsb61StateType.UNKNOWN: EnoceanTools.log_pickled_enocean_packet( self._logger.warning, packet, "process_enocean_fsb61_message - unknown packet type") return self._logger.debug("process_enocean_fsb61_message: %s", status) # # DEBUG # EnoceanTools.log_pickled_enocean_packet(self._logger.debug, packet, 'process_enocean_fsb61_message') self._update_position(status) self._publish_actor_result() self._process_device_command2(status) # trigger queued commands # prevent offline message self._reset_offline_refresh_timer() self._last_status_request_time = self._now()
def process_enocean_message(self, message: EnoceanMessage): packet = message.payload # type: RadioPacket if packet.packet_type != PACKET.RADIO: self._logger.debug("skipped packet with packet_type=%s", EnoceanTools.packet_type_to_string(packet.rorg)) return if packet.rorg != self._eep.rorg: self._logger.debug("skipped packet with rorg=%s", hex(packet.rorg)) return self._reset_offline_refresh_timer() data = EnoceanTools.extract_packet_props(packet, self._eep) self._logger.debug("proceed_enocean - got: %s", data) try: value = self.extract_handle_state(data.get("WIN")) except DeviceException as ex: self._logger.exception(ex) value = HandleValue.ERROR if value == HandleValue.ERROR and self._logger.isEnabledFor( logging.DEBUG): # write ascii representation to reproduce in tests self._logger.debug("proceed_enocean - pickled error packet:\n%s", PickleTools.pickle_packet(packet)) since = self._determine_and_store_since(value) message = self._create_message(value, since) self._publish_mqtt(message)
def process_enocean_message(self, message: EnoceanMessage): packet = message.payload # type: RadioPacket if packet.packet_type != PACKET.RADIO: self._logger.debug("skipped packet with packet_type=%s", EnoceanTools.packet_type_to_string(packet.rorg)) return if packet.rorg != self._eep.rorg: self._logger.debug("skipped packet with rorg=%s", hex(packet.rorg)) return data = EnoceanTools.extract_packet_props(packet, self._eep) self._logger.debug("proceed_enocean - got: %s", data) notification = self.extract_notification(data) if notification.channel != self._actor_channel: self._logger.debug("skip channel (%s, awaiting=%s)", notification.channel, self._actor_channel) return if notification.switch_state == SwitchStatus.ERROR and self._logger.isEnabledFor( logging.DEBUG): # write ascii representation to reproduce in tests self._logger.debug( "process_enocean_message - pickled error packet:\n%s", PickleTools.pickle_packet(packet)) message = self._create_json_message(notification.switch_state, None) self._publish_mqtt(message)
def test_extract_release(self): packet = PickleTools.unpickle_packet(PACKET_RELEASE) device = _MockDevice() extracted = EnoceanTools.extract_packet_props(packet, device._eep) action = RockerAction(press=RockerPress.RELEASE) expected = RockerSwitchTools.create_props(action) self.assertEqual(extracted, expected)
def process_enocean_message(self, message: EnoceanMessage): packet = message.payload if packet.sender_int in self._enocean_ids_skip: return packet_type = EnoceanTools.packet_type_to_string(packet.packet_type) if self._dump_packet and self._logger.isEnabledFor(logging.INFO): self._logger.info( "proceed_enocean - packet: %s; sender: %s; dest: %s; RORG: %s; dump:\n%s", packet_type, packet.sender_hex, packet.destination_hex, enocean_utils.to_hex_string(packet.rorg), PickleTools.pickle_packet(packet)) packet.parse() if packet.contains_eep: self._logger.debug( 'learn received, EEP detected, RORG: 0x%02X, FUNC: 0x%02X, TYPE: 0x%02X, Manufacturer: 0x%02X' % (packet.rorg, packet.rorg_func, packet.rorg_type, packet.rorg_manufacturer)) # noqa: E501 else: self._logger.info( "proceed_enocean - packet: %s; sender: %s; dest: %s; RORG: %s", packet_type, packet.destination_hex, enocean_utils.to_hex_string(packet.rorg), packet.sender_hex)
def test_ft55(self): packet = PickleTools.unpickle_packet(PACKET_FT55_21L) # f6-02-02 eep = Eep(rorg=0xf6, func=0x02, type=0x02) data = EnoceanTools.extract_props(packet, eep) self.assertTrue(data)
def create_packet(cls, eep: Eep, destination=None, sender=None, learn=False, **kwargs): destination_id = destination or 0xffffffff if type(destination_id) == int: destination_id = EnoceanTools.int_to_byte_list(destination_id) sender_id = sender or cls._sender_id if type(sender_id) == int: sender_id = EnoceanTools.int_to_byte_list(sender_id) return RadioPacket.create( eep.rorg, eep.func, eep.type, direction=eep.direction, command=eep.command, destination=destination_id, sender=sender_id, learn=learn, **kwargs )
def test_extract_1_off(self): packet = PickleTools.unpickle_packet(_PACKET_1_OFF) device = _MockDevice() data = EnoceanTools.extract_packet_props(packet, _MockDevice.DEFAULT_EEP) notification = device.extract_notification(data) self.assertEqual(notification.channel, 1) self.assertEqual(notification.switch_state, SwitchStatus.OFF)
def extract_props(cls, packet: RadioPacket) -> Dict: eep = cls.DEFAULT_EEP if packet.packet_type == PACKET.RADIO and packet.rorg == eep.rorg: try: data = EnoceanTools.extract_props(packet=packet, eep=eep) except AttributeError as ex: raise DeviceException(ex) else: data = {} return data
def get_props_from_packet(cls, packet: RadioPacket) -> Dict[str, int]: eep = cls._EEP if packet.packet_type == PACKET.RADIO and packet.rorg == eep.rorg: try: props = EnoceanTools.extract_props(packet=packet, eep=eep) except AttributeError as ex: raise EepPropException(ex) else: props = {} return props
def process_enocean_message(self, message: EnoceanMessage): packet = message.payload # type: RadioPacket if packet.packet_type != PACKET.RADIO: self._logger.debug("skipped packet with packet_type=%s", EnoceanTools.packet_type_to_string(packet.rorg)) return rocker_scene = self.find_rocker_scene(packet) if rocker_scene: self.process_rocker_scene(rocker_scene) else: self._process_actor_packet(packet)
def process_enocean_message(self, message: EnoceanMessage): packet = message.payload # type: RadioPacket if packet.packet_type != PACKET.RADIO: self._logger.debug("skipped packet with packet_type=%s", EnoceanTools.packet_type_to_string(packet.rorg)) return if packet.rorg != self._eep.rorg: self._logger.debug("skipped packet with rorg=%s", hex(packet.rorg)) return message_data = self._find_rocker_command(packet) if message_data and message_data.topic: self._publish_mqtt(message_data.payload, message_data.topic)
def get_props_from_packet(cls, packet, command: Optional[Fsr61Command] = None) -> Dict[str, int]: eep = cls.EEP.clone() if packet.packet_type == PACKET.RADIO and packet.rorg == eep.rorg: if command is None: eep.command = 0 try: tmp_props = EnoceanTools.extract_props(packet=packet, eep=eep) eep.command = tmp_props[Fsr61Prop.CMD.value] except AttributeError as ex: raise EepPropException(ex) else: eep.command = command.value try: props = EnoceanTools.extract_props(packet=packet, eep=eep) except AttributeError as ex: raise EepPropException(ex) else: props = {} return props
def find_rocker_scene(self, packet: RadioPacket) -> Optional[RockerScene]: if packet.packet_type == PACKET.RADIO and packet.rorg == RockerSwitchTools.DEFAULT_EEP.rorg: scenes = [ s for s in self._scenes if s.rocker_id == packet.sender_int ] if scenes: try: rocker_action = RockerSwitchTools.extract_action_from_packet( packet) scenes = [ s for s in scenes if s.rocker_key == rocker_action.button ] except DeviceException: scenes = None EnoceanTools.log_pickled_enocean_packet( self._logger.warning, packet, "find_rocker_scene - cannot extract") if scenes: return scenes[0] return None
def test_created_switch_packet(self): device = _MockDevice() packet = device._create_switch_packet(RockerSwitchAction.ON) extract = EnoceanTools.extract_props(packet=packet, eep=RockerSwitchTools.DEFAULT_EEP) self.assertEqual(extract, { 'R1': 1, 'EB': 1, 'R2': 0, 'SA': 0, 'T21': 1, 'NU': 1 })
def test_packet_roundtrip(self): props_in = {'R1': 1, 'EB': 1, 'R2': 0, 'SA': 0, 'T21': 1, 'NU': 1} eep = Eep(rorg=0xf6, func=0x02, type=0x02) packet_in = EnoceanPacketFactory.create_packet( eep=eep, destination=EnoceanTools.int_to_byte_list(0xffffffff), learn=False, **props_in ) text = PickleTools.pickle_packet(packet_in) packet_out = PickleTools.unpickle_packet(text) self.assertEqual(packet_out, packet_in)
def test_extract_press(self): loop_data = [ (PACKET_0_PRESS, RockerButton.ROCK0), (PACKET_1_PRESS, RockerButton.ROCK1), (PACKET_2_PRESS, RockerButton.ROCK2), (PACKET_3_PRESS, RockerButton.ROCK3), ] for i in range(0, 3): packet = PickleTools.unpickle_packet(loop_data[i][0]) device = _MockDevice() extracted = EnoceanTools.extract_packet_props(packet, device._eep) action = RockerAction(press=RockerPress.PRESS_SHORT, button=loop_data[i][1]) expected = RockerSwitchTools.create_props(action) self.assertEqual(extracted, expected)
def extract_packet(cls, packet: RadioPacket) -> Fsb61State: status = Fsb61State() status.rssi = packet.dBm status.sender = packet.sender_int status.destination = packet.destination_int if Fsb61CommandConverter.is_command_packet( packet): # packet.rorg == 0xa5 command = Fsb61CommandConverter.extract_packet(packet) if command.type == Fsb61CommandType.CLOSE: status.type = Fsb61StateType.CLOSED status.time = command.time elif command.type == Fsb61CommandType.OPEN: status.type = Fsb61StateType.OPENED status.time = command.time elif command.type == Fsb61CommandType.STOP: status.type = Fsb61StateType.STOPPED status.time = 0 else: raise EepPropException("Invalid command type!") elif packet.rorg == cls._EEP.rorg: props = EnoceanTools.extract_props(packet, cls._EEP) r2 = props["R2"] # R2 (Rocker 2nd action) sa = props["SA"] # 2nd action valid if sa == 1: if r2 == 0: # 0: Button AI: "Switch light on" or "Dim light up" or "Move blind open" status.type = Fsb61StateType.OPENING elif r2 == 1: # 1: Button A0: "switch light off" or "Dim light down" or "Move blind closed" status.type = Fsb61StateType.CLOSING elif sa == 0: if r2 == 1: # 1: Button A0: "switch light off" or "Dim light down" or "Move blind closed" status.type = Fsb61StateType.CLOSING else: status.type = Fsb61StateType.STOPPED if status.type is None: raise EepPropException("Invalid data ({})!".format(props)) else: status.type = Fsb61StateType.UNKNOWN return status
def process_enocean_message(self, message: EnoceanMessage): packet = message.payload # type: RadioPacket if packet.packet_type != PACKET.RADIO: self._logger.debug("skipped packet with packet_type=%s", EnoceanTools.packet_type_to_string(packet.rorg)) return if packet.rorg == RockerSwitchTools.DEFAULT_EEP.rorg: props = RockerSwitchTools.extract_props(packet) self._logger.debug("proceed_enocean - got=%s", props) action = RockerSwitchTools.extract_action( props) # type: RockerAction if action.button == RockerButton.ROCK3: self._current_switch_state = SwitchStatus.ON elif action.button == RockerButton.ROCK2: self._current_switch_state = SwitchStatus.OFF else: self._current_switch_state = SwitchStatus.ERROR else: self._current_switch_state = SwitchStatus.ERROR if self._current_switch_state not in [ SwitchStatus.ON, SwitchStatus.OFF ]: if self._logger.isEnabledFor(logging.DEBUG): self._logger.debug( "proceed_enocean - pickled error packet:\n%s", PickleTools.pickle_packet(packet)) self._logger.debug("proceed_enocean - switch_state=%s", self._current_switch_state) self._last_status_request = self._now() self._reset_offline_refresh_timer() message = self._create_json_message(self._current_switch_state) self._publish_mqtt(message)
def test_open(self): packet = PickleTools.unpickle(PACKET_WIN_OPEN) comp = {'WIN': 2, 'T21': 1, 'NU': 0} data = EnoceanTools.extract_packet_props(packet, self.eep) self.assertEqual(data, comp)
def test_packet_type_text(self): self.assertEqual(EnoceanTools.packet_type_to_string(PACKET.RADIO), "RADIO") self.assertEqual(EnoceanTools.packet_type_to_string(int(PACKET.RADIO)), "RADIO") self.assertEqual(EnoceanTools.packet_type_to_string(None), "None")
def set_sender_id(cls, sender_id): if type(sender_id) == int: cls._sender_id = EnoceanTools.int_to_byte_list(sender_id) else: cls._sender_id = copy.deepcopy(sender_id)
def test_int_to_byte_list(self): value = 0x034567af byte_list = EnoceanTools.int_to_byte_list(value) result = enocean.utils.combine_hex(byte_list) self.assertEqual(result, value)