From d87f4ad31840e79577086ea9d470a7f9d83a28f2 Mon Sep 17 00:00:00 2001 From: veista Date: Wed, 7 Dec 2022 02:00:27 +0200 Subject: [PATCH] Added more entities for VP 18 M2 --- custom_components/nilan/button.py | 153 ------------------------- custom_components/nilan/config_flow.py | 2 +- custom_components/nilan/device.py | 44 +++++-- custom_components/nilan/manifest.json | 2 +- custom_components/nilan/sensor.py | 51 +++++++++ 5 files changed, 88 insertions(+), 164 deletions(-) delete mode 100644 custom_components/nilan/button.py diff --git a/custom_components/nilan/button.py b/custom_components/nilan/button.py deleted file mode 100644 index 2174559..0000000 --- a/custom_components/nilan/button.py +++ /dev/null @@ -1,153 +0,0 @@ -"""Platform for button integration.""" -from __future__ import annotations - -from datetime import timedelta - -from collections import namedtuple - -from .__init__ import NilanEntity - -from homeassistant.components.button import ButtonEntity - -from .const import DOMAIN, SCAN_INTERVAL_TIME - -SCAN_INTERVAL = timedelta(seconds=SCAN_INTERVAL_TIME) - -Map = namedtuple("map", "press_attr name entity_category press_value auto_clear icon") - -ATTRIBUTE_TO_BUTTONS = { - "display_escape_button": [ - Map( - "Display Escape Button", - "set_display_button_press", - None, - 0x01, - True, - None, - ) - ], - "display_up_button": [ - Map( - "Display Up Button", - "set_display_button_press", - None, - 0x02, - True, - None, - ) - ], - "display_down_button": [ - Map( - "Display Down Button", - "set_display_button_press", - None, - 0x04, - True, - None, - ) - ], - "display_enter_button": [ - Map( - "Display Enter Button", - "set_display_button_press", - None, - 0x08, - True, - None, - ) - ], - "display_off_button": [ - Map( - "Display Off Button", - "set_display_button_press", - None, - 0x10, - True, - None, - ) - ], - "display_on_button": [ - Map( - "Display On Button", - "set_display_button_press", - None, - 0x20, - True, - None, - ) - ], - "display_down_escape_button": [ - Map( - "Display Down + Escape Button", - "set_display_button_press", - None, - 0x05, - False, - None, - ) - ], -} - - -async def async_setup_entry(hass, config_entry, async_add_entities): - """Set up the number platform.""" - device = hass.data[DOMAIN][config_entry.entry_id] - numbers = [] - for attribute in device.get_assigned("button"): - if attribute in ATTRIBUTE_TO_BUTTONS: - maps = ATTRIBUTE_TO_BUTTONS[attribute] - numbers.extend( - [ - NilanCTS602Number( - device, - attribute, - m.name, - m.press_attr, - m.entity_category, - m.press_value, - m.auto_clear, - m.icon, - ) - for m in maps - ] - ) - async_add_entities(numbers, update_before_add=True) - - -class NilanCTS602Number(ButtonEntity, NilanEntity): - """Representation of a Switch.""" - - def __init__( - self, - device, - attribute, - press_attr, - name, - entity_category, - press_value, - auto_clear, - icon, - ) -> None: - """Init Number""" - super().__init__(device) - self._attribute = attribute - self._device = device - self._available = True - self._attr_name = "Nilan: " + name - self._press_attr = press_attr - self._attr_entity_category = entity_category - self._attr_icon = icon - self._name = name - self._press_value = press_value - self._auto_clear = auto_clear - - @property - def unique_id(self) -> str: - """Return a unique ID.""" - _name = self._device.get_device_name.lower().replace(" ", "_") - _unique_id = self._name.lower().replace(" ", "_") - return f"{_name}.{_unique_id}" - - async def async_press(self, **kwargs): - """Handle the button press.""" - await getattr(self._device, self._press_attr)(int(self._press_value)) diff --git a/custom_components/nilan/config_flow.py b/custom_components/nilan/config_flow.py index 03d5d7f..4540475 100644 --- a/custom_components/nilan/config_flow.py +++ b/custom_components/nilan/config_flow.py @@ -49,7 +49,7 @@ async def validate_device(address, port, unit_id) -> None: value_output = int.from_bytes( result.registers[0].to_bytes(2, "little", signed=False), "little", - signed=True, + signed=False, ) if not value_output in DEVICE_TYPES: _LOGGER.debug( diff --git a/custom_components/nilan/device.py b/custom_components/nilan/device.py index ef4ee2f..81d4693 100644 --- a/custom_components/nilan/device.py +++ b/custom_components/nilan/device.py @@ -14,13 +14,6 @@ "get_t4_outlet": "sensor", "get_display_text_1": "sensor", "get_display_text_2": "sensor", - "display_escape_button": "button", - "display_up_button": "button", - "display_down_button": "button", - "display_enter_button": "button", - "display_off_button": "button", - "display_on_button": "button", - "display_down_escape_button": "button", } VP18C_SUPPORTED_ENTITIES = { @@ -38,6 +31,7 @@ "get_max_return_step": "select", "get_low_outdoor_temperature_ventilation_step": "select", "get_defrost_ventilation_level": "select", + "get_air_filter_alarm_interval": "select", "get_scalding_protection_setpoint": "number", "get_max_supply_air_summer_setpoint": "number", "get_max_supply_air_winter_setpoint": "number", @@ -76,6 +70,25 @@ } VP18M2_SUPPORTED_ENTITIES = { + "get_air_exchange_mode": "climate", + "get_electric_water_heater_setpoint": "water_heater", + "get_electric_water_heater_state": "water_heater", + "get_compressor_water_heater_setpoint": "water_heater", + "get_t12_compressor_water_heater_temperature": "water_heater", + "get_t11_electric_water_heater_temperature": "water_heater", + "get_display_led_1_state": "binary_sensor", + "get_display_led_2_state": "binary_sensor", + "get_compressor_state": "binary_sensor", + "get_display_text_1": "sensor", + "get_display_text_2": "sensor", + "get_t10_external_temperature": "sensor", + "get_t6_evaporator_temperature": "sensor", + "get_t5_condenser_temperature": "sensor", + "get_t1_intake_temperature": "sensor", + "get_t13_return_temperature": "sensor", + "get_t14_supply_temperature": "sensor", + "get_t16_sacrificial_anode_temperature": "sensor", + "get_anode_state": "sensor", } COMBI302_SUPPORTED_ENTITIES = { @@ -88,6 +101,7 @@ "get_pre_heater_deftrost_select": "select", "get_pre_heater_temp_set": "select", "get_air_quality_control_type": "select", + "get_air_filter_alarm_interval": "select", "get_supply_power_at_level_1": "number", "get_supply_power_at_level_2": "number", "get_supply_power_at_level_3": "number", @@ -140,7 +154,6 @@ "get_return_fan_speed": "sensor", "get_supply_fan_speed": "sensor", "get_smoke_alarm_state": "binary_sensor", - "get_air_filter_alarm_interval": "select", "get_cooling_mode_ventilation_step": "select", "get_cooling_setpoint": "select", "get_low_humidity_step": "select", @@ -229,7 +242,7 @@ async def setup(self): self._attributes = COMMON_ENTITIES self._attributes.update(HW_VERSION_TO_DEVICE[hw_type]) self._device_type = DEVICE_TYPES[hw_type] - if hw_type not in (13,): + if hw_type not in (13, 21): self._device_hw_ver = await self.get_controller_hardware_version() if await self.get_co2_present(): self._attributes.update(CO2_PRESENT_TO_ATTRIBUTES) @@ -427,6 +440,19 @@ async def get_user_menu_state(self) -> int: ) return None + async def get_anode_state(self) -> int: + """get user menu state.""" + result = await self._modbus.async_pymodbus_call( + self._unit_id, CTS602InputRegisters.hot_water_anode_state, 1, "input" + ) + if result is not None: + return int.from_bytes( + result.registers[0].to_bytes(2, "little", signed=False), + "little", + signed=False, + ) + return None + async def get_supply_air_after_heating(self) -> int: """get After heating activation state.""" result = await self._modbus.async_pymodbus_call( diff --git a/custom_components/nilan/manifest.json b/custom_components/nilan/manifest.json index f3e11b9..eff326c 100644 --- a/custom_components/nilan/manifest.json +++ b/custom_components/nilan/manifest.json @@ -1,7 +1,7 @@ { "domain": "nilan", "name": "Nilan", - "version": "1.0.21", + "version": "1.0.22", "config_flow": true, "documentation": "https://github.com/veista/nilan", "requirements": ["pymodbus==2.5.3"], diff --git a/custom_components/nilan/sensor.py b/custom_components/nilan/sensor.py index b6dbc7c..5077100 100644 --- a/custom_components/nilan/sensor.py +++ b/custom_components/nilan/sensor.py @@ -75,6 +75,13 @@ 2: "No Off Key", } +ANODE_STATES = { + 0: "Off", + 1: "OK", + 2: "Service", + 3: "Error", +} + Map = namedtuple( "map", "name default_unit device_class state_class entity_category icon enum" ) @@ -190,6 +197,28 @@ None, ) ], + "get_t13_return_temperature": [ + Map( + "Return Water Temperature", + TEMP_CELSIUS, + SensorDeviceClass.TEMPERATURE, + SensorStateClass.MEASUREMENT, + None, + None, + None, + ) + ], + "get_t14_supply_temperature": [ + Map( + "Supply Water Temperature", + TEMP_CELSIUS, + SensorDeviceClass.TEMPERATURE, + SensorStateClass.MEASUREMENT, + None, + None, + None, + ) + ], "get_t15_user_panel_temperature": [ Map( "User Panel Temperature", @@ -201,6 +230,17 @@ None, ) ], + "get_t16_sacrificial_anode_temperature": [ + Map( + "Anode Temperature", + TEMP_CELSIUS, + SensorDeviceClass.TEMPERATURE, + SensorStateClass.MEASUREMENT, + None, + None, + None, + ) + ], "get_humidity": [ Map( "Humidity", @@ -355,6 +395,17 @@ USER_MENU_STATES, ) ], + "get_anode_state": [ + Map( + "Anode State", + None, + None, + SensorStateClass.MEASUREMENT, + None, + None, + ANODE_STATES, + ) + ], "get_supply_fan_level": [ Map( "Supply Fan Level",