def _process_zone_statuses(self, zone_statuses, device, device_sn): for z_key, p_status in zone_statuses.items(): if z_key not in self.zones: continue zone = self.zones[z_key] open_topic = "{}/{}/{}/{}/{}".format( cfg.MQTT_BASE_TOPIC, cfg.MQTT_STATES_TOPIC, cfg.MQTT_ZONE_TOPIC, sanitize_key(zone["key"]), "open", ) config = dict( name=zone["label"], unique_id="{}_zone_{}_open".format(device_sn, zone["key"]), state_topic=open_topic, device_class="motion", availability_topic=self.availability_topic, payload_on="True", payload_off="False", device=device, ) configuration_topic = "{}/binary_sensor/{}/{}/config".format( cfg.MQTT_HOMEASSISTANT_DISCOVERY_PREFIX, device_sn, sanitize_key(zone["key"]), ) self.publish(configuration_topic, json.dumps(config), 0, cfg.MQTT_RETAIN)
def _process_partition_statuses(self, partition_statuses, device, device_sn): for p_key, p_status in partition_statuses.items(): if p_key not in self.partitions: continue partition = self.partitions[p_key] state_topic = '{}/{}/{}/{}/{}'.format( cfg.MQTT_BASE_TOPIC, cfg.MQTT_STATES_TOPIC, cfg.MQTT_PARTITION_TOPIC, sanitize_key(partition['key']), 'current_state') configuration_topic = '{}/alarm_control_panel/{}/{}/config'.format( cfg.MQTT_HOMEASSISTANT_DISCOVERY_PREFIX, device_sn, sanitize_key(partition['key'])) command_topic = '{}/{}/{}/{}'.format( cfg.MQTT_BASE_TOPIC, cfg.MQTT_CONTROL_TOPIC, cfg.MQTT_PARTITION_TOPIC, sanitize_key(partition['key'])) config = dict(name=partition['label'], unique_id="{}_partition_{}".format( device_sn, partition['key']), command_topic=command_topic, state_topic=state_topic, availability_topic=self.availability_topic, device=device, payload_disarm="disarm", payload_arm_home="arm_stay", payload_arm_away="arm", payload_arm_night="arm_sleep") self.publish(configuration_topic, json.dumps(config), 0, cfg.MQTT_RETAIN)
def _process_zone_statuses(self, zone_statuses): for z_key, p_status in zone_statuses.items(): if z_key not in self.zones: continue zone = self.zones[z_key] if self.first_status: # For HASS auto discovery open_topic = '{}/{}/{}/{}/{}'.format(cfg.MQTT_BASE_TOPIC, cfg.MQTT_STATES_TOPIC, cfg.MQTT_ZONE_TOPIC, sanitize_key(zone['key']), 'open') config = dict(name=zone['label'], unique_id="{}_zone_{}_open".format( self.detected_panel.get( 'serial_number', 'pai'), zone['key']), state_topic=open_topic, device_class="motion", availability_topic=self.availability_topic, payload_on="True", payload_off="False", device=self.device) configuration_topic = '{}/binary_sensor/{}/{}/config'.format( cfg.MQTT_HOMEASSISTANT_DISCOVERY_PREFIX, self.detected_panel.get('serial_number', 'pai'), sanitize_key(zone['key'])) self.publish(configuration_topic, json.dumps(config), 0, cfg.MQTT_RETAIN)
def _publish( self, base: str, element_type: str, label: str, attribute: str, value: [str, int, bool], ): if element_type in ELEMENT_TOPIC_MAP: element_topic = ELEMENT_TOPIC_MAP[element_type] else: element_topic = element_type if isinstance(value, dict): # This is fragile... if "/" in attribute and not attribute.startswith("/"): attribute = f"/{attribute}" for attr_name, attr_value in value.items(): label_tp = f"{attribute}/{attr_name}" self._publish(base, element_type, label, label_tp, attr_value) return if cfg.MQTT_USE_NUMERIC_STATES: publish_value = int(value) else: publish_value = value self.publish( "{}/{}/{}/{}".format(base, element_topic, sanitize_key(label), attribute), "{}".format(publish_value), 0, cfg.MQTT_RETAIN, )
async def _load_labels( self, data: dict, elem_type: str, addresses: typing.Iterator[typing.Tuple[int, int]], field_length=16, label_offset=0, template=None, ): """ Load labels from panel :param data_dict: Dict to fill :param addresses: Addresses list with indexes :param field_length: Text field length :param label_offset: Label offset :param template: Default template :return: """ element_dict = data[elem_type] if template is None: template = {} async for index, data in self._eeprom_batch_reader( addresses, field_length): b_label = data[label_offset:label_offset + field_length].strip(b"\0 ") label = b_label.replace(b"\0", b" ") try: label = label.decode(cfg.LABEL_ENCODING) except UnicodeDecodeError: logger.warning( "Unable to properly decode label {} using the {} encoding.\n \ Specify a different encoding using the LABEL_ENCODING configuration option." .format(b_label, cfg.LABEL_ENCODING)) label = label.decode("utf-8", errors="ignore") properties = template.copy() properties["id"] = index properties["key"] = sanitize_key(label) or sanitize_key( f"{elem_type} {index}") properties["label"] = label element_dict[index] = properties
def _process_pgm_statuses(self, pgm_statuses, device, device_sn): for pgm_key, p_status in pgm_statuses.items(): if pgm_key not in self.pgms: continue pgm = self.pgms[pgm_key] on_topic = "{}/{}/{}/{}/{}".format( cfg.MQTT_BASE_TOPIC, cfg.MQTT_STATES_TOPIC, cfg.MQTT_OUTPUT_TOPIC, sanitize_key(pgm["key"]), "on", ) command_topic = "{}/{}/{}/{}".format( cfg.MQTT_BASE_TOPIC, cfg.MQTT_CONTROL_TOPIC, cfg.MQTT_OUTPUT_TOPIC, sanitize_key(pgm["key"]), ) config = dict( name=pgm["label"], unique_id="{}_pgm_{}_open".format(device_sn, pgm["key"]), state_topic=on_topic, command_topic=command_topic, availability_topic=self.availability_topic, state_on="True", state_off="False", payload_on="on", payload_off="off", device=device, ) configuration_topic = "{}/switch/{}/{}/config".format( cfg.MQTT_HOMEASSISTANT_DISCOVERY_PREFIX, device_sn, sanitize_key(pgm["key"]), ) self.publish(configuration_topic, json.dumps(config), 0, cfg.MQTT_RETAIN)
async def _load_labels(self, data_dict: dict, addresses: typing.List[typing.Tuple[int, int]], field_length=16, label_offset=0, template=None): """ Load labels from panel :param data_dict: Dict to fill :param addresses: Addresses list with indexes :param field_length: Text field length :param label_offset: Label offset :param template: Default template :return: """ if template is None: template = {} for index, address in addresses: args = dict(address=address, length=field_length) reply = await self.core.send_wait( self.get_message('ReadEEPROM'), args, reply_expected=lambda m: m.fields.value.po.command == 0x05 and m.fields.value.address == address) if reply is None: logger.error("Could not fully load labels") return data = reply.fields.value.data b_label = data[label_offset:label_offset + field_length].strip(b'\0 ') label = b_label.replace(b'\0', b' ') try: label = label.decode(cfg.LABEL_ENCODING) except UnicodeDecodeError: logger.warning( 'Unable to properly decode label {} using the {} encoding.\n \ Specify a different encoding using the LABEL_ENCODING configuration option.' .format(b_label, cfg.LABEL_ENCODING)) label = label.decode('utf-8', errors='ignore') properties = template.copy() properties['id'] = index properties['key'] = sanitize_key(label) properties['label'] = label data_dict[index] = properties
async def _load_labels(self, data_dict: dict, addresses: typing.Iterator[typing.Tuple[int, int]], field_length=16, label_offset=0, template=None): """ Load labels from panel :param data_dict: Dict to fill :param addresses: Addresses list with indexes :param field_length: Text field length :param label_offset: Label offset :param template: Default template :return: """ if template is None: template = {} async for index, data in self._eeprom_batch_reader( addresses, field_length): b_label = data[label_offset:label_offset + field_length].strip(b'\0 ') label = b_label.replace(b'\0', b' ') try: label = label.decode(cfg.LABEL_ENCODING) except UnicodeDecodeError: logger.warning( 'Unable to properly decode label {} using the {} encoding.\n \ Specify a different encoding using the LABEL_ENCODING configuration option.' .format(b_label, cfg.LABEL_ENCODING)) label = label.decode('utf-8', errors='ignore') properties = template.copy() properties['id'] = index properties['key'] = sanitize_key(label) properties['label'] = label data_dict[index] = properties
def _handle_panel_change(self, change: Change): attribute = change.property label = change.key value = change.new_value element_type = change.type """Handle Property Change""" # Dash stuff START # TODO: move to a separate component # Keep track of ARM state if element_type == 'partition': if label not in self.partitions: self.partitions[label] = dict() # After we get 2 partitions, lets publish a dashboard if cfg.MQTT_DASH_PUBLISH and len(self.partitions) == 2: self._publish_dash(cfg.MQTT_DASH_TEMPLATE, list(self.partitions.keys())) self.partitions[label][attribute] = value # Dash stuff END if element_type in ELEMENT_TOPIC_MAP: element_topic = ELEMENT_TOPIC_MAP[element_type] else: element_topic = element_type if cfg.MQTT_USE_NUMERIC_STATES: publish_value = int(value) else: publish_value = value self.publish('{}/{}/{}/{}/{}'.format(cfg.MQTT_BASE_TOPIC, cfg.MQTT_STATES_TOPIC, element_topic, sanitize_key(label), attribute), "{}".format(publish_value), 0, cfg.MQTT_RETAIN)
def test_sanitize_key(): assert sanitize_key('Előtér') == 'Előtér' assert sanitize_key('Living room') == 'Living_room' assert sanitize_key(1) == '1'
def test_sanitize_key(): assert sanitize_key("Előtér") == "Előtér" assert sanitize_key("Living room") == "Living_room" assert sanitize_key(1) == "1"