From 9c9ae1629744f179efb026663b976754d6430e38 Mon Sep 17 00:00:00 2001 From: Lars Kusch Date: Sun, 6 Oct 2024 17:06:26 +0200 Subject: [PATCH] Added possibility to enable/disable features of solvis components --- custom_components/solvis_control/__init__.py | 21 +++++++- .../solvis_control/config_flow.py | 51 +++++++++++++++++-- custom_components/solvis_control/const.py | 33 +++++++++++- .../solvis_control/coordinator.py | 25 +++++++-- custom_components/solvis_control/number.py | 12 +++++ custom_components/solvis_control/select.py | 12 +++++ custom_components/solvis_control/sensor.py | 12 +++++ 7 files changed, 154 insertions(+), 12 deletions(-) diff --git a/custom_components/solvis_control/__init__.py b/custom_components/solvis_control/__init__.py index d57cbd1..0951091 100644 --- a/custom_components/solvis_control/__init__.py +++ b/custom_components/solvis_control/__init__.py @@ -12,7 +12,16 @@ from homeassistant.const import CONF_IP_ADDRESS, Platform from homeassistant.core import HomeAssistant -from .const import CONF_HOST, CONF_PORT, DATA_COORDINATOR, DOMAIN +from .const import ( + CONF_HOST, + CONF_PORT, + DATA_COORDINATOR, + DOMAIN, + CONF_OPTION_1, + CONF_OPTION_2, + CONF_OPTION_3, + CONF_OPTION_4, +) from .coordinator import SolvisModbusCoordinator PLATFORMS: [Platform] = [Platform.SENSOR, Platform.NUMBER, Platform.SELECT] @@ -32,7 +41,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.data[DOMAIN].setdefault(entry.entry_id, {}) # Create coordinator for polling - coordinator = SolvisModbusCoordinator(hass, conf_host, conf_port) + coordinator = SolvisModbusCoordinator( + hass, + conf_host, + conf_port, + CONF_OPTION_1, + CONF_OPTION_2, + CONF_OPTION_3, + CONF_OPTION_4, + ) await coordinator.async_config_entry_first_refresh() hass.data[DOMAIN][entry.entry_id].setdefault(DATA_COORDINATOR, coordinator) diff --git a/custom_components/solvis_control/config_flow.py b/custom_components/solvis_control/config_flow.py index a2dbdbf..0c4e3d3 100644 --- a/custom_components/solvis_control/config_flow.py +++ b/custom_components/solvis_control/config_flow.py @@ -11,7 +11,16 @@ from homeassistant.data_entry_flow import FlowResult from homeassistant.helpers.typing import ConfigType -from .const import CONF_HOST, CONF_NAME, CONF_PORT, DOMAIN +from .const import ( + CONF_HOST, + CONF_NAME, + CONF_PORT, + DOMAIN, + CONF_OPTION_1, + CONF_OPTION_2, + CONF_OPTION_3, + CONF_OPTION_4, +) _LOGGER = logging.getLogger(__name__) @@ -26,6 +35,17 @@ def get_host_schema_config(data: ConfigType) -> Schema: ) +def get_solvis_modules(data: ConfigType) -> Schema: + return vol.Schema( + { + vol.Required(CONF_OPTION_1, default=False): bool, # HKR 2 + vol.Required(CONF_OPTION_2, default=False): bool, # HKR 3 + vol.Required(CONF_OPTION_3, default=False): bool, # solar collectors + vol.Required(CONF_OPTION_4, default=False): bool, # heat pump + } + ) + + def get_host_schema_options(data: ConfigType) -> Schema: return vol.Schema( { @@ -37,7 +57,7 @@ def get_host_schema_options(data: ConfigType) -> Schema: class SolvisConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): VERSION = 1 - MINOR_VERSION = 1 + MINOR_VERSION = 2 def __init__(self) -> None: """Init the ConfigFlow.""" @@ -57,6 +77,17 @@ async def async_step_user( await self.async_set_unique_id(self.data[CONF_HOST], raise_on_progress=False) self._abort_if_unique_id_configured() + return await self.async_step_features() + + async def async_step_features( + self, user_input: dict[bool, bool, bool] | None = None + ) -> FlowResult: + """Handle the feature step.""" + if user_input is None: + return self.async_show_form( + step_id="features", data_schema=get_solvis_modules(self.data) + ) + self.data.update(user_input) return self.async_create_entry(title=self.data[CONF_NAME], data=self.data) @staticmethod @@ -113,6 +144,16 @@ async def async_step_init( data_schema=get_host_schema_options(self.data), ) self.data = user_input - return self.async_create_entry( - title=self.config_entry.get(CONF_NAME), data=self.data - ) + self.data.update(user_input) + return await self.async_step_features() + + async def async_step_features( + self, user_input: dict[bool, bool, bool] | None = None + ) -> FlowResult: + """Handle the feature step.""" + if user_input is None: + return self.async_show_form( + step_id="features", data_schema=get_solvis_modules(self.data) + ) + self.data.update(user_input) + return self.async_create_entry(title=self.config.get(CONF_NAME), data=self.data) diff --git a/custom_components/solvis_control/const.py b/custom_components/solvis_control/const.py index e677365..4e55381 100644 --- a/custom_components/solvis_control/const.py +++ b/custom_components/solvis_control/const.py @@ -5,6 +5,11 @@ CONF_NAME = "name" CONF_HOST = "host" CONF_PORT = "port" +# Option attributes to make certain values configurable +CONF_OPTION_1 = False # HKR 2 +CONF_OPTION_2 = False # HKR 3 +CONF_OPTION_3 = False # Solar collector +CONF_OPTION_4 = False # heat pump DATA_COORDINATOR = "coordinator" MANUFACTURER = "Solvis" @@ -21,12 +26,13 @@ class ModbusFieldConfig: # 1 = INPUT, 2 = HOLDING register: int = 1 - negative: bool = False entity_category: str = None enabled_by_default: bool = True edit: bool = False data: tuple = None absolute_value: bool = False + # Assign CONF_OPTION to entities + conf_option: int = 0 PORT = 502 @@ -52,6 +58,7 @@ class ModbusFieldConfig: device_class="temperature", state_class="measurement", enabled_by_default=False, + conf_option=3, ), ModbusFieldConfig( # Zirkulationsdurchfluss name="cold_water_temp", @@ -82,6 +89,7 @@ class ModbusFieldConfig: device_class="temperature", state_class="measurement", enabled_by_default=False, + conf_option=3, ), ModbusFieldConfig( name="solar_heat_exchanger_in_water_temp", @@ -90,6 +98,7 @@ class ModbusFieldConfig: device_class="temperature", state_class="measurement", enabled_by_default=False, + conf_option=3, ), ModbusFieldConfig( name="solar_heat_exchanger_out_water_temp", @@ -98,6 +107,7 @@ class ModbusFieldConfig: device_class="temperature", state_class="measurement", enabled_by_default=False, + conf_option=3, ), ModbusFieldConfig( # Speicherreferenztemperatur name="tank_layer1_water_temp", @@ -150,7 +160,6 @@ class ModbusFieldConfig: unit="", device_class="", state_class="measurement", - negative=True, multiplier=1, entity_category="diagnostic", absolute_value=True, @@ -326,6 +335,7 @@ class ModbusFieldConfig: register=2, multiplier=1, data=("2", "3", "4", "5", "6", "7"), + conf_option=1, ), ModbusFieldConfig( # HKR2 Solltemperatur Tag name="hkr2_solltemperatur_tag", @@ -337,6 +347,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(5, 75), + conf_option=1, ), ModbusFieldConfig( # HKR2 Absenktemperatur Nacht name="hkr2_absenktemperatur_nacht", @@ -348,6 +359,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(5, 75), + conf_option=1, ), ModbusFieldConfig( # HKR2 Heizkurve Tag Temp. 1 name="hkr2_heizkurve_temp_tag_1", @@ -359,6 +371,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(5, 50), + conf_option=1, ), ModbusFieldConfig( # HKR2 Heizkurve Tag Temp. 2 name="hkr2_heizkurve_temp_tag_2", @@ -370,6 +383,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(5, 30), + conf_option=1, ), ModbusFieldConfig( # HKR2 Heizkurve Tag Temp. 3 name="hkr2_heizkurve_temp_tag_3", @@ -381,6 +395,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(5, 30), + conf_option=1, ), ModbusFieldConfig( # HKR2 Heizkurve Absenkung name="hkr2_heizkurve_temp_absenkung", @@ -392,6 +407,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(5, 30), + conf_option=1, ), ModbusFieldConfig( # HKR2 Heizkurve Steilheit name="hkr2_heizkurve_steilheit", @@ -403,6 +419,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(20, 250), + conf_option=1, ), ModbusFieldConfig( # Raumtemperatur_HKR2 name="raumtemperatur_hkr2", @@ -413,6 +430,7 @@ class ModbusFieldConfig: register=2, edit=True, data=(0, 40), + conf_option=1, ), ModbusFieldConfig( # HKR3 Betriebsart name="hkr3_betriebsart", @@ -423,6 +441,7 @@ class ModbusFieldConfig: register=2, multiplier=1, data=("2", "3", "4", "5", "6", "7"), + conf_option=2, ), ModbusFieldConfig( # HKR3 Solltemperatur Tag name="hkr3_solltemperatur_tag", @@ -434,6 +453,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(5, 75), + conf_option=2, ), ModbusFieldConfig( # HKR3 Absenktemperatur Nacht name="hkr3_absenktemperatur_nacht", @@ -445,6 +465,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(5, 75), + conf_option=2, ), ModbusFieldConfig( # HKR3 Heizkurve Tag Temp. 1 name="hkr3_heizkurve_temp_tag_1", @@ -456,6 +477,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(5, 50), + conf_option=2, ), ModbusFieldConfig( # HKR3 Heizkurve Tag Temp. 2 name="hkr3_heizkurve_temp_tag_2", @@ -467,6 +489,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(5, 30), + conf_option=2, ), ModbusFieldConfig( # HKR3 Heizkurve Tag Temp. 3 name="hkr3_heizkurve_temp_tag_3", @@ -478,6 +501,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(5, 30), + conf_option=2, ), ModbusFieldConfig( # HKR3 Heizkurve Absenkung name="hkr3_heizkurve_temp_absenkung", @@ -489,6 +513,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(5, 30), + conf_option=2, ), ModbusFieldConfig( # HKR3 Heizkurve Steilheit name="hkr3_heizkurve_steilheit", @@ -500,6 +525,7 @@ class ModbusFieldConfig: multiplier=1, edit=True, data=(20, 250), + conf_option=2, ), ModbusFieldConfig( # Raumtemperatur_HKR3 name="raumtemperatur_hkr3", @@ -510,6 +536,7 @@ class ModbusFieldConfig: register=2, edit=True, data=(0, 40), + conf_option=2, ), ModbusFieldConfig( # DigIn Stoerungen name="digin_stoerungen", @@ -567,6 +594,7 @@ class ModbusFieldConfig: register=2, edit=False, enabled_by_default=False, + conf_option=4, ), ModbusFieldConfig( # elektrische Wärmepumenleistung name="elek_waermepumpe_leistung", @@ -577,5 +605,6 @@ class ModbusFieldConfig: register=2, edit=False, enabled_by_default=False, + conf_option=4, ), ] diff --git a/custom_components/solvis_control/coordinator.py b/custom_components/solvis_control/coordinator.py index 6e6f63e..443170f 100644 --- a/custom_components/solvis_control/coordinator.py +++ b/custom_components/solvis_control/coordinator.py @@ -18,7 +18,16 @@ class SolvisModbusCoordinator(DataUpdateCoordinator): """My custom coordinator.""" - def __init__(self, hass, conf_host, conf_port): + def __init__( + self, + hass, + conf_host, + conf_port, + conf_option_1: bool, + conf_option_2: bool, + conf_option_3: bool, + conf_option_4: bool, + ): """Initialize my coordinator.""" super().__init__( hass, @@ -28,6 +37,10 @@ def __init__(self, hass, conf_host, conf_port): # Polling interval. Will only be polled if there are subscribers. update_interval=timedelta(seconds=30), ) + self.CONF_OPTION_4 = conf_option_4 + self.CONF_OPTION_3 = conf_option_3 + self.CONF_OPTION_2 = conf_option_2 + self.CONF_OPTION_1 = conf_option_1 self.logger.debug("Creating client") self.modbus = ModbusClient.AsyncModbusTcpClient(host=conf_host, port=conf_port) @@ -46,6 +59,14 @@ async def _async_update_data(self): self.logger.warning("Couldn't connect to device") if self.modbus.connected: for register in REGISTERS: + if not self.CONF_OPTION_1 and register.conf_option == 1: + continue + if not self.CONF_OPTION_2 and register.conf_option == 2: + continue + if not self.CONF_OPTION_3 and register.conf_option == 3: + continue + if not self.CONF_OPTION_4 and register.conf_option == 4: + continue self.logger.debug("Connected to Modbus for Solvis") try: if register.register == 1: @@ -65,8 +86,6 @@ async def _async_update_data(self): parsed_data[register.name] = round( d.decode_16bit_int() * register.multiplier, 2 ) - if register.negative: - parsed_data[register.name] *= -1 if register.absolute_value: parsed_data[register.name] = abs(parsed_data[register.name]) self.modbus.close() diff --git a/custom_components/solvis_control/number.py b/custom_components/solvis_control/number.py index 66fe2cc..8671f31 100644 --- a/custom_components/solvis_control/number.py +++ b/custom_components/solvis_control/number.py @@ -21,6 +21,10 @@ DOMAIN, MANUFACTURER, REGISTERS, + CONF_OPTION_3, + CONF_OPTION_2, + CONF_OPTION_1, + CONF_OPTION_4, ) from .coordinator import SolvisModbusCoordinator @@ -52,6 +56,14 @@ async def async_setup_entry( continue if register.address in (2818, 2049, 3074, 3330): continue + if not entry.data.get(CONF_OPTION_1) and register.conf_option == 1: + continue + if not entry.data.get(CONF_OPTION_2) and register.conf_option == 2: + continue + if not entry.data.get(CONF_OPTION_3) and register.conf_option == 3: + continue + if not entry.data.get(CONF_OPTION_4) and register.conf_option == 4: + continue sensors_to_add.append( SolvisSensor( hass.data[DOMAIN][entry.entry_id][DATA_COORDINATOR], diff --git a/custom_components/solvis_control/select.py b/custom_components/solvis_control/select.py index 6457e2a..47ec678 100644 --- a/custom_components/solvis_control/select.py +++ b/custom_components/solvis_control/select.py @@ -21,6 +21,10 @@ DOMAIN, MANUFACTURER, REGISTERS, + CONF_OPTION_4, + CONF_OPTION_3, + CONF_OPTION_2, + CONF_OPTION_1, ) from .coordinator import SolvisModbusCoordinator @@ -51,6 +55,14 @@ async def async_setup_entry( for register in REGISTERS: if register.address not in (2818, 3074, 3330): continue + if not entry.data.get(CONF_OPTION_1) and register.conf_option == 1: + continue + if not entry.data.get(CONF_OPTION_2) and register.conf_option == 2: + continue + if not entry.data.get(CONF_OPTION_3) and register.conf_option == 3: + continue + if not entry.data.get(CONF_OPTION_4) and register.conf_option == 4: + continue sensors_to_add.append( SolvisSensor( hass.data[DOMAIN][entry.entry_id][DATA_COORDINATOR], diff --git a/custom_components/solvis_control/sensor.py b/custom_components/solvis_control/sensor.py index d732af6..f01d3af 100644 --- a/custom_components/solvis_control/sensor.py +++ b/custom_components/solvis_control/sensor.py @@ -19,6 +19,10 @@ DOMAIN, MANUFACTURER, REGISTERS, + CONF_OPTION_1, + CONF_OPTION_2, + CONF_OPTION_3, + CONF_OPTION_4, ) from .coordinator import SolvisModbusCoordinator @@ -51,6 +55,14 @@ async def async_setup_entry( continue if register.address in (2818, 3074, 3330): continue + if not entry.data.get(CONF_OPTION_1) and register.conf_option == 1: + continue + if not entry.data.get(CONF_OPTION_2) and register.conf_option == 2: + continue + if not entry.data.get(CONF_OPTION_3) and register.conf_option == 3: + continue + if not entry.data.get(CONF_OPTION_4) and register.conf_option == 4: + continue sensors_to_add.append( SolvisSensor( hass.data[DOMAIN][entry.entry_id][DATA_COORDINATOR],