From b6baba468e9af7598431ab4489bf95bf15950896 Mon Sep 17 00:00:00 2001 From: sisamiwe Date: Thu, 17 Aug 2023 19:48:00 +0200 Subject: [PATCH 001/147] AVM: Add set_color and set_hsv - bump to 2.2.0 - update user_doc.rst showing all allowed attributes - enhance item_attributes_master.py to add/update attributes list and description - add / enhance methods to set color and hsv - enable to switch to on/off based on dimmer value --- avm/__init__.py | 209 ++++++++++++---------- avm/item_attributes.py | 6 +- avm/item_attributes_master.py | 62 ++++++- avm/plugin.yaml | 6 +- avm/user_doc.rst | 320 ++++++++++++++++++++++++++++++++++ 5 files changed, 502 insertions(+), 101 deletions(-) mode change 100755 => 100644 avm/user_doc.rst diff --git a/avm/__init__.py b/avm/__init__.py index 0eab2326c..b088acda5 100644 --- a/avm/__init__.py +++ b/avm/__init__.py @@ -113,7 +113,7 @@ class AVM(SmartPlugin): """ Main class of the Plugin. Does all plugin specific stuff """ - PLUGIN_VERSION = '2.1.0' + PLUGIN_VERSION = '2.2.0' # ToDo: FritzHome.handle_updated_item: implement 'saturation' # ToDo: FritzHome.handle_updated_item: implement 'unmapped_hue' @@ -2071,6 +2071,7 @@ def handle_updated_item(self, item, avm_data_type: str, readafterwrite: int): 'unmapped_hue': (self.set_unmapped_hue, {'hue': item()}, self.get_unmapped_hue), 'unmapped_saturation': (self.set_unmapped_saturation, {'saturation': item()}, self.get_unmapped_saturation), 'color': (self.set_color, {'hs': item(), 'duration': 1, 'mapped': False}, self.get_color), + 'hsv': (self.set_hsv, {'hsv': item(), 'duration': 1, 'mapped': False}, self.get_hsv), } # Remove "set_" prefix of AHA_WO_ATTRIBUTES Items: @@ -2656,7 +2657,7 @@ def get_state(self, ain: str): """ Get the switch/actuator/lightbulb to a state. """ - return self.get_devices_as_dict()[ain].switch_state + return self.get_devices_as_dict()[ain].simpleonoff # Level/Dimmer-related methods @@ -2671,6 +2672,11 @@ def set_level(self, ain: str, level: int): else: level = int(level) + if not level and self.get_state(ain): + self.set_state_off(ain) + elif level and not self.get_state(ain): + self.set_state_on(ain) + return self.aha_request("setlevel", ain=ain, param={'level': level}, result_type='int') @NoKeyOrAttributeError @@ -2690,6 +2696,11 @@ def set_level_percentage(self, ain: str, level: int): else: level = int(level) + if not level and self.get_state(ain): + self.set_state_off(ain) + elif level and not self.get_state(ain): + self.set_state_on(ain) + return self.aha_request("setlevelpercentage", ain=ain, param={'level': level}, result_type='int') @NoKeyOrAttributeError @@ -2820,58 +2831,91 @@ def get_colors(self, ain: str) -> dict: colors[name] = values return colors + def set_color(self, ain: str, hs: list, duration: int = 1, mapped: bool = True) -> bool: + """ + Set hue and saturation. + hs: colorspace element obtained from get_colors() + hs is an array including hue, saturation and level + hue must be within range 0-359 + saturation must be within range 0-100 + duration: Speed of change in seconds, 0 = instant + mapped = True uses the AVM setcolor function. It only supports pre-defined colors that can be obtained by the get_colors function. + mapped = False uses the AVM setunmappedcolor function, featured by AVM firmwareversion since approximately Q2 2022. It supports every combination if hue/saturation/level + """ + + if len(hs) != 2: + self.logger.warning(f"set_color: hsv={hs} does to much or to less entries. hue and saturation needed.") + return False + + hue = to_int(hs[0]) + saturation = int(to_int(hs[1])*2.55) + duration = to_int(duration) * 10 + + # Range checks: + if not self.HUE_RANGE['min'] <= hue <= self.HUE_RANGE['max']: + hue = clamp(hue, self.HUE_RANGE['min'], self.HUE_RANGE['max']) + self.logger.warning(f"set_color: hue value must be between {self.HUE_RANGE['min']} and {self.HUE_RANGE['max']}; hue will be set to {hue}") + + if not self.SATURATION_RANGE['min'] <= saturation <= self.SATURATION_RANGE['max']: + saturation = clamp(saturation, self.SATURATION_RANGE['min'], self.SATURATION_RANGE['max']) + self.logger.warning(f"set_color: saturation value must be between {self.SATURATION_RANGE['min']} and {self.SATURATION_RANGE['max']}; hue will be set to {saturation}") + + self.logger.debug(f"set_color called with mapped={mapped} and hs: {hue}, {saturation}") + + param = { + 'hue': hue, + 'saturation': saturation, + 'duration': duration, + } + + # special mode for white color (hue=0, saturation=0): + if (hue == 0) and (saturation == 0): + self.logger.debug(f"set_color, warm white color selected") + return self.set_color_temp(ain, temperature=self.COLOR_TEMP_RANGE['min'], duration=1) + + if mapped: + result = self.aha_request("setcolor", ain=ain, param=param, result_type='int') + else: + result = self.aha_request("setunmappedcolor", ain=ain, param=param, result_type='int') + + self.logger.debug(f"set_color in mapped={mapped} with result={result}") + return result + @NoKeyOrAttributeError def get_color(self, ain: str) -> list: """get hue, saturation value as list""" return self.get_devices_as_dict()[ain].color - def set_color(self, ain, hsv, duration=0, mapped=True): + def get_hsv(self, ain: str) -> list: + """get hue, saturation, level value as list""" + return self.get_devices_as_dict()[ain].hsv + + def set_hsv(self, ain: str, hsv: list, duration: int = 1, mapped: bool = True) -> bool: """ - Set hue and saturation. - hsv: HUE colorspace element obtained from get_colors() + Set hue, saturation, level. + hsv: colorspace element obtained from get_colors() hsv is an array including hue, saturation and level hue must be within range 0-359 - saturation must be within range 0-255 + saturation must be within range 0-100 + value must be within range 0-100 duration: Speed of change in seconds, 0 = instant - mapped = True uses the AVM setcolor function. It only - supports pre-defined colors that can be obtained - by the get_colors function. - mapped = False uses the AVM setunmappedcolor function, featured - by AVM firmwareversion since approximately Q2 2022. It - supports every combination if hue/saturation/level - """ - - params = { - 'hue': int(hsv[0]), - 'saturation': int(hsv[1]), - "duration": int(duration) * 10 - } + mapped = True uses the AVM setcolor function. It only supports pre-defined colors that can be obtained by the get_colors function. + mapped = False uses the AVM setunmappedcolor function, featured by AVM firmwareversion since approximately Q2 2022. It supports every combination if hue/saturation/level + """ - # Range checks: - hue = int(hsv[0]) - if (hue < 0) or hue > 359: - self.logger.error(f"set_color, hue value must be between 0 and 359") - return False - saturation = int(hsv[1]) - if (saturation < 0) or saturation > 255: - self.logger.error(f"set_color, saturation value must be between 0 and 255") + self.logger.debug(f"set_hsv called: {ain=}, {hsv=}, {duration=}, {mapped=}") + + if len(hsv) != 3: + self.logger.warning(f"set_color: hsv={hsv} does have to much or to less entries. hue, saturation and level needed.") return False - # special mode for white color (hue=0, saturation=0): - self.logger.warning(f"Debug set_color called with mapped {mapped} and hs(v): {int(hsv[0])}, {int(hsv[1])}") - if (int(hsv[0]) == 0) and (int(hsv[1]) == 0): - self.logger.debug(f"set_color, warm white color selected") - success = self.set_color_temp(ain, temperature=2700, duration=1) - return success + hue, saturation, level = hsv - if mapped: - success = self.aha_request(cmd="setcolor", ain=ain, param=params) - else: - # undocumented API method for free color selection - success = self.aha_request(cmd="setunmappedcolor", ain=ain, param=params) + result_hs = self.set_color(ain, [hue, saturation], duration, mapped) + result_l = self.set_level_percentage(ain, level) - self.logger.warning(f"Debug set color in mapped {mapped} mode: success: {success}") - return success + self.logger.debug(f"set_hsv: in mapped '{mapped}': result_hs={result_hs}, result_l={result_l}") + return result_hs & result_l def set_color_discrete(self, ain, hue, duration=0): """ @@ -3718,14 +3762,14 @@ class FritzhomeDeviceColor(FritzhomeDeviceBase): supported_color_mode = None fullcolorsupport = None mapped = None - hue = None saturation = None unmapped_hue = None unmapped_saturation = None colortemperature = None color = None - + hsv = None + logger = logging.getLogger(__name__) def _update_from_node(self, node): @@ -3744,60 +3788,41 @@ def _update_color_from_node(self, node): colorcontrol_element = node.find("colorcontrol") if colorcontrol_element is not None: + self.color_mode = int(colorcontrol_element.attrib.get("current_mode")) + self.supported_color_mode = int(colorcontrol_element.attrib.get("supported_modes")) + self.fullcolorsupport = bool(colorcontrol_element.attrib.get("fullcolorsupport")) + self.mapped = bool(colorcontrol_element.attrib.get("mapped")) + self.hue = get_node_value_as_int(colorcontrol_element, "hue") + saturation = get_node_value_as_int(colorcontrol_element, "saturation") + self.saturation = int(saturation/2.55) + self.unmapped_hue = get_node_value_as_int(colorcontrol_element, "unmapped_hue") + unmapped_saturation = get_node_value_as_int(colorcontrol_element, "unmapped_saturation") + self.unmapped_saturation = int(unmapped_saturation/2.55) + self.colortemperature = get_node_value_as_int(colorcontrol_element, "temperature") + + if self.mapped: + self.color = [self.hue, self.saturation] + else: + self.color = [self.unmapped_hue, self.unmapped_saturation] - try: - self.color_mode = int(colorcontrol_element.attrib.get("current_mode")) - except ValueError: - pass - - try: - self.supported_color_mode = int(colorcontrol_element.attrib.get("supported_modes")) - except ValueError: - pass - - try: - self.fullcolorsupport = bool(colorcontrol_element.attrib.get("fullcolorsupport")) - except ValueError: - pass - - try: - self.mapped = bool(colorcontrol_element.attrib.get("mapped")) - except ValueError: - pass - - try: - self.hue = get_node_value_as_int(colorcontrol_element, "hue") - self.logger.debug(f"received hue value {self.hue}") - except ValueError: - self.hue = 0 - - try: - value = get_node_value_as_int(colorcontrol_element, "saturation") - self.saturation = int(value/2.55) - self.logger.debug(f"received unmapped saturation value {value}, scaled to {self.saturation}") - except ValueError: - self.saturation = 0 + self.logger.debug(f"FritzColor: created color={self.color} with mapped={self.mapped}") - try: - self.unmapped_hue = get_node_value_as_int(colorcontrol_element, "unmapped_hue") - self.logger.debug(f"received unmapped hue value {self.unmapped_hue}") - except ValueError: - self.logger.warning(f"exception in unmapped_hue extraction") - self.unmapped_hue = 0 + # get levelpercentage + levelcontrol_element = node.find("levelcontrol") + if levelcontrol_element is not None: + levelpercentage = get_node_value_as_int(levelcontrol_element, "levelpercentage") + else: + levelpercentage = 0 - try: - value = get_node_value_as_int(colorcontrol_element, "unmapped_saturation") - self.unmapped_saturation = int(value/2.55) - self.logger.debug(f"received unmapped saturation value {value}, scaled to {self.unmapped_saturation}") - except ValueError: - self.unmapped_saturation = 0 - except Exception as e: - self.logger.error(f"Exception while receiving unmapped saturation: {e}") + # Set Level to zero for consistency, if light is off: + state_element = node.find("simpleonoff") + if state_element is not None: + simpleonoff = get_node_value_as_int_as_bool(state_element, "state") + if simpleonoff is False: + levelpercentage = 0 - try: - self.colortemperature = get_node_value_as_int(colorcontrol_element, "temperature") - except ValueError: - self.colortemperature = 0 + self.hsv = self.color.copy() + self.hsv.append(levelpercentage) def get_colors(self): """Get the supported colors.""" diff --git a/avm/item_attributes.py b/avm/item_attributes.py index b6bb7011a..9b9317aad 100644 --- a/avm/item_attributes.py +++ b/avm/item_attributes.py @@ -29,13 +29,13 @@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ALL_ATTRIBUTES_SUPPORTED_BY_REPEATER = ['uptime', 'serial_number', 'software_version', 'hardware_version', 'manufacturer', 'product_class', 'manufacturer_oui', 'model_name', 'description', 'device_log', 'security_port', 'reboot', 'wlanconfig', 'wlanconfig_ssid', 'wlan_guest_time_remaining', 'wlan_associates', 'wps_active', 'wps_status', 'wps_mode', 'wlan_total_associates', 'hosts_count', 'hosts_info', 'mesh_topology', 'number_of_hosts', 'hosts_url', 'mesh_url', 'network_device', 'device_ip', 'device_connection_type', 'device_hostname', 'connection_status', 'is_host_active', 'host_info'] -ALL_ATTRIBUTES_WRITEABLE = ['reboot', 'set_target_temperature', 'set_window_open', 'set_hkr_boost', 'set_simpleonoff', 'set_level', 'set_levelpercentage', 'set_hue', 'set_saturation', 'set_colortemperature', 'switch_toggle', 'tam', 'wlanconfig', 'wps_active', 'deflection_enable', 'aha_device', 'target_temperature', 'window_open', 'hkr_boost', 'simpleonoff', 'level', 'levelpercentage', 'hue', 'saturation', 'colortemperature', 'unmapped_hue', 'unmapped_saturation', 'switch_state'] +ALL_ATTRIBUTES_WRITEABLE = ['reboot', 'set_target_temperature', 'set_window_open', 'set_hkr_boost', 'set_simpleonoff', 'set_level', 'set_levelpercentage', 'set_hue', 'set_saturation', 'set_colortemperature', 'switch_toggle', 'tam', 'wlanconfig', 'wps_active', 'deflection_enable', 'aha_device', 'target_temperature', 'window_open', 'hkr_boost', 'simpleonoff', 'level', 'levelpercentage', 'hue', 'saturation', 'colortemperature', 'unmapped_hue', 'unmapped_saturation', 'color', 'hsv', 'switch_state'] ALL_ATTRIBUTES_WRITEONLY = ['reboot', 'set_target_temperature', 'set_window_open', 'set_hkr_boost', 'set_simpleonoff', 'set_level', 'set_levelpercentage', 'set_hue', 'set_saturation', 'set_colortemperature', 'switch_toggle'] DEPRECATED_ATTRIBUTES = ['aha_device', 'hkr_device', 'set_temperature', 'temperature', 'set_temperature_reduced', 'set_temperature_comfort', 'firmware_version', 'boost_active'] -AHA_ATTRIBUTES = ['device_id', 'manufacturer', 'product_name', 'fw_version', 'connected', 'device_name', 'tx_busy', 'device_functions', 'set_target_temperature', 'target_temperature', 'current_temperature', 'temperature_reduced', 'temperature_comfort', 'temperature_offset', 'set_window_open', 'window_open', 'windowopenactiveendtime', 'set_hkr_boost', 'hkr_boost', 'boost_active', 'boostactiveendtime', 'summer_active', 'holiday_active', 'battery_low', 'battery_level', 'lock', 'device_lock', 'errorcode', 'set_simpleonoff', 'simpleonoff', 'set_level', 'level', 'set_levelpercentage', 'levelpercentage', 'set_hue', 'hue', 'set_saturation', 'saturation', 'set_colortemperature', 'colortemperature', 'unmapped_hue', 'unmapped_saturation', 'color_mode', 'supported_color_mode', 'fullcolorsupport', 'mapped', 'switch_state', 'switch_mode', 'switch_toggle', 'power', 'energy', 'voltage', 'humidity', 'alert_state', 'blind_mode', 'endpositionsset', 'statistics_temp', 'statistics_hum', 'statistics_voltage', 'statistics_power', 'statistics_energy'] +AHA_ATTRIBUTES = ['device_id', 'manufacturer', 'product_name', 'fw_version', 'connected', 'device_name', 'tx_busy', 'device_functions', 'set_target_temperature', 'target_temperature', 'current_temperature', 'temperature_reduced', 'temperature_comfort', 'temperature_offset', 'set_window_open', 'window_open', 'windowopenactiveendtime', 'set_hkr_boost', 'hkr_boost', 'boost_active', 'boostactiveendtime', 'summer_active', 'holiday_active', 'battery_low', 'battery_level', 'lock', 'device_lock', 'errorcode', 'set_simpleonoff', 'simpleonoff', 'set_level', 'level', 'set_levelpercentage', 'levelpercentage', 'set_hue', 'hue', 'set_saturation', 'saturation', 'set_colortemperature', 'colortemperature', 'unmapped_hue', 'unmapped_saturation', 'color', 'hsv', 'color_mode', 'supported_color_mode', 'fullcolorsupport', 'mapped', 'switch_state', 'switch_mode', 'switch_toggle', 'power', 'energy', 'voltage', 'humidity', 'alert_state', 'blind_mode', 'endpositionsset', 'statistics_temp', 'statistics_hum', 'statistics_voltage', 'statistics_power', 'statistics_energy'] AHA_RO_ATTRIBUTES = ['device_id', 'manufacturer', 'product_name', 'fw_version', 'connected', 'device_name', 'tx_busy', 'device_functions', 'current_temperature', 'temperature_reduced', 'temperature_comfort', 'temperature_offset', 'windowopenactiveendtime', 'boost_active', 'boostactiveendtime', 'summer_active', 'holiday_active', 'battery_low', 'battery_level', 'lock', 'device_lock', 'errorcode', 'color_mode', 'supported_color_mode', 'fullcolorsupport', 'mapped', 'switch_mode', 'power', 'energy', 'voltage', 'humidity', 'alert_state', 'blind_mode', 'endpositionsset', 'statistics_temp', 'statistics_hum', 'statistics_voltage', 'statistics_power', 'statistics_energy'] AHA_WO_ATTRIBUTES = ['set_target_temperature', 'set_window_open', 'set_hkr_boost', 'set_simpleonoff', 'set_level', 'set_levelpercentage', 'set_hue', 'set_saturation', 'set_colortemperature', 'switch_toggle'] -AHA_RW_ATTRIBUTES = ['target_temperature', 'window_open', 'hkr_boost', 'simpleonoff', 'level', 'levelpercentage', 'hue', 'saturation', 'colortemperature', 'unmapped_hue', 'unmapped_saturation', 'switch_state'] +AHA_RW_ATTRIBUTES = ['target_temperature', 'window_open', 'hkr_boost', 'simpleonoff', 'level', 'levelpercentage', 'hue', 'saturation', 'colortemperature', 'unmapped_hue', 'unmapped_saturation', 'color', 'hsv', 'switch_state'] AHA_STATS_ATTRIBUTES = ['statistics_temp', 'statistics_hum', 'statistics_voltage', 'statistics_power', 'statistics_energy'] TR064_ATTRIBUTES = ['uptime', 'serial_number', 'software_version', 'hardware_version', 'manufacturer', 'product_class', 'manufacturer_oui', 'model_name', 'description', 'device_log', 'security_port', 'reboot', 'myfritz_status', 'call_direction', 'call_event', 'monitor_trigger', 'is_call_incoming', 'last_caller_incoming', 'last_call_date_incoming', 'call_event_incoming', 'last_number_incoming', 'last_called_number_incoming', 'is_call_outgoing', 'last_caller_outgoing', 'last_call_date_outgoing', 'call_event_outgoing', 'last_number_outgoing', 'last_called_number_outgoing', 'call_duration_incoming', 'call_duration_outgoing', 'tam', 'tam_name', 'tam_new_message_number', 'tam_old_message_number', 'tam_total_message_number', 'wan_connection_status', 'wan_connection_error', 'wan_is_connected', 'wan_uptime', 'wan_ip', 'wan_upstream', 'wan_downstream', 'wan_total_packets_sent', 'wan_total_packets_received', 'wan_current_packets_sent', 'wan_current_packets_received', 'wan_total_bytes_sent', 'wan_total_bytes_received', 'wan_current_bytes_sent', 'wan_current_bytes_received', 'wan_link', 'wlanconfig', 'wlanconfig_ssid', 'wlan_guest_time_remaining', 'wlan_associates', 'wps_active', 'wps_status', 'wps_mode', 'wlan_total_associates', 'hosts_count', 'hosts_info', 'mesh_topology', 'number_of_hosts', 'hosts_url', 'mesh_url', 'network_device', 'device_ip', 'device_connection_type', 'device_hostname', 'connection_status', 'is_host_active', 'host_info', 'number_of_deflections', 'deflections_details', 'deflection_details', 'deflection_enable', 'deflection_type', 'deflection_number', 'deflection_to_number', 'deflection_mode', 'deflection_outgoing', 'deflection_phonebook_id', 'aha_device', 'hkr_device', 'set_temperature', 'temperature', 'set_temperature_reduced', 'set_temperature_comfort', 'firmware_version'] TR064_RW_ATTRIBUTES = ['tam', 'wlanconfig', 'wps_active', 'deflection_enable', 'aha_device'] diff --git a/avm/item_attributes_master.py b/avm/item_attributes_master.py index 505a557f0..a865451d1 100644 --- a/avm/item_attributes_master.py +++ b/avm/item_attributes_master.py @@ -25,6 +25,8 @@ FILENAME_PLUGIN = 'plugin.yaml' +DOC_FILE_NAME = 'user_doc.rst' + ATTRIBUTE = 'avm_data_type' FILE_HEADER = """\ @@ -197,6 +199,8 @@ 'colortemperature': {'interface': 'aha', 'group': 'color', 'sub_group': None, 'access': 'rw', 'type': 'num ', 'deprecated': False, 'supported_by_repeater': False, 'description': 'Farbtemperatur (Status und Setzen)'}, 'unmapped_hue': {'interface': 'aha', 'group': 'color', 'sub_group': None, 'access': 'rw', 'type': 'num ', 'deprecated': False, 'supported_by_repeater': False, 'description': 'Hue (Status und Setzen)'}, 'unmapped_saturation': {'interface': 'aha', 'group': 'color', 'sub_group': None, 'access': 'rw', 'type': 'num ', 'deprecated': False, 'supported_by_repeater': False, 'description': 'Saturation (Status und Setzen)'}, + 'color': {'interface': 'aha', 'group': 'color', 'sub_group': None, 'access': 'rw', 'type': 'list ', 'deprecated': False, 'supported_by_repeater': False, 'description': 'Farbwerte als Liste h,s (Status und Setzen)'}, + 'hsv': {'interface': 'aha', 'group': 'color', 'sub_group': None, 'access': 'rw', 'type': 'list ', 'deprecated': False, 'supported_by_repeater': False, 'description': 'Farbwerte und Helligkeit als Liste h,s,v (Status und Setzen)'}, 'color_mode': {'interface': 'aha', 'group': 'color', 'sub_group': None, 'access': 'ro', 'type': 'num ', 'deprecated': False, 'supported_by_repeater': False, 'description': 'Aktueller Farbmodus (1-HueSaturation-Mode; 4-Farbtemperatur-Mode)'}, 'supported_color_mode': {'interface': 'aha', 'group': 'color', 'sub_group': None, 'access': 'ro', 'type': 'num ', 'deprecated': False, 'supported_by_repeater': False, 'description': 'Unterstützer Farbmodus (1-HueSaturation-Mode; 4-Farbtemperatur-Mode)'}, 'fullcolorsupport': {'interface': 'aha', 'group': 'color', 'sub_group': None, 'access': 'ro', 'type': 'bool', 'deprecated': False, 'supported_by_repeater': False, 'description': 'Lampe unterstützt setunmappedcolor'}, @@ -269,7 +273,6 @@ def export_item_attributs_py(): ATTRS['HOMEAUTO_ATTRIBUTES'] = get_attrs(['tr064'], {'group': 'homeauto'}) ATTRS['MYFRITZ_ATTRIBUTES'] = get_attrs(['tr064'], {'group': 'myfritz'}) - # create file and write header f = open(FILENAME_ATTRIBUTES, "w") f.write(FILE_HEADER) @@ -278,7 +281,7 @@ def export_item_attributs_py(): # write avm_data_types for attr, alist in ATTRS.items(): with open(FILENAME_ATTRIBUTES, "a") as f: - print (f'{attr} = {alist!r}', file=f) + print(f'{attr} = {alist!r}', file=f) print(f' {FILENAME_ATTRIBUTES} successfully created!') @@ -381,17 +384,66 @@ def get_all_keys(d): print(f' Check complete.') +def update_user_doc(): + # Update user_doc.rst + print() + print(f'D) Start updating {ATTRIBUTE} and descriptions in {DOC_FILE_NAME}!"') + attribute_list = [ + "\n", + "Dieses Kapitel wurde automatisch durch Ausführen des Skripts in der Datei 'datapoints.py' erstellt.\n", "\n", + "Nachfolgend eine Auflistung der möglichen Attribute für das Plugin:\n", + "\n"] + + for attribute in AVM_DATA_TYPES: + attribute_list.append("\n") + attribute_list.append(f"{attribute.upper()}-Interface\n") + attribute_list.append('^' * (len(attribute) + 10)) + attribute_list.append("\n") + attribute_list.append("\n") + + for avm_data_type in AVM_DATA_TYPES[attribute]: + attribute_list.append(f"- {avm_data_type}: {AVM_DATA_TYPES[attribute][avm_data_type]['description']} " + f"| Zugriff: {AVM_DATA_TYPES[attribute][avm_data_type]['access']} " + f"| Item-Type: {AVM_DATA_TYPES[attribute][avm_data_type]['type']}\n") + attribute_list.append("\n") + + with open(DOC_FILE_NAME, 'r', encoding='utf-8') as file: + lines = file.readlines() + + start = end = None + for i, line in enumerate(lines): + if 'Attribute und Beschreibung' in line: + start = i + if 'item_structs' in line: + end = i + + part1 = lines[0:start+2] + part3 = lines[end-1:len(lines)] + new_lines = part1 + attribute_list + part3 + + with open(DOC_FILE_NAME, 'w', encoding='utf-8') as file: + for line in new_lines: + file.write(line) + + print(f" Successfully updated {ATTRIBUTE} in {DOC_FILE_NAME}!") + if __name__ == '__main__': - # Run main to export item_attributes.py and update ´valid_list and valid_list_description of avm_data_type in plugin.yaml - print() - print(f'Start automated update and check of {FILENAME_PLUGIN} and {FILENAME_ATTRIBUTES}.') + print(f'Start automated update and check of {FILENAME_PLUGIN} with generation of {FILENAME_ATTRIBUTES} and update of {DOC_FILE_NAME}.') print('------------------------------------------------------------------------') + export_item_attributs_py() + update_plugin_yaml_avm_data_type() + check_plugin_yaml_structs() + update_user_doc() + + print() + print(f'Automated update and check of {FILENAME_PLUGIN} and generation of {FILENAME_ATTRIBUTES} complete.') + # Notes: # - HOST_ATTRIBUTES: host index needed # - HOSTS_ATTRIBUTES: no index needed diff --git a/avm/plugin.yaml b/avm/plugin.yaml index eda929418..bdc88c6f0 100644 --- a/avm/plugin.yaml +++ b/avm/plugin.yaml @@ -12,7 +12,7 @@ plugin: documentation: http://smarthomeng.de/user/plugins/avm/user_doc.html support: https://knx-user-forum.de/forum/supportforen/smarthome-py/934835-avm-plugin - version: 2.1.0 # Plugin version (must match the version specified in __init__.py) + version: 2.2.0 # Plugin version (must match the version specified in __init__.py) sh_minversion: 1.8 # minimum shNG version to use this plugin # sh_maxversion: # maximum shNG version to use this plugin (leave empty if latest) # py_minversion: 3.6 # minimum Python version to use for this plugin @@ -259,6 +259,8 @@ item_attributes: - colortemperature # rw num - unmapped_hue # rw num - unmapped_saturation # rw num + - color # rw list + - hsv # rw list - color_mode # ro num - supported_color_mode # ro num - fullcolorsupport # ro bool @@ -434,6 +436,8 @@ item_attributes: - Farbtemperatur (Status und Setzen) - Hue (Status und Setzen) - Saturation (Status und Setzen) + - Farbwerte als Liste h,s (Status und Setzen) + - Farbwerte und Helligkeit als Liste h,s,v (Status und Setzen) - Aktueller Farbmodus (1-HueSaturation-Mode; 4-Farbtemperatur-Mode) - Unterstützer Farbmodus (1-HueSaturation-Mode; 4-Farbtemperatur-Mode) - Lampe unterstützt setunmappedcolor diff --git a/avm/user_doc.rst b/avm/user_doc.rst old mode 100755 new mode 100644 index 551a9ac41..70340456c --- a/avm/user_doc.rst +++ b/avm/user_doc.rst @@ -54,6 +54,326 @@ zu Nichterreichbarkeit des Webservice) führen. Wird ein kürzerer Updatezyklus werden. Dort werden entsprechende Fehlermeldungen hinterlegt. +Attribute und Beschreibung +-------------------------- + +Dieses Kapitel wurde automatisch durch Ausführen des Skripts in der Datei 'datapoints.py' erstellt. + +Nachfolgend eine Auflistung der möglichen Attribute für das Plugin: + + +TR064-Interface +^^^^^^^^^^^^^^^ + +- uptime: Laufzeit des Fritzdevice in Sekunden | Zugriff: ro | Item-Type: num + +- serial_number: Serialnummer des Fritzdevice | Zugriff: ro | Item-Type: str + +- software_version: Software Version | Zugriff: ro | Item-Type: str + +- hardware_version: Hardware Version | Zugriff: ro | Item-Type: str + +- manufacturer: Hersteller | Zugriff: ro | Item-Type: str + +- product_class: Produktklasse | Zugriff: ro | Item-Type: str + +- manufacturer_oui: Hersteller OUI | Zugriff: ro | Item-Type: str + +- model_name: Modellname | Zugriff: ro | Item-Type: str + +- description: Modellbeschreibung | Zugriff: ro | Item-Type: str + +- device_log: Geräte Log | Zugriff: ro | Item-Type: str + +- security_port: Security Port | Zugriff: ro | Item-Type: str + +- reboot: Startet das Gerät neu | Zugriff: wo | Item-Type: bool + +- myfritz_status: MyFritz Status (an/aus) | Zugriff: ro | Item-Type: bool + +- call_direction: Richtung des letzten Anrufes | Zugriff: ro | Item-Type: str + +- call_event: Status des letzten Anrufes | Zugriff: ro | Item-Type: str + +- monitor_trigger: Monitortrigger | Zugriff: ro | Item-Type: bool + +- is_call_incoming: Eingehender Anruf erkannt | Zugriff: ro | Item-Type: bool + +- last_caller_incoming: Letzter Anrufer | Zugriff: ro | Item-Type: str + +- last_call_date_incoming: Zeitpunkt des letzten eingehenden Anrufs | Zugriff: ro | Item-Type: str + +- call_event_incoming: Status des letzten eingehenden Anrufs | Zugriff: ro | Item-Type: str + +- last_number_incoming: Nummer des letzten eingehenden Anrufes | Zugriff: ro | Item-Type: str + +- last_called_number_incoming: Angerufene Nummer des letzten eingehenden Anrufs | Zugriff: ro | Item-Type: str + +- is_call_outgoing: Ausgehender Anruf erkannt | Zugriff: ro | Item-Type: bool + +- last_caller_outgoing: Letzter angerufener Kontakt | Zugriff: ro | Item-Type: str + +- last_call_date_outgoing: Zeitpunkt des letzten ausgehenden Anrufs | Zugriff: ro | Item-Type: str + +- call_event_outgoing: Status des letzten ausgehenden Anrufs | Zugriff: ro | Item-Type: str + +- last_number_outgoing: Nummer des letzten ausgehenden Anrufes | Zugriff: ro | Item-Type: str + +- last_called_number_outgoing: Letzte verwendete Telefonnummer für ausgehenden Anruf | Zugriff: ro | Item-Type: str + +- call_duration_incoming: Dauer des eingehenden Anrufs | Zugriff: ro | Item-Type: num + +- call_duration_outgoing: Dauer des ausgehenden Anrufs | Zugriff: ro | Item-Type: num + +- tam: TAM an/aus | Zugriff: rw | Item-Type: bool + +- tam_name: Name des TAM | Zugriff: ro | Item-Type: str + +- tam_new_message_number: Anzahl der alten Nachrichten | Zugriff: ro | Item-Type: num + +- tam_old_message_number: Anzahl der neuen Nachrichten | Zugriff: ro | Item-Type: num + +- tam_total_message_number: Gesamtanzahl der Nachrichten | Zugriff: ro | Item-Type: num + +- wan_connection_status: WAN Verbindungsstatus | Zugriff: ro | Item-Type: str + +- wan_connection_error: WAN Verbindungsfehler | Zugriff: ro | Item-Type: str + +- wan_is_connected: WAN Verbindung aktiv | Zugriff: ro | Item-Type: bool + +- wan_uptime: WAN Verbindungszeit | Zugriff: ro | Item-Type: str + +- wan_ip: WAN IP Adresse | Zugriff: ro | Item-Type: str + +- wan_upstream: WAN Upstream Datenmenge | Zugriff: ro | Item-Type: num + +- wan_downstream: WAN Downstream Datenmenge | Zugriff: ro | Item-Type: num + +- wan_total_packets_sent: WAN Verbindung-Anzahl insgesamt versendeter Pakete | Zugriff: ro | Item-Type: num + +- wan_total_packets_received: WAN Verbindung-Anzahl insgesamt empfangener Pakete | Zugriff: ro | Item-Type: num + +- wan_current_packets_sent: WAN Verbindung-Anzahl aktuell versendeter Pakete | Zugriff: ro | Item-Type: num + +- wan_current_packets_received: WAN Verbindung-Anzahl aktuell empfangener Pakete | Zugriff: ro | Item-Type: num + +- wan_total_bytes_sent: WAN Verbindung-Anzahl insgesamt versendeter Bytes | Zugriff: ro | Item-Type: num + +- wan_total_bytes_received: WAN Verbindung-Anzahl insgesamt empfangener Bytes | Zugriff: ro | Item-Type: num + +- wan_current_bytes_sent: WAN Verbindung-Anzahl aktuelle Bitrate Senden | Zugriff: ro | Item-Type: num + +- wan_current_bytes_received: WAN Verbindung-Anzahl aktuelle Bitrate Empfangen | Zugriff: ro | Item-Type: num + +- wan_link: WAN Link | Zugriff: ro | Item-Type: bool + +- wlanconfig: WLAN An/Aus | Zugriff: rw | Item-Type: bool + +- wlanconfig_ssid: WLAN SSID | Zugriff: ro | Item-Type: str + +- wlan_guest_time_remaining: Verbleibende Zeit, bis zum automatischen Abschalten des Gäste-WLAN | Zugriff: ro | Item-Type: num + +- wlan_associates: Anzahl der verbundenen Geräte im jeweiligen WLAN | Zugriff: ro | Item-Type: num + +- wps_active: Schaltet WPS für das entsprechende WlAN an / aus | Zugriff: rw | Item-Type: bool + +- wps_status: WPS Status des entsprechenden WlAN | Zugriff: ro | Item-Type: str + +- wps_mode: WPS Modus des entsprechenden WlAN | Zugriff: ro | Item-Type: str + +- wlan_total_associates: Anzahl der verbundenen Geräte im WLAN | Zugriff: ro | Item-Type: num + +- hosts_count: Anzahl der Hosts | Zugriff: ro | Item-Type: num + +- hosts_info: Informationen über die Hosts | Zugriff: ro | Item-Type: dict + +- mesh_topology: Topologie des Mesh | Zugriff: ro | Item-Type: dict + +- number_of_hosts: Anzahl der verbundenen Hosts (Muss Child von "network_device" sein) | Zugriff: ro | Item-Type: num + +- hosts_url: URL zu Hosts (Muss Child von "network_device" sein) | Zugriff: ro | Item-Type: str + +- mesh_url: URL zum Mesh (Muss Child von "network_device" sein) | Zugriff: ro | Item-Type: str + +- network_device: Verbindungsstatus des Gerätes // Defines Network device via MAC-Adresse | Zugriff: ro | Item-Type: bool + +- device_ip: Geräte-IP (Muss Child von "network_device" sein) | Zugriff: ro | Item-Type: str + +- device_connection_type: Verbindungstyp (Muss Child von "network_device" sein) | Zugriff: ro | Item-Type: str + +- device_hostname: Gerätename (Muss Child von "network_device" sein | Zugriff: ro | Item-Type: str + +- connection_status: Verbindungsstatus (Muss Child von "network_device" sein) | Zugriff: ro | Item-Type: bool + +- is_host_active: Host aktiv? (Muss Child von "network_device" sein) | Zugriff: ro | Item-Type: bool + +- host_info: Informationen zum Host (Muss Child von "network_device" sein) | Zugriff: ro | Item-Type: str + +- number_of_deflections: Anzahl der eingestellten Rufumleitungen | Zugriff: ro | Item-Type: num + +- deflections_details: Details zu allen Rufumleitung (als dict) | Zugriff: ro | Item-Type: dict + +- deflection_details: Details zur Rufumleitung (als dict); Angabe der Rufumleitung mit Parameter "avm_deflection_index" im Item | Zugriff: ro | Item-Type: dict + +- deflection_enable: Rufumleitung Status an/aus; Angabe der Rufumleitung mit Parameter "avm_deflection_index" im Item bzw Parent-Item | Zugriff: rw | Item-Type: bool + +- deflection_type: Type der Rufumleitung; Angabe der Rufumleitung mit Parameter "avm_deflection_index" im Item bzw Parent-Item | Zugriff: ro | Item-Type: str + +- deflection_number: Telefonnummer, die umgeleitet wird; Angabe der Rufumleitung mit Parameter "avm_deflection_index" im Item bzw Parent-Item | Zugriff: ro | Item-Type: str + +- deflection_to_number: Zielrufnummer der Umleitung; Angabe der Rufumleitung mit Parameter "avm_deflection_index" im Item bzw Parent-Item | Zugriff: ro | Item-Type: str + +- deflection_mode: Modus der Rufumleitung; Angabe der Rufumleitung mit Parameter "avm_deflection_index" im Item bzw Parent-Item | Zugriff: ro | Item-Type: str + +- deflection_outgoing: Outgoing der Rufumleitung; Angabe der Rufumleitung mit Parameter "avm_deflection_index" im Item bzw Parent-Item | Zugriff: ro | Item-Type: str + +- deflection_phonebook_id: Phonebook_ID der Zielrufnummer (Only valid if Type==fromPB); Angabe der Rufumleitung mit Parameter "avm_deflection_index" im Item bzw Parent-Item | Zugriff: ro | Item-Type: str + +- aha_device: Steckdose schalten; siehe "switch_state" | Zugriff: rw | Item-Type: bool + +- hkr_device: Status des HKR (OPEN; CLOSED; TEMP) | Zugriff: ro | Item-Type: str + +- set_temperature: siehe "target_temperature" | Zugriff: ro | Item-Type: num + +- temperature: siehe "current_temperature" | Zugriff: ro | Item-Type: num + +- set_temperature_reduced: siehe "temperature_reduced" | Zugriff: ro | Item-Type: num + +- set_temperature_comfort: siehe "temperature_comfort" | Zugriff: ro | Item-Type: num + +- firmware_version: siehe "fw_version" | Zugriff: ro | Item-Type: str + + +AHA-Interface +^^^^^^^^^^^^^ + +- device_id: Geräte -ID | Zugriff: ro | Item-Type: str + +- manufacturer: Hersteller | Zugriff: ro | Item-Type: str + +- product_name: Produktname | Zugriff: ro | Item-Type: str + +- fw_version: Firmware Version | Zugriff: ro | Item-Type: str + +- connected: Verbindungsstatus | Zugriff: ro | Item-Type: bool + +- device_name: Gerätename | Zugriff: ro | Item-Type: str + +- tx_busy: Verbindung aktiv | Zugriff: ro | Item-Type: bool + +- device_functions: Im Gerät vorhandene Funktionen | Zugriff: ro | Item-Type: list + +- set_target_temperature: Soll-Temperatur Setzen | Zugriff: wo | Item-Type: num + +- target_temperature: Soll-Temperatur (Status und Setzen) | Zugriff: rw | Item-Type: num + +- current_temperature: Ist-Temperatur | Zugriff: ro | Item-Type: num + +- temperature_reduced: Eingestellte reduzierte Temperatur | Zugriff: ro | Item-Type: num + +- temperature_comfort: Eingestellte Komfort-Temperatur | Zugriff: ro | Item-Type: num + +- temperature_offset: Eingestellter Temperatur-Offset | Zugriff: ro | Item-Type: num + +- set_window_open: Window-Open-Funktion (Setzen) | Zugriff: wo | Item-Type: bool + +- window_open: Window-Open-Funktion (Status und Setzen) | Zugriff: rw | Item-Type: bool + +- windowopenactiveendtime: Zeitliches Ende der "Window Open" Funktion | Zugriff: ro | Item-Type: num + +- set_hkr_boost: Boost-Funktion (Setzen) | Zugriff: wo | Item-Type: bool + +- hkr_boost: Boost-Funktion (Status und Setzen) | Zugriff: rw | Item-Type: bool + +- boost_active: Status der "Boost" Funktion | Zugriff: ro | Item-Type: bool + +- boostactiveendtime: Zeitliches Ende der Boost Funktion | Zugriff: ro | Item-Type: num + +- summer_active: Status der "Sommer" Funktion | Zugriff: ro | Item-Type: bool + +- holiday_active: Status der "Holiday" Funktion | Zugriff: ro | Item-Type: bool + +- battery_low: Battery-low Status | Zugriff: ro | Item-Type: bool + +- battery_level: Batterie-Status in % | Zugriff: ro | Item-Type: num + +- lock: Tastensperre über UI/API aktiv | Zugriff: ro | Item-Type: bool + +- device_lock: Tastensperre direkt am Gerät ein | Zugriff: ro | Item-Type: bool + +- errorcode: Fehlercodes die der HKR liefert | Zugriff: ro | Item-Type: num + +- set_simpleonoff: Gerät/Aktor/Lampe an-/ausschalten | Zugriff: wo | Item-Type: bool + +- simpleonoff: Gerät/Aktor/Lampe (Status und Setzen) | Zugriff: rw | Item-Type: bool + +- set_level: Level/Niveau von 0 bis 255 (Setzen) | Zugriff: wo | Item-Type: num + +- level: Level/Niveau von 0 bis 255 (Setzen & Status) | Zugriff: rw | Item-Type: num + +- set_levelpercentage: Level/Niveau von 0% bis 100% (Setzen) | Zugriff: wo | Item-Type: num + +- levelpercentage: Level/Niveau von 0% bis 100% (Setzen & Status) | Zugriff: rw | Item-Type: num + +- set_hue: Hue (Setzen) | Zugriff: wo | Item-Type: num + +- hue: Hue (Status und Setzen) | Zugriff: rw | Item-Type: num + +- set_saturation: Saturation (Setzen) | Zugriff: wo | Item-Type: num + +- saturation: Saturation (Status und Setzen) | Zugriff: rw | Item-Type: num + +- set_colortemperature: Farbtemperatur (Setzen) | Zugriff: wo | Item-Type: num + +- colortemperature: Farbtemperatur (Status und Setzen) | Zugriff: rw | Item-Type: num + +- unmapped_hue: Hue (Status und Setzen) | Zugriff: rw | Item-Type: num + +- unmapped_saturation: Saturation (Status und Setzen) | Zugriff: rw | Item-Type: num + +- color: Farbwerte als Liste h,s (Status und Setzen) | Zugriff: rw | Item-Type: list + +- hsv: Farbwerte und Helligkeit als Liste h,s,v (Status und Setzen) | Zugriff: rw | Item-Type: list + +- color_mode: Aktueller Farbmodus (1-HueSaturation-Mode; 4-Farbtemperatur-Mode) | Zugriff: ro | Item-Type: num + +- supported_color_mode: Unterstützer Farbmodus (1-HueSaturation-Mode; 4-Farbtemperatur-Mode) | Zugriff: ro | Item-Type: num + +- fullcolorsupport: Lampe unterstützt setunmappedcolor | Zugriff: ro | Item-Type: bool + +- mapped: von den Colordefaults abweichend zugeordneter HueSaturation-Wert gesetzt | Zugriff: ro | Item-Type: bool + +- switch_state: Schaltzustand Steckdose (Status und Setzen) | Zugriff: rw | Item-Type: bool + +- switch_mode: Zeitschaltung oder manuell schalten | Zugriff: ro | Item-Type: str + +- switch_toggle: Schaltzustand umschalten (toggle) | Zugriff: wo | Item-Type: bool + +- power: Leistung in W (Aktualisierung alle 2 min) | Zugriff: ro | Item-Type: num + +- energy: absoluter Verbrauch seit Inbetriebnahme in Wh | Zugriff: ro | Item-Type: num + +- voltage: Spannung in V (Aktualisierung alle 2 min) | Zugriff: ro | Item-Type: num + +- humidity: Relative Luftfeuchtigkeit in % (FD440) | Zugriff: ro | Item-Type: num + +- alert_state: letzter übermittelter Alarmzustand | Zugriff: ro | Item-Type: bool + +- blind_mode: automatische Zeitschaltung oder manuell fahren | Zugriff: ro | Item-Type: str + +- endpositionsset: ist die Endlage für das Rollo konfiguriert | Zugriff: ro | Item-Type: bool + +- statistics_temp: Wertestatistik für Temperatur | Zugriff: ro | Item-Type: list + +- statistics_hum: Wertestatistik für Feuchtigkeit | Zugriff: ro | Item-Type: list + +- statistics_voltage: Wertestatistik für Spannung | Zugriff: ro | Item-Type: list + +- statistics_power: Wertestatistik für Leistung | Zugriff: ro | Item-Type: list + +- statistics_energy: Wertestatistik für Energie | Zugriff: ro | Item-Type: list + + item_structs ------------ Zur Vereinfachung der Einrichtung von Items sind für folgende Item-structs vordefiniert: From 3b158f9d372e04ee274472f1d01ea298b04ca84c Mon Sep 17 00:00:00 2001 From: Onkel Andy Date: Sat, 2 Sep 2023 02:16:27 +0200 Subject: [PATCH 002/147] stateengine plugin: fix force action --- stateengine/StateEngineAction.py | 1 + 1 file changed, 1 insertion(+) diff --git a/stateengine/StateEngineAction.py b/stateengine/StateEngineAction.py index 407957ffa..8f439103a 100755 --- a/stateengine/StateEngineAction.py +++ b/stateengine/StateEngineAction.py @@ -830,6 +830,7 @@ class SeActionForceItem(SeActionBase): def __init__(self, abitem, name: str): super().__init__(abitem, name) self.__item = None + self.__status = None self.__value = StateEngineValue.SeValue(self._abitem, "value") self.__mindelta = StateEngineValue.SeValue(self._abitem, "mindelta") self.__function = "force set" From 7b6e831a8b35e1aca85da6334de4d20528ff95f3 Mon Sep 17 00:00:00 2001 From: Onkel Andy Date: Sat, 2 Sep 2023 02:21:43 +0200 Subject: [PATCH 003/147] stateengine plugin: fix exception when using separate action attributes (previously introduced issue) --- stateengine/StateEngineActions.py | 49 ++++++++++++++++++------------- stateengine/StateEngineItem.py | 9 +++++- stateengine/StateEngineState.py | 22 ++++++++++++-- 3 files changed, 57 insertions(+), 23 deletions(-) diff --git a/stateengine/StateEngineActions.py b/stateengine/StateEngineActions.py index 5e134b467..2d1e4d6c5 100755 --- a/stateengine/StateEngineActions.py +++ b/stateengine/StateEngineActions.py @@ -83,75 +83,84 @@ def update(self, attribute, value): # If we do not have the action yet (delay-attribute before action-attribute), ... self.__unassigned_delays[name] = value else: - self.__actions[name].update_delay(value) - return + _issue = self.__actions[name].update_delay(value) + return _count, _issue elif func == "se_instanteval": # set instant calculation if name not in self.__actions: # If we do not have the action yet (repeat-attribute before action-attribute), ... self.__unassigned_instantevals[name] = value else: - self.__actions[name].update_instanteval(value) - return + _issue = self.__actions[name].update_instanteval(value) + return _count, _issue elif func == "se_repeat": # set repeat if name not in self.__actions: # If we do not have the action yet (repeat-attribute before action-attribute), ... self.__unassigned_repeats[name] = value else: - self.__actions[name].update_repeat(value) - return + _issue = self.__actions[name].update_repeat(value) + return _count, _issue elif func == "se_conditionset": # set conditionset if name not in self.__actions: # If we do not have the action yet (conditionset-attribute before action-attribute), ... self.__unassigned_conditionsets[name] = value else: - self.__actions[name].update_conditionsets(value) - return + _issue = self.__actions[name].update_conditionset(value) + return _count, _issue elif func == "se_previousconditionset": # set conditionset if name not in self.__actions: # If we do not have the action yet (conditionset-attribute before action-attribute), ... self.__unassigned_previousconditionsets[name] = value else: - self.__actions[name].update_previousconditionsets(value) - return + _issue = self.__actions[name].update_previousconditionset(value) + return _count, _issue elif func == "se_previousstate_conditionset": # set conditionset if name not in self.__actions: # If we do not have the action yet (conditionset-attribute before action-attribute), ... self.__unassigned_previousstate_conditionsets[name] = value else: - self.__actions[name].update_previousstate_conditionsets(value) - return + _issue = self.__actions[name].update_previousstate_conditionset(value) + return _count, _issue elif func == "se_mode": # set remove mode + _issue_list = [] if name not in self.__actions: # If we do not have the action yet (mode-attribute before action-attribute), ... self.__unassigned_modes[name] = value else: self.__actions[name].update_modes(value) - return + return _count, _issue_list elif func == "se_order": # set order if name not in self.__actions: # If we do not have the action yet (order-attribute before action-attribute), ... self.__unassigned_orders[name] = value else: - self.__actions[name].update_order(value) - return + _issue = self.__actions[name].update_order(value) + return _count, _issue elif func == "se_action": # and name not in self.__actions: _issue = self.__handle_combined_action_attribute(name, value) _count += 1 - elif self.__ensure_action_exists(func, name): - # update action - _issue = self.__actions[name].update(value) - _count += 1 + else: + _issue_list = [] + _ensure_action, _issue = self.__ensure_action_exists(func, name) + if _issue: + _issue_list.append(_issue) + if _ensure_action: + # update action + _issue = self.__actions[name].update(value) + if _issue: + _issue_list.append(_issue) + _count += 1 + _issue = StateEngineTools.flatten_list(_issue_list) except ValueError as ex: if name in self.__actions: del self.__actions[name] - _issue = {name: {'issue': ex, 'issueorigin': [{'state': 'unknown', 'action': 'unknown'}]}} + _issue = {name: {'issue': ex, 'issueorigin': [{'state': 'unknown', 'action': self.__actions[name].function}]}} self._log_warning("Ignoring action {0} because: {1}", attribute, ex) return _count, _issue diff --git a/stateengine/StateEngineItem.py b/stateengine/StateEngineItem.py index 3cd77f8f7..a933d6d18 100755 --- a/stateengine/StateEngineItem.py +++ b/stateengine/StateEngineItem.py @@ -750,6 +750,9 @@ def __update_can_release(self, can_release, new_state=None): def __handle_releasedby(self, new_state, last_state): def update_can_release_list(): for e in _returnvalue: + if isinstance(e, list): + self.__logger.warning("Entry {} should not be list. Please check!", e) + e = e[0] e = self.__update_release_item_value(e, new_state) if e and state.id not in can_release.setdefault(e, [state.id]): can_release[e].append(state.id) @@ -882,7 +885,11 @@ def combine_dicts(dict1, dict2): for key, value in dict2.items(): if key in combined_dict: - combined_dict[key]['issueorigin'].extend(value['issueorigin']) + for k, v in combined_dict.items(): + v['issueorigin'].extend( + [item for item in v['issueorigin'] if item not in combined_dict[k]['issueorigin']]) + v['issue'].extend([item for item in v['issue'] if item not in combined_dict[k]['issue']]) + else: combined_dict[key] = value diff --git a/stateengine/StateEngineState.py b/stateengine/StateEngineState.py index e665a0788..bc01ced1a 100755 --- a/stateengine/StateEngineState.py +++ b/stateengine/StateEngineState.py @@ -362,7 +362,12 @@ def update_unused(used_attributes, type, name): def update_action_status(action_status, actiontype): if action_status is None: return - + action_status = StateEngineTools.flatten_list(action_status) + #self._log_debug("Action status: {}", action_status) + if isinstance(action_status, list): + for e in action_status: + update_action_status(e, actiontype) + return for itm, dct in action_status.items(): if itm not in self.__action_status: self.__action_status.update({itm: dct}) @@ -370,6 +375,9 @@ def update_action_status(action_status, actiontype): for (itm, dct) in action_status.items(): issues = dct.get('issue') if issues: + if isinstance(issues, list): + self.__action_status[itm]['issue'].extend( + [issue for issue in issues if issue not in self.__action_status[itm]['issue']]) origin_list = self.__action_status[itm].get('issueorigin', []) new_list = origin_list.copy() for i, listitem in enumerate(origin_list): @@ -392,7 +400,8 @@ def update_action_status(action_status, actiontype): filtered_dict[key].update(nested_dict) #self._log_develop("Add {} to used {}", key, filtered_dict) self.__used_attributes = copy(filtered_dict) - filtered_dict = {key: value for key, value in self.__action_status.items() if value.get('issue') not in [[], None]} + filtered_dict = {key: value for key, value in self.__action_status.items() + if value.get('issue') not in [[], [None], None]} self.__action_status = filtered_dict #self._log_develop("Updated action status: {}, updated used {}", self.__action_status, self.__used_attributes) @@ -523,6 +532,7 @@ def update_action_status(action_status, actiontype): _, _action_status = self.__actions_enter.update(attribute, child_item.conf[attribute]) if _action_status: update_action_status(_action_status, 'enter') + self._abitem.update_action_status(self.__action_status) update_unused(_used_attributes, 'action', child_name) elif child_name == "on_stay": _actioncount += 1 @@ -531,6 +541,7 @@ def update_action_status(action_status, actiontype): _, _action_status = self.__actions_stay.update(attribute, child_item.conf[attribute]) if _action_status: update_action_status(_action_status, 'stay') + self._abitem.update_action_status(self.__action_status) update_unused(_used_attributes, 'action', child_name) elif child_name == "on_enter_or_stay": _actioncount += 1 @@ -539,6 +550,7 @@ def update_action_status(action_status, actiontype): _, _action_status = self.__actions_enter_or_stay.update(attribute, child_item.conf[attribute]) if _action_status: update_action_status(_action_status, 'enter_or_stay') + self._abitem.update_action_status(self.__action_status) update_unused(_used_attributes, 'action', child_name) elif child_name == "on_leave": _actioncount += 1 @@ -547,6 +559,7 @@ def update_action_status(action_status, actiontype): _, _action_status = self.__actions_leave.update(attribute, child_item.conf[attribute]) if _action_status: update_action_status(_action_status, 'leave') + self._abitem.update_action_status(self.__action_status) update_unused(_used_attributes, 'action', child_name) except ValueError as ex: raise ValueError("Condition {0} check for actions error: {1}".format(child_name, ex)) @@ -558,6 +571,7 @@ def update_action_status(action_status, actiontype): _action_status = _result[1] if _action_status: update_action_status(_action_status, 'enter_or_stay') + self._abitem.update_action_status(self.__action_status) _total_actioncount = _enter_actioncount + _stay_actioncount + _enter_stay_actioncount + _leave_actioncount @@ -568,15 +582,19 @@ def update_action_status(action_status, actiontype): _action_status = self.__actions_enter.complete(item_state, self.__conditions.evals_items) if _action_status: update_action_status(_action_status, 'enter') + self._abitem.update_action_status(self.__action_status) _action_status = self.__actions_stay.complete(item_state, self.__conditions.evals_items) if _action_status: update_action_status(_action_status, 'stay') + self._abitem.update_action_status(self.__action_status) _action_status = self.__actions_enter_or_stay.complete(item_state, self.__conditions.evals_items) if _action_status: update_action_status(_action_status, 'enter_or_stay') + self._abitem.update_action_status(self.__action_status) _action_status = self.__actions_leave.complete(item_state, self.__conditions.evals_items) if _action_status: update_action_status(_action_status, 'leave') + self._abitem.update_action_status(self.__action_status) self._abitem.update_action_status(self.__action_status) self._abitem.update_attributes(self.__unused_attributes, self.__used_attributes) _summary = "{} on_enter, {} on_stay , {} on_enter_or_stay, {} on_leave" From 7bb1b8099253e264ffb15a499f65d1c2625b7a5f Mon Sep 17 00:00:00 2001 From: msinn Date: Sat, 2 Sep 2023 15:38:27 +0200 Subject: [PATCH 004/147] piratewthr: Ignoring responses from pirateweather, if units in response don't match units from request; Bumped to v1.2.5 --- piratewthr/__init__.py | 20 ++++++++++++++------ piratewthr/plugin.yaml | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/piratewthr/__init__.py b/piratewthr/__init__.py index 76cffe812..7d2f36e65 100755 --- a/piratewthr/__init__.py +++ b/piratewthr/__init__.py @@ -37,7 +37,7 @@ class PirateWeather(SmartPlugin): - PLUGIN_VERSION = "1.2.3" + PLUGIN_VERSION = "1.2.5" # https://api.pirateweather.net/forecast/[apikey]/[latitude],[longitude] _base_url = 'https://api.pirateweather.net/forecast/' @@ -203,10 +203,11 @@ def get_forecast(self): """ Requests the forecast information at pirateweather.net """ - self.logger.info(f"get_forecast: url={self._build_url()}") + url_to_send = self._build_url() + self.logger.info(f"get_forecast: url={url_to_send}") json_obj = None try: - response = self._session.get(self._build_url()) + response = self._session.get(url_to_send) except Exception as e: self.logger.warning(f"get_forecast: Exception when sending GET request: {e}") return @@ -221,9 +222,16 @@ def get_forecast(self): self.logger.warning(f"api.pirateweather.net: {self.get_http_response(response.status_code)} - Ignoring response.") return - if json_obj['currently']['temperature'] > 45: - # Log data, if receiving data in imperial units - self.logger.notice(f"Data in imperial units?: {json_obj}") + if json_obj['flags']['units'].lower() != self._units.lower(): + # Log data, if receiving data in other format than the requested units + self.logger.notice(f"get_forecast: url sent={url_to_send}") + self.logger.notice(f"get_forecast: Ignoring data in other units than requested: {json_obj}") + return + + # if json_obj['currently']['temperature'] > 45: + # # Log data, if receiving data in imperial units + # self.logger.notice(f"get_forecast: url sent={url_to_send}") + # self.logger.notice(f"get_forecast: Data in imperial units?: {json_obj}") daily_data = OrderedDict() if not json_obj.get('daily', False): diff --git a/piratewthr/plugin.yaml b/piratewthr/plugin.yaml index 952831259..571a4843e 100755 --- a/piratewthr/plugin.yaml +++ b/piratewthr/plugin.yaml @@ -11,7 +11,7 @@ plugin: keywords: weather sun wind rain precipitation #documentation: '' support: 'https://knx-user-forum.de/forum/supportforen/smarthome-py/1852685' - version: 1.2.3 # Plugin version + version: 1.2.5 # Plugin version sh_minversion: 1.9.5.4 # minimum shNG version to use this plugin #sh_maxversion: # maximum shNG version to use this plugin (leave empty if latest) multi_instance: True # plugin supports multi instance From 5566952eceb11e9010f7f7d6fca75cc3eb678586 Mon Sep 17 00:00:00 2001 From: lgb-this Date: Mon, 4 Sep 2023 12:13:53 +0200 Subject: [PATCH 005/147] PNG replaces JPG --- byd_bat/webif/static/img/diag.png | Bin 0 -> 199480 bytes byd_bat/webif/static/img/home.png | Bin 0 -> 355439 bytes byd_bat/webif/static/img/temp.png | Bin 0 -> 226750 bytes byd_bat/webif/static/img/volt.png | Bin 0 -> 475568 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 byd_bat/webif/static/img/diag.png create mode 100644 byd_bat/webif/static/img/home.png create mode 100644 byd_bat/webif/static/img/temp.png create mode 100644 byd_bat/webif/static/img/volt.png diff --git a/byd_bat/webif/static/img/diag.png b/byd_bat/webif/static/img/diag.png new file mode 100644 index 0000000000000000000000000000000000000000..829475694634baa66de78329af5f3ff90310ab8e GIT binary patch literal 199480 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�ez8qNWsC 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

V)@ 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