diff --git a/README.md b/README.md index 5fcbbb76..5adb8e44 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Wiser Home Assistant Integration v3.3.0 +# Wiser Home Assistant Integration v3.3.1 [![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg?style=for-the-badge)](https://github.com/hacs/integration) [![downloads](https://shields.io/github/downloads/asantaga/wiserHomeAssistantPlatform/latest/total?style=for-the-badge)](https://github.com/asantaga/wiserHomeAssistantPlatform) @@ -21,7 +21,6 @@ For more information checkout the AMAZING community thread available on - Improved data in Wiser events - Improved error handling for setting schedules from YAML files - ## Contents - [Minimum Requirements](#minimum-requirements) @@ -523,14 +522,15 @@ The integration provides a wiser_event event name with types of boosted, started max: 10 ``` - ## Integration Automations In order to extend the capability of this integration and simplify complex problems by not having to write complex automations, we have added a new concept of integration automations. Below are the current automations available with a description of how they work. Please note, you need to enable Integration Automations in the integration config. ### Passive Mode -An automation that allows you to set a room to only heat when other rooms are heating. This is only available for TRVs and not Heating Actuators. In each room will be a switch to enable/disable passive mode for that room. In passive mode, the room is actually set to manual to the min temp (set by the thermostat card). This allows the room to call for heat if the temp goes below the minimum. When it is detected that other (non-passive) rooms are requesting heat, the manual temp of the passive rooms is raised in 0.5C increments until it reaches the max temp. At any point, if all non-passive rooms are no longer calling for heat, the passive rooms are set back to their min temp. +An automation that allows you to set a room to only heat when other rooms are heating. This is only available for rooms with TRVs and not Heating Actuators. In each room will be a switch to set Passive Mode on or off for that room. + +More detailed information on this automation is available [here](docs/inbuilt_automations.md) ## Schedule Card @@ -619,6 +619,27 @@ There are two primary branches for this integration, `master` and `dev` . Master ## Change log +- 3.3.1 + - Bump api to v1.3.1 + - Added is_passive attribute to climate entity + - Added that away mode overrides passive mode + - Added config option to manage passive mode temperature increments + - Added hub update if built in automations make changes to hub to reflect current status immediately + +- 3.3.1beta2 + - Bump api to v1.3.0 + - Breaking change - if you have installed and used passive mode in v3.3.1beta, this version will leave orphaned select entities that will need to be deleted manually. + - Reworking of passive mode to be based on the auto/heat/off HVAC modes with passive mode on/off switch + - Storage of the manual set temp in the (now existing) integration storage file to presist after a HA restart + +- 3.3.1beta + - Bump api to v1.2.2 + - Breaking change - added passive mode follow schedule which changes on/off switch for passive mode to selector for type of mode. Please note, there is a bug in the thermostat card (due to be fixed in an upcoming release of HA frontend) which causes the high temperature setting to not show correctly in Passive Follow Schedule mode if you try to change it manually. + - Breaking change - where the automations were enabled in v3.3.0, this willneed re-enabling in v3.3.1beta1 due to changes in the config configuration + - Allow boost override when in passive mode - issue [#348](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/348) + - Added additional opentherm parameters - issue [#337](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/337) + - Corrected error saving on/off schedule - issue [#349](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/349) + - 3.3.0 - Bump api to v1.0.2 - Add event data to wiser events - issue [#324](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/324) @@ -635,7 +656,6 @@ There are two primary branches for this integration, `master` and `dev` . Master - Added new passive mode for rooms with api smarts - Improved repeater name on device signal entity - issue [#345](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/345) - - 3.2.2 - Bump api to v0.1.8 - v1.1.7 of schedule card @@ -837,7 +857,7 @@ There are two primary branches for this integration, `master` and `dev` . Master - 2.3 - Fix for error given by latest HA highlighting that I/O Detected in event loop - issue [#97](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/97) - Fix for climate graph not showing true state - issue [#98](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/98) - - Fixed heating boost - issue [#101]([https://github.com/asantaga/wiserHomeAssistantPlatform/issues/101) + - Fixed heating boost - issue [#101](https://github.com/asantaga/wiserHomeAssistantPlatform/issues/101) - 2.2 - Battery voltage across sensor types now consistent (1 decimal place no v) diff --git a/custom_components/wiser/button.py b/custom_components/wiser/button.py index 0af4694a..23ddca85 100644 --- a/custom_components/wiser/button.py +++ b/custom_components/wiser/button.py @@ -36,7 +36,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): ] ) - if data.enable_moments and data.wiserhub.moments: + if data.wiserhub.moments: _LOGGER.debug("Setting up Moments buttons") for moment in data.wiserhub.moments.all: wiser_buttons.append(WiserMomentsButton(data, moment.id)) diff --git a/custom_components/wiser/climate.py b/custom_components/wiser/climate.py index b9ce0b97..b817dd1b 100755 --- a/custom_components/wiser/climate.py +++ b/custom_components/wiser/climate.py @@ -51,6 +51,8 @@ STATUS_OVERRIDE = "Override" STATUS_BLANK = "" +TEXT_PASSIVE = "Passive" + WISER_PRESET_TO_HASS = { "FromAwayMode": STATUS_AWAY, "FromManualMode": STATUS_BLANK, @@ -64,7 +66,10 @@ "FromNoControl": STATUS_BLANK, } -WISER_PRESETS = {"Advance Schedule": 0, "Cancel Overrides": 0} +WISER_PRESETS = { + "Advance Schedule": 0, + "Cancel Overrides": 0, +} WISER_PRESETS.update(WISER_BOOST_PRESETS) HVAC_MODE_WISER_TO_HASS = { @@ -82,6 +87,9 @@ SUPPORT_FLAGS = ( ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE ) +PASSIVE_MODE_SUPPORT_FLAGS = ( + ClimateEntityFeature.TARGET_TEMPERATURE_RANGE | ClimateEntityFeature.PRESET_MODE +) async def async_setup_entry(hass, config_entry, async_add_entities): @@ -267,13 +275,17 @@ def __init__(self, hass, coordinator, room_id): self._hvac_modes_list = [modes for modes in HVAC_MODE_HASS_TO_WISER.keys()] self._is_heating = self._room.is_heating self._schedule = self._room.schedule - self._previous_target_temp = self.current_temperature - # Set initial previous target temp based on config setting - if self._schedule and self._data.previous_target_temp_option == "Schedule": - self._previous_target_temp = self._room.schedule.current_setting - elif self._data.previous_target_temp_option == "Minimum": - self._previous_target_temp = TEMP_MINIMUM + # Set room stored manual target temp based on options (if not already set) + self._room.stored_manual_target_temperature_alt_source = ( + self._data.previous_target_temp_option.lower() + ) + + # Set passive mode temperature increment value if enabled + if self._room.is_passive_mode: + self._room.passive_temperature_increment = ( + self._data.passive_temperature_increment + ) _LOGGER.debug(f"{self._data.wiserhub.system.name} {self.name} initailise") @@ -290,6 +302,7 @@ def _handle_coordinator_update(self) -> None: if not self._room.is_boosted: self._boosted_time = 0 + self.async_write_ha_state() fire_events( @@ -335,35 +348,22 @@ def icon(self): @property def hvac_action(self): """Return hvac action from data.""" - if self._room.mode == "Passive": - return "Passive Mode" return HVACAction.HEATING if self._room.is_heating else HVACAction.IDLE @property def hvac_mode(self): - return ( - None - if self._room.mode == "Passive" - else HVAC_MODE_WISER_TO_HASS[self._room.mode] - ) + return HVAC_MODE_WISER_TO_HASS[self._room.mode] @property def hvac_modes(self): """Return the list of available operation modes.""" - return None if self._room.mode == "Passive" else self._hvac_modes_list + return self._hvac_modes_list async def async_set_hvac_mode(self, hvac_mode): """Set new operation mode.""" _LOGGER.debug(f"Setting HVAC mode to {hvac_mode} for {self._room.name}") try: - if self.hvac_mode == HVACMode.HEAT and self.target_temperature != -20: - - self._previous_target_temp = self._room.current_target_temperature - await self._room.set_mode(HVAC_MODE_HASS_TO_WISER[hvac_mode]) - # Restore previous manual target temp when coming from Off mode back to Manual - if hvac_mode == HVACMode.HEAT and self._previous_target_temp: - await self._room.set_target_temperature(self._previous_target_temp) await self.async_force_update() return True except KeyError: @@ -388,10 +388,9 @@ def name(self): def preset_mode(self): """Get current preset mode.""" try: - if ( - WISER_PRESET_TO_HASS[self._room.target_temperature_origin] - == STATUS_BOOST - ): + if self._room.is_passive_mode: + return TEXT_PASSIVE + elif self._room.preset_mode == "Boost": if int(self._room.boost_time_remaining / 60) != 0: return f"{STATUS_BOOST} {int(self._room.boost_time_remaining/60)}m" else: @@ -404,38 +403,22 @@ def preset_mode(self): @property def preset_modes(self): """Return the list of available preset modes.""" - if not self._schedule: - return [ - mode - for mode in list(WISER_PRESETS.keys()) - if mode != "Advance Schedule" - ] - return list(WISER_PRESETS.keys()) + return self._room.available_presets async def async_set_preset_mode(self, preset_mode: str) -> None: """Async call to set preset mode .""" - _LOGGER.debug(f"Setting Preset Mode {preset_mode} for {self._room.name}") - if preset_mode == "Advance Schedule": - await self._room.schedule_advance() - elif WISER_PRESETS[preset_mode] == 0: - await self._room.cancel_overrides() - elif preset_mode.startswith("Boost"): - boost_time = WISER_PRESETS[preset_mode] - boost_temp = self._data.boost_temp - await self._room.boost(boost_temp, boost_time) - else: - _LOGGER.error(f"Invalid preset mode. Options are {self.preset_modes}") + _LOGGER.info(f"Setting Preset Mode {preset_mode} for {self._room.name}") + try: + await self._room.set_preset(preset_mode) + except ValueError as ex: + _LOGGER.error(ex) await self.async_force_update() @property def state(self): """Return state""" - return ( - "Passive" - if self._room.mode == "Passive" - else HVAC_MODE_WISER_TO_HASS[self._room.mode] - ) + return HVAC_MODE_WISER_TO_HASS[self._room.mode] @property def extra_state_attributes(self): @@ -456,6 +439,7 @@ def extra_state_attributes(self): attrs["is_boosted"] = self._room.is_boosted attrs["is_override"] = self._room.is_override attrs["is_heating"] = self._room.is_heating + attrs["is_passive"] = self._room.is_passive_mode attrs["control_output_state"] = "On" if self._room.is_heating else "Off" attrs["heating_rate"] = self._room.heating_rate @@ -485,9 +469,7 @@ def extra_state_attributes(self): def supported_features(self): """Return the list of supported features.""" return ( - ClimateEntityFeature.TARGET_TEMPERATURE_RANGE - if self._room.mode == "Passive" - else SUPPORT_FLAGS + PASSIVE_MODE_SUPPORT_FLAGS if self._room.is_passive_mode else SUPPORT_FLAGS ) @property @@ -498,6 +480,10 @@ def target_temperature(self): or self._room.current_target_temperature == TEMP_OFF ): return None + + # if self._is_passive_mode and not self._room.is_boosted: + # return None + return self._room.current_target_temperature @property @@ -521,19 +507,16 @@ def target_temperature_low(self) -> float | None: async def async_set_temperature(self, **kwargs): """Set new target temperatures.""" - if self._room.mode == "Passive": + _LOGGER.info(kwargs) + if self._room.is_passive_mode and not self._room.is_boosted: if kwargs.get("target_temp_low", None): await self._room.set_passive_mode_lower_temp( kwargs.get("target_temp_low") ) - # await self._room.set_target_temperature(kwargs.get("target_temp_low")) - await self.async_force_update() - - if kwargs.get("target_temp_high", None): + if kwargs.get("target_temp_high", None) and self.hvac_mode == HVACMode.HEAT: await self._room.set_passive_mode_upper_temp( kwargs.get("target_temp_high") ) - await self.async_force_update() else: target_temperature = kwargs.get(ATTR_TEMPERATURE) if target_temperature is None: @@ -554,7 +537,7 @@ async def async_set_temperature(self, **kwargs): f"Setting temperature for {self.name} to {target_temperature}" ) await self._room.set_target_temperature(target_temperature) - await self.async_force_update() + await self.async_force_update() return True @property diff --git a/custom_components/wiser/config_flow.py b/custom_components/wiser/config_flow.py index dee26232..85821002 100755 --- a/custom_components/wiser/config_flow.py +++ b/custom_components/wiser/config_flow.py @@ -23,17 +23,18 @@ from homeassistant.helpers.selector import selector, SelectSelectorMode from .const import ( - CONF_AUTOMATIONS, + CONF_AUTOMATIONS_PASSIVE, + CONF_AUTOMATIONS_PASSIVE_TEMP_INCREMENT, CONF_HEATING_BOOST_TEMP, CONF_HEATING_BOOST_TIME, - CONF_LTS_SENSORS, - CONF_MOMENTS, CONF_RESTORE_MANUAL_TEMP_OPTION, CONF_SETPOINT_MODE, CONF_HW_BOOST_TIME, CONF_HOSTNAME, + CUSTOM_DATA_STORE, DEFAULT_BOOST_TEMP, DEFAULT_BOOST_TEMP_TIME, + DEFAULT_PASSIVE_TEMP_INCREMENT, DEFAULT_SCAN_INTERVAL, DOMAIN, WISER_RESTORE_TEMP_DEFAULT_OPTIONS, @@ -58,7 +59,7 @@ async def validate_input(hass, data): host=data[CONF_HOST], secret=data[CONF_PASSWORD], session=async_get_clientsession(hass), - extra_config_file=hass.config.config_dir + "/.storage/wiser_custom_data", + extra_config_file=hass.config.config_dir + CUSTOM_DATA_STORE, enable_automations=False, ) @@ -205,7 +206,39 @@ def __init__(self, config_entry: config_entries.ConfigEntry): """Initialize options flow.""" self.config_entry = config_entry - async def async_step_init(self, user_input=None): + async def async_step_automation_params(self, user_input=None): + if user_input is not None: + options = self.config_entry.options | user_input + return self.async_create_entry(title="", data=options) + + data_schema = { + vol.Optional( + CONF_AUTOMATIONS_PASSIVE, + default=self.config_entry.options.get(CONF_AUTOMATIONS_PASSIVE, False), + ): bool, + vol.Optional( + CONF_AUTOMATIONS_PASSIVE_TEMP_INCREMENT, + default=self.config_entry.options.get( + CONF_AUTOMATIONS_PASSIVE_TEMP_INCREMENT, + DEFAULT_PASSIVE_TEMP_INCREMENT, + ), + ): selector( + { + "number": { + "min": 0.5, + "max": 20, + "step": 0.5, + "unit_of_measurement": "°C", + "mode": "box", + } + } + ), + } + return self.async_show_form( + step_id="automation_params", data_schema=vol.Schema(data_schema) + ) + + async def async_step_main_params(self, user_input=None): """Handle options flow.""" if user_input is not None: if user_input[CONF_HOST]: @@ -218,7 +251,8 @@ async def async_step_init(self, user_input=None): self.hass.config_entries.async_update_entry( self.config_entry, data=data ) - return self.async_create_entry(title="", data=user_input) + options = self.config_entry.options | user_input + return self.async_create_entry(title="", data=options) data_schema = { vol.Required(CONF_HOST, default=self.config_entry.data[CONF_HOST]): str, @@ -273,20 +307,16 @@ async def async_step_init(self, user_input=None): } } ), - vol.Optional( - CONF_AUTOMATIONS, - default=self.config_entry.options.get(CONF_AUTOMATIONS, False), - ): bool, - vol.Optional( - CONF_MOMENTS, - default=self.config_entry.options.get(CONF_MOMENTS, False), - ): bool, - vol.Optional( - CONF_LTS_SENSORS, - default=self.config_entry.options.get(CONF_LTS_SENSORS, False), - ): bool, } - return self.async_show_form(step_id="init", data_schema=vol.Schema(data_schema)) + return self.async_show_form( + step_id="main_params", data_schema=vol.Schema(data_schema) + ) + + async def async_step_init(self, user_input=None): + """Handle options flow.""" + return self.async_show_menu( + step_id="init", menu_options=["main_params", "automation_params"] + ) class CannotConnect(exceptions.HomeAssistantError): diff --git a/custom_components/wiser/const.py b/custom_components/wiser/const.py index d96690f0..02e6d00c 100755 --- a/custom_components/wiser/const.py +++ b/custom_components/wiser/const.py @@ -10,7 +10,7 @@ URL_BASE = "/wiser" WISER_CARD_FILENAMES = ["wiser-schedule-card.js", "wiser-zigbee-card.js"] -VERSION = "3.3.0" +VERSION = "3.4.0" WISER_PLATFORMS = [ "climate", "sensor", @@ -25,6 +25,7 @@ UPDATE_TRACK = "update_track" UPDATE_LISTENER = "update_listener" MIN_SCAN_INTERVAL = 30 +CUSTOM_DATA_STORE = "/.storage/wiser_custom_data" # Hub MANUFACTURER = "Drayton Wiser" @@ -40,19 +41,19 @@ DEFAULT_BOOST_TEMP_TIME = 60 DEFAULT_SCAN_INTERVAL = 30 DEFAULT_SETPOINT_MODE = "normal" +DEFAULT_PASSIVE_TEMP_INCREMENT = 0.5 # Setpoint Modes SETPOINT_MODE_BOOST = "boost" SETPOINT_MODE_BOOST_AUTO = "boost auto mode only" # Custom Configs -CONF_AUTOMATIONS = "automations" +CONF_AUTOMATIONS_PASSIVE = "automations_passive_mode" +CONF_AUTOMATIONS_PASSIVE_TEMP_INCREMENT = "passive_mode_temperature_increments" CONF_HEATING_BOOST_TEMP = "heating_boost_temp" CONF_HEATING_BOOST_TIME = "heating_boost_time" CONF_HW_BOOST_TIME = "hotwater_boost_time" CONF_SETPOINT_MODE = "setpoint_mode" -CONF_MOMENTS = "moments" -CONF_LTS_SENSORS = "lts_sensors" CONF_HOSTNAME = "hostname" CONF_RESTORE_MANUAL_TEMP_OPTION = "restore_manual_temp_option" @@ -99,9 +100,9 @@ } WISER_SETPOINT_MODES = { - "Normal": "normal", - "Boost": "boost", - "BoostAuto": "boost in auto mode only", + "Normal": "Normal", + "Boost": "Boost", + "BoostAuto": "Boost in auto mode only", } WISER_RESTORE_TEMP_DEFAULT_OPTIONS = ["Current", "Scheduled", "Minimum"] diff --git a/custom_components/wiser/coordinator.py b/custom_components/wiser/coordinator.py index 76904be3..8bbd8cfe 100644 --- a/custom_components/wiser/coordinator.py +++ b/custom_components/wiser/coordinator.py @@ -26,15 +26,16 @@ ) from .const import ( - CONF_AUTOMATIONS, - CONF_MOMENTS, + CONF_AUTOMATIONS_PASSIVE, + CONF_AUTOMATIONS_PASSIVE_TEMP_INCREMENT, CONF_RESTORE_MANUAL_TEMP_OPTION, CONF_SETPOINT_MODE, + CUSTOM_DATA_STORE, + DEFAULT_PASSIVE_TEMP_INCREMENT, DEFAULT_SETPOINT_MODE, CONF_HEATING_BOOST_TEMP, CONF_HEATING_BOOST_TIME, CONF_HW_BOOST_TIME, - CONF_LTS_SENSORS, DEFAULT_BOOST_TEMP, DEFAULT_BOOST_TEMP_TIME, DEFAULT_SCAN_INTERVAL, @@ -89,6 +90,8 @@ def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None: self.last_update_status = "" self.minimum_temp = TEMP_MINIMUM self.maximum_temp = TEMP_MAXIMUM + + # Main option params self.boost_temp = config_entry.options.get( CONF_HEATING_BOOST_TEMP, DEFAULT_BOOST_TEMP ) @@ -101,19 +104,25 @@ def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None: self.setpoint_mode = config_entry.options.get( CONF_SETPOINT_MODE, DEFAULT_SETPOINT_MODE ) - self.enable_automations = config_entry.options.get(CONF_AUTOMATIONS, False) - self.enable_moments = config_entry.options.get(CONF_MOMENTS, False) - self.enable_lts_sensors = config_entry.options.get(CONF_LTS_SENSORS, False) self.previous_target_temp_option = config_entry.options.get( CONF_RESTORE_MANUAL_TEMP_OPTION, "Schedule" ) + # Automation option params + self.enable_automations_passive_mode = config_entry.options.get( + CONF_AUTOMATIONS_PASSIVE, False + ) + + self.passive_temperature_increment = config_entry.options.get( + CONF_AUTOMATIONS_PASSIVE_TEMP_INCREMENT, DEFAULT_PASSIVE_TEMP_INCREMENT + ) + self.wiserhub = WiserAPI( host=config_entry.data[CONF_HOST], secret=config_entry.data[CONF_PASSWORD], session=async_get_clientsession(hass), - extra_config_file=hass.config.config_dir + "/.storage/wiser_custom_data", - enable_automations=self.enable_automations, + extra_config_file=hass.config.config_dir + CUSTOM_DATA_STORE, + enable_automations=self.enable_automations_passive_mode, ) async def async_update_data(self) -> WiserData: diff --git a/custom_components/wiser/manifest.json b/custom_components/wiser/manifest.json index 6497c515..edea5944 100755 --- a/custom_components/wiser/manifest.json +++ b/custom_components/wiser/manifest.json @@ -7,7 +7,7 @@ "issue_tracker": "https://github.com/asantaga/wiserHomeAssistantPlatform/issues", "dependencies": ["http", "websocket_api", "frontend", "lovelace"], "codeowners": ["@asantaga", "@msp1974"], - "version": "3.3.0", - "requirements": ["aioWiserHeatAPI==1.1.0"], + "version": "3.3.1", + "requirements": ["aioWiserHeatAPI==1.3.1"], "zeroconf": [{ "type": "_http._tcp.local.", "name": "wiser*" }] } diff --git a/custom_components/wiser/select.py b/custom_components/wiser/select.py index f51208f9..b46a77ff 100644 --- a/custom_components/wiser/select.py +++ b/custom_components/wiser/select.py @@ -4,6 +4,7 @@ DATA, DOMAIN, MANUFACTURER, + ROOM, ) from .helpers import get_device_name, get_unique_id, get_identifier diff --git a/custom_components/wiser/sensor.py b/custom_components/wiser/sensor.py index abf647fd..3fce7aa1 100755 --- a/custom_components/wiser/sensor.py +++ b/custom_components/wiser/sensor.py @@ -100,24 +100,21 @@ async def async_setup_entry(hass, config_entry, async_add_entities): ) # Add LTS sensors - for room temp and target temp - if data.enable_lts_sensors: - _LOGGER.debug("Setting up LTS sensors") - for room in data.wiserhub.rooms.all: - if room.devices: - wiser_sensors.extend( - [ - WiserLTSTempSensor(data, room.id, sensor_type="current_temp"), - WiserLTSTempSensor( - data, room.id, sensor_type="current_target_temp" - ), - WiserLTSDemandSensor(data, room.id, "room"), - ] - ) + _LOGGER.debug("Setting up LTS sensors") + for room in data.wiserhub.rooms.all: + if room.devices: + wiser_sensors.extend( + [ + WiserLTSTempSensor(data, room.id, sensor_type="current_temp"), + WiserLTSTempSensor( + data, room.id, sensor_type="current_target_temp" + ), + WiserLTSDemandSensor(data, room.id, "room"), + ] + ) - # Add humidity sensor for Roomstat - for roomstat in data.wiserhub.devices.roomstats.all: - _LOGGER.debug("Setting up Roomstat humidity sensors") - wiser_sensors.append(WiserLTSHumiditySensor(data, roomstat.id)) + if room.roomstat_id: + wiser_sensors.append(WiserLTSHumiditySensor(data, room.roomstat_id)) # Add LTS sensors - for room Power and Energy for heating actuators if data.wiserhub.devices.heating_actuators: @@ -848,6 +845,7 @@ def extra_state_attributes(self): "relative_modulation_level" ] = operational_data.relative_modulation_level attrs["hw_temperature"] = operational_data.hw_temperature + attrs["hw_flow_rate"] = operational_data.hw_flow_rate attrs["slave_status"] = operational_data.slave_status boiler_params = opentherm.boiler_parameters @@ -857,6 +855,7 @@ def extra_state_attributes(self): attrs[ "boiler_ch_max_setpoint_transfer_enable" ] = boiler_params.ch_max_setpoint_transfer_enable + attrs["boiler_ch_setpoint"] = boiler_params.ch_setpoint attrs[ "boiler_ch_setpoint_lower_bound" ] = boiler_params.ch_setpoint_lower_bound @@ -869,6 +868,7 @@ def extra_state_attributes(self): attrs[ "boiler_hw_setpoint_transfer_enable" ] = boiler_params.hw_setpoint_transfer_enable + attrs["boiler_hw_setpoint"] = boiler_params.hw_setpoint attrs[ "boiler_hw_setpoint_lower_bound" ] = boiler_params.hw_setpoint_lower_bound diff --git a/custom_components/wiser/strings.json b/custom_components/wiser/strings.json index 91c349d5..eb463004 100755 --- a/custom_components/wiser/strings.json +++ b/custom_components/wiser/strings.json @@ -33,19 +33,28 @@ "options": { "step": { "init": { - "title": "Wiser Heat Hub Options", - "description": "Amend Wiser parameters.", + "title": "Wiser Integration Options", + "description": "Select parameters to amend" + }, + "main_params": { + "title": "Wiser Integration Options", + "description": "Main Parameters", "data": { "host": "IP Address or Hostname", - "scan_interval": "Scan Interval", - "heating_boost_temp": "Default Heating Boost Temperature", - "heating_boost_time": "Default Heating Boost Duration", - "hotwater_boost_time": "Default Hot Water Boost Duration", + "scan_interval": "Scan Interval (secs)", + "heating_boost_temp": "Default Heating Boost Temperature (°C)", + "heating_boost_time": "Default Heating Boost Duration (mins)", + "hotwater_boost_time": "Default Hot Water Boost Duration (mins)", "setpoint_mode": "Setpoint Mode", - "restore_manual_temp_option": "Use This Temperature If No Stored Manual Temperature", - "automations": "Enable Integration Automations (beta)", - "moments": "Enable Moments Buttons", - "lts_sensors": "Enable LTS Sensors" + "restore_manual_temp_option": "Use This Temperature If No Stored Manual Temperature" + } + }, + "automation_params": { + "title": "Wiser Integration Options", + "description": "Enable in-built automations", + "data": { + "automations_passive_mode": "Enable Passive Mode", + "passive_mode_temperature_increments": "Passive Mode Temperature Increments" } } } diff --git a/custom_components/wiser/switch.py b/custom_components/wiser/switch.py index 1caafd66..ba3ca6fd 100755 --- a/custom_components/wiser/switch.py +++ b/custom_components/wiser/switch.py @@ -148,7 +148,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): ) # Add Room passive mode switches - if data.enable_automations: + if data.enable_automations_passive_mode: for room in data.wiserhub.rooms.all: if room.number_of_smartvalves > 0: wiser_switches.append( @@ -156,6 +156,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): hass, data, room.id, f"Wiser Passive Mode {room.name}" ) ) + async_add_entities(wiser_switches) return True @@ -659,17 +660,17 @@ def __init__(self, hass, data, room_id, name): self._room_id = room_id self._hass = hass super().__init__(data, name, "", "passive-mode", "mdi:thermostat-box") - self._is_on = ( - self._data.wiserhub.rooms.get_by_id(self._room_id).mode == "Passive" - ) + self._is_on = self._data.wiserhub.rooms.get_by_id( + self._room_id + ).passive_mode_enabled @callback def _handle_coordinator_update(self) -> None: """Async Update to HA.""" super()._handle_coordinator_update() - self._is_on = ( - self._data.wiserhub.rooms.get_by_id(self._room_id).mode == "Passive" - ) + self._is_on = self._data.wiserhub.rooms.get_by_id( + self._room_id + ).passive_mode_enabled self.async_write_ha_state() @property @@ -703,16 +704,14 @@ def extra_state_attributes(self): async def async_turn_on(self, **kwargs): """Turn the device on.""" - await self._data.wiserhub.rooms.get_by_id(self._room_id).enable_passive_mode( - True - ) + await self._data.wiserhub.rooms.get_by_id(self._room_id).set_passive_mode(True) await self.async_force_update() return True async def async_turn_off(self, **kwargs): """Turn the device off.""" - await self._data.wiserhub.rooms.get_by_id(self._room_id).enable_passive_mode( - False - ) + room = self._data.wiserhub.rooms.get_by_id(self._room_id) + await room.set_passive_mode(False) + await room.cancel_overrides() await self.async_force_update() return True diff --git a/custom_components/wiser/translations/de.json b/custom_components/wiser/translations/de.json index e0ced3ae..ebce1427 100644 --- a/custom_components/wiser/translations/de.json +++ b/custom_components/wiser/translations/de.json @@ -33,8 +33,16 @@ "options": { "step": { "init": { - "title": "Wiser Heat Hub-Optionen", + "title": "Wiser Integrationsoptionen", "description": "Wiser-Parameter ändern.", + "menu_options": { + "main_params": "Hauptparameter", + "automation_params": "Aktivieren Sie integrierte Automatisierungen" + } + }, + "main_params": { + "title": "Wiser Integrationsoptionen", + "description": "Hauptparameter", "data": { "host": "IP Adresse", "scan_interval": "Scan Intervall", @@ -42,10 +50,15 @@ "heating_boost_time": "Boost Dauer", "hotwater_boost_time": "Standard-Warmwasser-Boost-Dauer", "setpoint_mode": "Sollwert-Modus", - "restore_manual_temp_option": "Verwenden Sie diese Temperatur, wenn keine gespeicherte manuelle Temperatur vorhanden ist", - "automations": "Integrationsautomatisierung aktivieren (beta)", - "moments": "Moments-Schaltflächen aktivieren", - "lts_sensors": "LTS-Sensoren aktivieren" + "restore_manual_temp_option": "Verwenden Sie diese Temperatur, wenn keine gespeicherte manuelle Temperatur vorhanden ist" + } + }, + "automation_params": { + "title": "Wiser Integrationsoptionen", + "description": "Aktivieren Sie integrierte Automatisierungen", + "data": { + "automations_passive_mode": "Passivmodus", + "passive_mode_temperature_increments": "Temperaturerhöhungen im passiven Modus" } } } diff --git a/custom_components/wiser/translations/en.json b/custom_components/wiser/translations/en.json index 6caddfa8..c9b15103 100755 --- a/custom_components/wiser/translations/en.json +++ b/custom_components/wiser/translations/en.json @@ -33,19 +33,32 @@ "options": { "step": { "init": { - "title": "Wiser Heat Hub Options", - "description": "Amend Wiser parameters.", + "title": "Wiser Integration Options", + "description": "Select parameters to amend", + "menu_options": { + "main_params": "Main Parameters", + "automation_params": "Automation Parameters" + } + }, + "main_params": { + "title": "Wiser Integration Options", + "description": "Main Parameters", "data": { "host": "IP Address or Hostname", - "scan_interval": "Scan Interval", - "heating_boost_temp": "Default Heating Boost Temperature", - "heating_boost_time": "Default Heating Boost Duration", - "hotwater_boost_time": "Default Hot Water Boost Duration", + "scan_interval": "Scan Interval (secs)", + "heating_boost_temp": "Default Heating Boost Temperature (°C)", + "heating_boost_time": "Default Heating Boost Duration (mins)", + "hotwater_boost_time": "Default Hot Water Boost Duration (mins)", "setpoint_mode": "Setpoint Mode", - "restore_manual_temp_option": "Use This Temperature If No Stored Manual Temperature", - "automations": "Enable Integration Automations (beta)", - "moments": "Enable Moments Buttons", - "lts_sensors": "Enable LTS Sensors" + "restore_manual_temp_option": "Use This Temperature If No Stored Manual Temperature" + } + }, + "automation_params": { + "title": "Wiser Integration Options", + "description": "Enable in-built automations", + "data": { + "automations_passive_mode": "Passive Mode", + "passive_mode_temperature_increments": "Passive Mode Temperature Increments" } } } diff --git a/custom_components/wiser/translations/fr.json b/custom_components/wiser/translations/fr.json index 9c5e8477..33ac41aa 100644 --- a/custom_components/wiser/translations/fr.json +++ b/custom_components/wiser/translations/fr.json @@ -33,19 +33,32 @@ "options": { "step": { "init": { - "title": "Options Box Wiser", + "title": "Wiser possibilités d'intégration", "description": "Réglages des paramètres Wiser.", + "menu_options": { + "main_params": "Paramètres principaux", + "automation_params": "Paramètres d'automatisation" + } + }, + "main_params": { + "title": "Wiser possibilités d'intégration", + "description": "Paramètres principaux", "data": { "host": "Adresse IP ou nom d'hote", "scan_interval": " Période d'acquisition", - "heating_boost_temp": "Défault Temperature de Boost chauffage", - "heating_boost_time": "Défault Durée de Boost chauffage", - "hotwater_boost_time": "Défault Durée de Boost Eau Chaude", + "heating_boost_temp": "Défault temperature de boost chauffage", + "heating_boost_time": "Défault durée de boost chauffage", + "hotwater_boost_time": "Défault durée de boost eau chaude", "setpoint_mode": "Mode de fonctionnement consigne", - "restore_manual_temp_option": "Utilisez cette température si aucune température manuelle stockée", - "automations": "Autorisation des automatisations d'intégration (bêta)", - "moments": "Autorisation de boutons Moments", - "lts_sensors": "Autorisation capteurs LTS (Longue Durée de Sauvegarde)" + "restore_manual_temp_option": "Utilisez cette température si aucune température manuelle stockée" + } + }, + "automation_params": { + "title": "Wiser possibilités d'intégration", + "description": "Activer les automatisations intégrées", + "data": { + "automations_passive_mode": "Mode passif", + "passive_mode_temperature_increments": "Incréments de température en mode passif" } } } diff --git a/docs/inbuilt_automations.md b/docs/inbuilt_automations.md new file mode 100644 index 00000000..16df1f7c --- /dev/null +++ b/docs/inbuilt_automations.md @@ -0,0 +1,55 @@ +# In Built Automations + +Currently there is only a single in built automation but more may come in the future. + +## Passive Mode + +Passive mode is designed to achieve a function that is not natively available from Wiser on the hub. It is designed to set a room to only heat when other non-passive mode rooms call for heat (causing the boiler to fire). + +It does this by setting the target temperature of the room lower than the current temp (down to the minimum setting) when no non-passive rooms are heating and then increasing the target temperature of the room when non-passive rooms are calling for heat thus heating the room to the set maximum temperature without the room itself causing the boiler to fire. + +As this is not a native hub function, there are some things to be aware of. + +1. The target temperature of the room is changed by the integration, so in the Wiser app or on a roomstat you may see unusual target temp settings for passive rooms. +2. The Wiser app will not show passive mode, just whther the room is following the schedule or not and the temperature settgin being driven by the automation. +3. If you use comfort mode to get your rooms up to temperature by a scheduled time, then this will not apply to passive rooms. You will need to adjust your schedule to set the passive upper temperature earlier so that it will heat that room as other non-passive rooms heat under comfort mode. +4. Putting the hub in away mode will override passive mode and it will not function when in away mode. However, there are functions which will override away mode and take the room out of this, however, this is a function of the Wiser system and how away mode is applied to rooms. +5. If you boost the room, this will also override passive mode and make the room non-passive whilst the boost is active. At the end of the boost duration, it will return to passive mode. This applies in both HVAC modes as described below. + +## Enabling Passive Mode + +You will need to enable this in the integration configuration Automation Options menu. Once done, you will have a new switch entity in every room (with iTRVs) to enable/disable passive mode for that room. + +When you enable passive mode for a room, the thermostat card will change to have a temperature range instead of the usual single target temperature. + +There are 2 modes of operation: + +1. HVAC Auto - In Auto mode, the passive mode will allow setting of the lower temp (which will cause the boiler to fire if the room temp goes below this lower setting), however, the upper temp settign is driven by the rooms schedule. If you try to change this via the thermostat card, it will revert within a couple of seconds to the scheduled temp setting. + +2. HVAC Heat - Also known as manual mode in the Wiser app. This allows manual setting of the lower and upper temperatures for that room for which passive mode will manage. These values are stored and will revert if you take the room out and then back into passive mode. The lower temperature setting is common to both HVAC modes. + +## Colour of Thermostat Card + +Due to the way passive mode works, to be as compatible as possible with other integrations (especially assistants like Alexa, Google Home, Homekit etc), when in passive mode, the colour of the thermostat card icons and slider represent the HVAC mode with the designation on the heating status as Idle - Passive or Heating - Passive and the fact that the slider is a range instead of a single target. If you wish for the card to show different colours when in passive mode, you can achieve this using card-mod. The below example shows how to do this and make the card light green when in Auto-Passive and light orange when in Heat-Passive. You can obviously change this to whatever colours you prefer. + +```yaml +type: thermostat +entity: climate.wiser_office +card_mod: + style: |- + {%- if state_attr(config.entity, 'is_passive') -%} + ha-card { + --state-climate-heat-color: var(--amber-color); + --state-climate-auto-color: var(--light-green-color); + } + {%- endif -%} +``` + +Some example pictures of the thermostat card + +![Auto-Passive](passive-auto.png) +![Heat-Passive](passive-heat.png) + +And a short video of it in use + +![Passive Mode Video](passive_mode_demo.gif) \ No newline at end of file diff --git a/docs/passive-auto.png b/docs/passive-auto.png new file mode 100644 index 00000000..bbb62dbf Binary files /dev/null and b/docs/passive-auto.png differ diff --git a/docs/passive-heat.png b/docs/passive-heat.png new file mode 100644 index 00000000..6393cdad Binary files /dev/null and b/docs/passive-heat.png differ diff --git a/docs/passive_mode_demo.gif b/docs/passive_mode_demo.gif new file mode 100644 index 00000000..334dfcbd Binary files /dev/null and b/docs/passive_mode_demo.gif differ diff --git a/hacs.json b/hacs.json index b17111e9..353d49c2 100644 --- a/hacs.json +++ b/hacs.json @@ -1,6 +1,6 @@ { "name": "Drayton Wiser Integration for Home Assistant", - "homeassistant": "2022.09", + "homeassistant": "2023.02", "render_readme": true, "zip_release": true, "filename": "wiser.zip"