From d162d718ea398cd65cb493fb4bc81be694997bbf Mon Sep 17 00:00:00 2001 From: gyro-labs <96442881+gyro-labs@users.noreply.github.com> Date: Tue, 28 Mar 2023 15:46:48 +0200 Subject: [PATCH 1/4] Update config.json --- hassio/config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hassio/config.json b/hassio/config.json index ddaab6d..09b66ca 100644 --- a/hassio/config.json +++ b/hassio/config.json @@ -1,9 +1,9 @@ { - "name": "HiSense Air Conditioners", + "name": "HiSense Air Conditioners (edit)", "version": "0.3.13", "slug": "hisense_ac", "description": "Interface for controlling Air Conditioners, e.g. with HiSense modules.", - "url": "https://github.com/deiger/AirCon", + "url": "https://github.com/gyro-labs/AirCon", "image": "deiger/aircon", "arch": ["armhf", "armv7", "aarch64", "amd64", "i386"], "startup": "application", From 345f18c1c6fa7946670b9b136a027d1921a3a714 Mon Sep 17 00:00:00 2001 From: gyro-labs <96442881+gyro-labs@users.noreply.github.com> Date: Tue, 28 Mar 2023 15:49:01 +0200 Subject: [PATCH 2/4] Update repository.json --- repository.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/repository.json b/repository.json index 8b470e1..34a732f 100644 --- a/repository.json +++ b/repository.json @@ -1,5 +1,5 @@ { - "name": "Home Assistant Add-on: HiSense Air Conditioners", - "url": "https://github.com/deiger/AirCon", - "maintainer": "Dror Eiger " + "name": "Home Assistant Add-on (edit): HiSense Air Conditioners", + "url": "https://github.com/gyro-labs/AirCon", + "maintainer": "Martijn Ruijzendaal " } From ae7537022b617ae4a162fd7bafabb9dc99b8e859 Mon Sep 17 00:00:00 2001 From: Martijn Ruijzendaal Date: Fri, 7 Apr 2023 16:09:28 +0200 Subject: [PATCH 3/4] Implement `display temperature` for FGL devices; Add some debug logging. --- aircon/__main__.py | 3 +++ aircon/aircon.py | 11 +++++++++-- aircon/mqtt_client.py | 6 ++++-- aircon/properties.py | 26 ++++++++++++++++++++++++++ aircon/query_handlers.py | 5 +++-- 5 files changed, 45 insertions(+), 6 deletions(-) diff --git a/aircon/__main__.py b/aircon/__main__.py index 2d0d0e2..0831c98 100644 --- a/aircon/__main__.py +++ b/aircon/__main__.py @@ -243,6 +243,9 @@ async def run(parsed_args): topics['temp']) config['max_temp'] = '86' if device.is_fahrenheit else '30' config['min_temp'] = '61' if device.is_fahrenheit else '16' + if 'display_temperature' in topics: + config['display_temperature_state_topic'] = mqtt_topics['pub'].format(device.mac_address, + topics['display_temperature']) mqtt_client.publish(mqtt_topics['discovery'].format(device.mac_address), payload=json.dumps(config), retain=True) diff --git a/aircon/aircon.py b/aircon/aircon.py index 855c825..48d5712 100644 --- a/aircon/aircon.py +++ b/aircon/aircon.py @@ -111,6 +111,9 @@ def get_property(self, name: str): def get_property_type(self, name: str): return self._properties.get_type(name) + def parse_property(self, name: str, value): + return self._properties.parse_attr(name, value) + def update_property(self, name: str, value, notify_value=None) -> None: """Update the stored properties, if changed.""" # Update value precision for value sent from the A/C @@ -123,11 +126,13 @@ def update_property(self, name: str, value, notify_value=None) -> None: with self._properties_lock: old_value = getattr(self._properties, name) + logging.debug(f"Updating {self}.{name} to {value}") if value != old_value: setattr(self._properties, name, value) # logging.debug('Updated properties: %s' % self._properties) if name == 't_control_value': self._update_controlled_properties(value) + logging.debug(f"Updated {self}.{name} to {getattr(self._properties, name)}") self._notify_listeners(name, notify_value) def _update_controlled_properties(self, control: int): @@ -546,7 +551,8 @@ def __init__(self, config: Dict[str, str], notifier: Callable[[None], None]): 'fan_speed': 'fan_speed', 'work_mode': 'operation_mode', 'swing_mode': 'af_vertical_swing', - 'temp': 'adjust_temperature' + 'temp': 'adjust_temperature', + 'display_temperature': 'display_temperature', } self.work_modes = ['off', 'fan_only', 'heat', 'cool', 'dry', 'auto'] self.fan_modes = ['auto', 'quiet', 'low', 'medium', 'high'] @@ -559,7 +565,8 @@ def __init__(self, config: Dict[str, str], notifier: Callable[[None], None]): self.topics = { 'fan_speed': 'fan_speed', 'work_mode': 'operation_mode', - 'temp': 'adjust_temperature' + 'temp': 'adjust_temperature', + 'display_temperature': 'display_temperature', } self.work_modes = ['off', 'fan_only', 'heat', 'cool', 'dry', 'auto'] self.fan_modes = ['auto', 'quiet', 'low', 'medium', 'high'] diff --git a/aircon/mqtt_client.py b/aircon/mqtt_client.py index 0e74ff7..5fd9a9d 100644 --- a/aircon/mqtt_client.py +++ b/aircon/mqtt_client.py @@ -19,8 +19,10 @@ def __init__(self, client_id: str, mqtt_topics: dict, devices: [Device]): def mqtt_on_connect(self, client: mqtt.Client, userdata, flags, rc): for device in self._devices: - client.subscribe([(self._mqtt_topics['sub'].format(device.mac_address, data_field.name), 0) - for data_field in fields(device.get_all_properties())]) + topics_fmt = [(self._mqtt_topics['sub'].format(device.mac_address, data_field.name), 0) + for data_field in fields(device.get_all_properties())] + logging.debug(f"Subscribing to topics{topics_fmt} for device {device}") + client.subscribe(topics_fmt) # Subscribe to subscription updates. client.subscribe('$SYS/broker/log/M/subscribe/#') diff --git a/aircon/properties.py b/aircon/properties.py index 278fdec..39dbb7d 100644 --- a/aircon/properties.py +++ b/aircon/properties.py @@ -147,6 +147,20 @@ def _get_metadata(cls, attr: str): def get_type(cls, attr: str): return cls.__dataclass_fields__[attr].type + @classmethod + def parse_attr(cls, attr, value): + """If a field supplies a parser function in its metadata, use it to parse its value from the raw data.""" + # Retrieve the desired type from the class attribute type hinting + native_type = cls.__dataclass_fields__[attr].type + value_fmt = native_type(value) + + # Detect parser for this attribute + parser = cls.__dataclass_fields__[attr].metadata.get('parser') + if parser: + value_fmt = parser(value) + + return value_fmt + @classmethod def get_base_type(cls, attr: str): return cls._get_metadata(attr)['base_type'] @@ -406,6 +420,12 @@ class FglProperties(Properties): 'precision': 0.1, 'read_only': False }) + display_temperature: float = field(default=25, + metadata={ + 'base_type': 'integer', + 'read_only': True, + 'parser': lambda x: round((x-5000)/50)/2, + }) af_vertical_direction: int = field(default=3, metadata={ 'base_type': 'integer', @@ -472,6 +492,12 @@ class FglBProperties(Properties): 'precision': 0.1, 'read_only': False }) + display_temperature: float = field(default=25, + metadata={ + 'base_type': 'float', + 'read_only': True, + 'parser': lambda x: round((x-5000)/50)/2, + }) af_vertical_move_step1: int = field(default=3, metadata={ 'base_type': 'integer', diff --git a/aircon/query_handlers.py b/aircon/query_handlers.py index da4cbed..34d08ad 100644 --- a/aircon/query_handlers.py +++ b/aircon/query_handlers.py @@ -85,9 +85,10 @@ async def property_update_handler(self, request: web.Request) -> web.Response: # Fix A/C typos. if name == 'f_votage': name = 'f_voltage' - data_type = device.get_property_type(name) - value = data_type(update['data']['value']) + value = device.parse_property(name, update['data']['value']) + logging.debug(f"Updating {device}.{name} to {value} ({update['data']['value']})") device.update_property(name, value) + logging.debug(f"Updated{device}: {device.get_all_properties()})") except Exception as ex: logging.error('Failed to handle {}. Exception = {}'.format(update, ex)) #TODO: Should return internal error? From f0299e34aab9a09bd0362b659e5ea63042c95357 Mon Sep 17 00:00:00 2001 From: Martijn Ruijzendaal Date: Fri, 7 Apr 2023 16:21:10 +0200 Subject: [PATCH 4/4] Merge with dreiger/AirCon --- hassio/config.json | 4 ++-- repository.json | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hassio/config.json b/hassio/config.json index 09b66ca..ddaab6d 100644 --- a/hassio/config.json +++ b/hassio/config.json @@ -1,9 +1,9 @@ { - "name": "HiSense Air Conditioners (edit)", + "name": "HiSense Air Conditioners", "version": "0.3.13", "slug": "hisense_ac", "description": "Interface for controlling Air Conditioners, e.g. with HiSense modules.", - "url": "https://github.com/gyro-labs/AirCon", + "url": "https://github.com/deiger/AirCon", "image": "deiger/aircon", "arch": ["armhf", "armv7", "aarch64", "amd64", "i386"], "startup": "application", diff --git a/repository.json b/repository.json index 34a732f..8b470e1 100644 --- a/repository.json +++ b/repository.json @@ -1,5 +1,5 @@ { - "name": "Home Assistant Add-on (edit): HiSense Air Conditioners", - "url": "https://github.com/gyro-labs/AirCon", - "maintainer": "Martijn Ruijzendaal " + "name": "Home Assistant Add-on: HiSense Air Conditioners", + "url": "https://github.com/deiger/AirCon", + "maintainer": "Dror Eiger " }