Skip to content

Commit

Permalink
feat: add preset mode support (#52)
Browse files Browse the repository at this point in the history
* add preset mode option

* Update README.md

Update README for adding preset modes

* refactor: reformat with black

---------

Co-authored-by: Josh Willox <[email protected]>
  • Loading branch information
scuba75 and jcwillox committed Jul 20, 2024
1 parent 06e1e77 commit bb71c1d
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,20 @@ If you do not define a `template` or its corresponding `action` the climate devi
| target_temperature_low_template | [`template`](https://www.home-assistant.io/docs/configuration/templating) | Defines a template to get the target temperature low of the climate device. | |
| hvac_mode_template | [`template`](https://www.home-assistant.io/docs/configuration/templating) | Defines a template to get the hvac mode of the climate device. | |
| fan_mode_template | [`template`](https://www.home-assistant.io/docs/configuration/templating) | Defines a template to get the fan mode of the climate device. | |
| preset_mode_template | [`template`](https://www.home-assistant.io/docs/configuration/templating) | Defines a template to get the preset mode of the climate device. | |
| swing_mode_template | [`template`](https://www.home-assistant.io/docs/configuration/templating) | Defines a template to get the swing mode of the climate device. | |
| hvac_action_template | [`template`](https://www.home-assistant.io/docs/configuration/templating) | Defines a template to get the [`hvac action`](https://developers.home-assistant.io/docs/core/entity/climate/#hvac-action) of the climate device. | |
| | | | |
| set_humidity | [`action`](https://www.home-assistant.io/docs/scripts) | Defines an action to run when the climate device is given the set humidity command. Can use `humidity` variable. | |
| set_temperature | [`action`](https://www.home-assistant.io/docs/scripts) | Defines an action to run when the climate device is given the set temperature command. Can use `temperature`, `target_temp_high`, `target_temp_low` and `hvac_mode` variables. | |
| set_hvac_mode | [`action`](https://www.home-assistant.io/docs/scripts) | Defines an action to run when the climate device is given the set hvac mode command. Can use `hvac_mode` variable. | |
| set_fan_mode | [`action`](https://www.home-assistant.io/docs/scripts) | Defines an action to run when the climate device is given the set fan mode command. Can use `fan_mode` variable. | |
| set_preset_mode | [`action`](https://www.home-assistant.io/docs/scripts) | Defines an action to run when the climate device is given the set preset mode command. Can use `preset_mode` variable. | |
| set_swing_mode | [`action`](https://www.home-assistant.io/docs/scripts) | Defines an action to run when the climate device is given the set swing mode command. Can use `swing_mode` variable. | |
| | | | |
| modes | `list` | A list of supported hvac modes. Needs to be a subset of the default values. | ["auto", "off", "cool", "heat", "dry", "fan_only"] |
| fan_modes | `list` | A list of supported fan modes. | ["auto", "low", "medium", "high"] |
| preset_modes | `list` | A list of supported preset modes. | ["activity", "away", "boost", "comfort", "eco", "home", "sleep"] |
| swing_modes | `list` | A list of supported swing modes. | ["on", "off"] |
| | | | |
| min_temp | `float` | Minimum set point available. | 7 |
Expand Down
74 changes: 74 additions & 0 deletions custom_components/climate_template/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
ATTR_MAX_TEMP,
ATTR_HVAC_MODE,
ATTR_FAN_MODE,
ATTR_PRESET_MODE,
ATTR_SWING_MODE,
ATTR_CURRENT_TEMPERATURE,
ATTR_CURRENT_HUMIDITY,
Expand All @@ -26,6 +27,13 @@
FAN_LOW,
FAN_MEDIUM,
FAN_HIGH,
PRESET_ACTIVITY,
PRESET_AWAY,
PRESET_BOOST,
PRESET_COMFORT,
PRESET_ECO,
PRESET_HOME,
PRESET_SLEEP,
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
HVACMode,
Expand Down Expand Up @@ -55,6 +63,7 @@
_LOGGER = logging.getLogger(__name__)

CONF_FAN_MODE_LIST = "fan_modes"
CONF_PRESET_MODE_LIST = "preset_modes"
CONF_MODE_LIST = "modes"
CONF_SWING_MODE_LIST = "swing_modes"
CONF_TEMP_MIN_TEMPLATE = "min_temp_template"
Expand All @@ -74,13 +83,15 @@
CONF_TARGET_TEMPERATURE_LOW_TEMPLATE = "target_temperature_low_template"
CONF_HVAC_MODE_TEMPLATE = "hvac_mode_template"
CONF_FAN_MODE_TEMPLATE = "fan_mode_template"
CONF_PRESET_MODE_TEMPLATE = "preset_mode_template"
CONF_SWING_MODE_TEMPLATE = "swing_mode_template"
CONF_HVAC_ACTION_TEMPLATE = "hvac_action_template"

CONF_SET_HUMIDITY_ACTION = "set_humidity"
CONF_SET_TEMPERATURE_ACTION = "set_temperature"
CONF_SET_HVAC_MODE_ACTION = "set_hvac_mode"
CONF_SET_FAN_MODE_ACTION = "set_fan_mode"
CONF_SET_PRESET_MODE_ACTION = "set_preset_mode"
CONF_SET_SWING_MODE_ACTION = "set_swing_mode"

CONF_CLIMATES = "climates"
Expand All @@ -106,12 +117,14 @@
vol.Optional(CONF_TARGET_TEMPERATURE_LOW_TEMPLATE): cv.template,
vol.Optional(CONF_HVAC_MODE_TEMPLATE): cv.template,
vol.Optional(CONF_FAN_MODE_TEMPLATE): cv.template,
vol.Optional(CONF_PRESET_MODE_TEMPLATE): cv.template,
vol.Optional(CONF_SWING_MODE_TEMPLATE): cv.template,
vol.Optional(CONF_HVAC_ACTION_TEMPLATE): cv.template,
vol.Optional(CONF_SET_HUMIDITY_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_SET_TEMPERATURE_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_SET_HVAC_MODE_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_SET_FAN_MODE_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_SET_PRESET_MODE_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(CONF_SET_SWING_MODE_ACTION): cv.SCRIPT_SCHEMA,
vol.Optional(
CONF_MODE_LIST,
Expand All @@ -128,6 +141,18 @@
CONF_FAN_MODE_LIST,
default=[FAN_AUTO, FAN_LOW, FAN_MEDIUM, FAN_HIGH],
): cv.ensure_list,
vol.Optional(
CONF_PRESET_MODE_LIST,
default=[
PRESET_ECO,
PRESET_AWAY,
PRESET_BOOST,
PRESET_COMFORT,
PRESET_HOME,
PRESET_SLEEP,
PRESET_ACTIVITY,
],
): cv.ensure_list,
vol.Optional(
CONF_SWING_MODE_LIST, default=[STATE_ON, HVACMode.OFF]
): cv.ensure_list,
Expand Down Expand Up @@ -178,6 +203,7 @@ def __init__(self, hass: HomeAssistant, config: ConfigType):
self._target_humidity = None

self._current_fan_mode = FAN_LOW # default optimistic state
self._current_preset_mode = PRESET_COMFORT # default optimistic state
self._current_operation = HVACMode.OFF # default optimistic state
self._current_swing_mode = HVACMode.OFF # default optimistic state
self._target_temp = DEFAULT_TEMP # default optimistic state
Expand All @@ -198,6 +224,7 @@ def __init__(self, hass: HomeAssistant, config: ConfigType):
)
self._hvac_mode_template = config.get(CONF_HVAC_MODE_TEMPLATE)
self._fan_mode_template = config.get(CONF_FAN_MODE_TEMPLATE)
self._preset_mode_template = config.get(CONF_PRESET_MODE_TEMPLATE)
self._swing_mode_template = config.get(CONF_SWING_MODE_TEMPLATE)
self._hvac_action_template = config.get(CONF_HVAC_ACTION_TEMPLATE)

Expand All @@ -207,6 +234,7 @@ def __init__(self, hass: HomeAssistant, config: ConfigType):

self._attr_hvac_modes = config[CONF_MODE_LIST]
self._attr_fan_modes = config[CONF_FAN_MODE_LIST]
self._attr_preset_modes = config[CONF_PRESET_MODE_LIST]
self._swing_modes_list = config[CONF_SWING_MODE_LIST]

self.entity_id = async_generate_entity_id(
Expand Down Expand Up @@ -245,6 +273,14 @@ def __init__(self, hass: HomeAssistant, config: ConfigType):
)
self._attr_supported_features |= ClimateEntityFeature.FAN_MODE

self._set_preset_mode_script = None
set_preset_mode_action = config.get(CONF_SET_PRESET_MODE_ACTION)
if set_preset_mode_action:
self._set_preset_mode_script = Script(
hass, set_preset_mode_action, self._attr_name, DOMAIN
)
self._attr_supported_features |= ClimateEntityFeature.PRESET_MODE

self._set_temperature_script = None
set_temperature_action = config.get(CONF_SET_TEMPERATURE_ACTION)
if set_temperature_action:
Expand Down Expand Up @@ -299,6 +335,9 @@ async def async_added_to_hass(self):
self._current_fan_mode = previous_state.attributes.get(
ATTR_FAN_MODE, FAN_LOW
)
self._current_preset_mode = previous_state.attributes.get(
ATTR_PRESET_MODE, PRESET_COMFORT
)
self._current_swing_mode = previous_state.attributes.get(
ATTR_SWING_MODE, HVACMode.OFF
)
Expand Down Expand Up @@ -419,6 +458,14 @@ async def async_added_to_hass(self):
self._update_hvac_mode,
none_on_template_error=True,
)
if self._preset_mode_template:
self.add_template_attribute(
"_current_preset_mode",
self._preset_mode_template,
None,
self._update_preset_mode,
none_on_template_error=True,
)

if self._fan_mode_template:
self.add_template_attribute(
Expand Down Expand Up @@ -544,6 +591,17 @@ def _update_hvac_mode(self, hvac_mode):
self._attr_hvac_modes,
)

def _update_preset_mode(self, preset_mode):
if preset_mode in self._attr_preset_modes:
self._current_preset_mode = preset_mode
self.hass.async_create_task(self.async_set_preset_mode(preset_mode))
elif preset_mode not in (STATE_UNKNOWN, STATE_UNAVAILABLE):
_LOGGER.error(
"Received invalid preset mode %s. Expected %s.",
preset_mode,
self._attr_preset_modes,
)

def _update_fan_mode(self, fan_mode):
if fan_mode in self._attr_fan_modes:
self._current_fan_mode = fan_mode
Expand Down Expand Up @@ -649,6 +707,11 @@ def hvac_mode(self):
"""Return current operation ie. heat, cool, idle."""
return self._current_operation

@property
def preset_mode(self):
"""Return preset setting"""
return self._current_preset_mode

@property
def fan_mode(self):
"""Return the fan setting."""
Expand All @@ -675,6 +738,17 @@ async def async_set_hvac_mode(self, hvac_mode: str) -> None:
run_variables={ATTR_HVAC_MODE: hvac_mode}, context=self._context
)

async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set new preset mode."""
if self._preset_mode_template is None:
self._current_preset_mode = preset_mode
self.async_write_ha_state()

if self._set_preset_mode_script is not None:
await self._set_preset_mode_script.async_run(
run_variables={ATTR_PRESET_MODE: preset_mode}, context=self._context
)

async def async_set_fan_mode(self, fan_mode: str) -> None:
"""Set new fan mode."""
if self._fan_mode_template is None:
Expand Down

0 comments on commit bb71c1d

Please sign in to comment.