|
6 | 6 | import voluptuous as vol |
7 | 7 | from homeassistant import config_entries |
8 | 8 | from homeassistant.components import sensor, switch, valve, weather, binary_sensor, climate, input_boolean |
| 9 | +from homeassistant.components.climate import ( |
| 10 | + PRESET_ACTIVITY, |
| 11 | + PRESET_AWAY, |
| 12 | + PRESET_COMFORT, |
| 13 | + PRESET_HOME, |
| 14 | + PRESET_SLEEP, |
| 15 | +) |
9 | 16 | from homeassistant.config_entries import ConfigEntry |
10 | 17 | from homeassistant.core import callback |
11 | 18 | from homeassistant.helpers import selector, entity_registry |
@@ -628,46 +635,96 @@ async def async_step_general(self, _user_input: Optional[dict[str, Any]] = None) |
628 | 635 | ) |
629 | 636 | ) |
630 | 637 |
|
| 638 | + schema[vol.Required(CONF_SYNC_CLIMATES_WITH_PRESET, default=options[CONF_SYNC_CLIMATES_WITH_PRESET])] = bool |
| 639 | + schema[vol.Required(CONF_PUSH_SETPOINT_TO_THERMOSTAT, default=options[CONF_PUSH_SETPOINT_TO_THERMOSTAT])] = bool |
| 640 | + |
631 | 641 | return self.async_show_form(step_id="general", data_schema=vol.Schema(schema)) |
632 | 642 |
|
633 | 643 | async def async_step_presets(self, _user_input: Optional[dict[str, Any]] = None): |
634 | | - if _user_input is not None: |
635 | | - return await self.update_options(_user_input) |
| 644 | + if len(self._config_entry.data.get(CONF_ROOMS, [])) > 0: |
| 645 | + return self.async_show_menu( |
| 646 | + step_id="presets", |
| 647 | + menu_options=[ |
| 648 | + "preset_home", |
| 649 | + "preset_comfort", |
| 650 | + "preset_sleep", |
| 651 | + "preset_away", |
| 652 | + "preset_activity", |
| 653 | + ] |
| 654 | + ) |
| 655 | + |
| 656 | + return await self.async_step_preset_home(_user_input) |
| 657 | + |
| 658 | + async def async_step_preset_home(self, user_input: Optional[dict[str, Any]] = None): |
| 659 | + return await self._async_step_preset_settings(PRESET_HOME, CONF_HOME_TEMPERATURE, user_input) |
| 660 | + |
| 661 | + async def async_step_preset_comfort(self, user_input: Optional[dict[str, Any]] = None): |
| 662 | + return await self._async_step_preset_settings(PRESET_COMFORT, CONF_COMFORT_TEMPERATURE, user_input) |
| 663 | + |
| 664 | + async def async_step_preset_sleep(self, user_input: Optional[dict[str, Any]] = None): |
| 665 | + return await self._async_step_preset_settings(PRESET_SLEEP, CONF_SLEEP_TEMPERATURE, user_input) |
| 666 | + |
| 667 | + async def async_step_preset_away(self, user_input: Optional[dict[str, Any]] = None): |
| 668 | + return await self._async_step_preset_settings(PRESET_AWAY, CONF_AWAY_TEMPERATURE, user_input) |
| 669 | + |
| 670 | + async def async_step_preset_activity(self, user_input: Optional[dict[str, Any]] = None): |
| 671 | + return await self._async_step_preset_settings(PRESET_ACTIVITY, CONF_ACTIVITY_TEMPERATURE, user_input) |
| 672 | + |
| 673 | + async def _async_step_preset_settings(self, preset: str, preset_option_key: str, user_input: Optional[dict[str, Any]] = None): |
| 674 | + primary_key = "primary_temperature" |
| 675 | + if user_input is not None: |
| 676 | + options = await self.get_options() |
| 677 | + overrides = dict(options.get(CONF_PRESET_ROOM_OVERRIDES) or {}) |
| 678 | + room_overrides: dict[str, float] = {} |
| 679 | + |
| 680 | + for entity_id in self._config_entry.data.get(CONF_ROOMS, []): |
| 681 | + raw_value = user_input.get(entity_id) |
| 682 | + if raw_value is None: |
| 683 | + continue |
| 684 | + |
| 685 | + try: |
| 686 | + value = float(raw_value) |
| 687 | + except (TypeError, ValueError): |
| 688 | + continue |
| 689 | + |
| 690 | + if abs(value - float(user_input[primary_key])) > 0.001: |
| 691 | + room_overrides[entity_id] = value |
| 692 | + |
| 693 | + if room_overrides: |
| 694 | + overrides[preset] = room_overrides |
| 695 | + else: |
| 696 | + overrides.pop(preset, None) |
| 697 | + |
| 698 | + update = { |
| 699 | + preset_option_key: user_input[primary_key], |
| 700 | + CONF_PRESET_ROOM_OVERRIDES: overrides, |
| 701 | + } |
| 702 | + |
| 703 | + return await self.update_options(update) |
636 | 704 |
|
637 | 705 | options = await self.get_options() |
638 | | - schema_entries: list[tuple[Marker, Any]] = [ |
639 | | - ( |
640 | | - vol.Required(CONF_HOME_TEMPERATURE, default=options[CONF_HOME_TEMPERATURE]), |
641 | | - selector.NumberSelector(selector.NumberSelectorConfig(min=5, max=35, step=0.5, unit_of_measurement="°C")), |
642 | | - ), |
643 | | - ( |
644 | | - vol.Required(CONF_COMFORT_TEMPERATURE, default=options[CONF_COMFORT_TEMPERATURE]), |
645 | | - selector.NumberSelector(selector.NumberSelectorConfig(min=5, max=35, step=0.5, unit_of_measurement="°C")), |
646 | | - ), |
647 | | - ( |
648 | | - vol.Required(CONF_SLEEP_TEMPERATURE, default=options[CONF_SLEEP_TEMPERATURE]), |
649 | | - selector.NumberSelector(selector.NumberSelectorConfig(min=5, max=35, step=0.5, unit_of_measurement="°C")), |
650 | | - ), |
651 | | - ( |
652 | | - vol.Required(CONF_AWAY_TEMPERATURE, default=options[CONF_AWAY_TEMPERATURE]), |
653 | | - selector.NumberSelector(selector.NumberSelectorConfig(min=5, max=35, step=0.5, unit_of_measurement="°C")), |
654 | | - ), |
655 | | - ( |
656 | | - vol.Required(CONF_ACTIVITY_TEMPERATURE, default=options[CONF_ACTIVITY_TEMPERATURE]), |
657 | | - selector.NumberSelector(selector.NumberSelectorConfig(min=5, max=35, step=0.5, unit_of_measurement="°C")), |
658 | | - ), |
659 | | - (vol.Required(CONF_SYNC_CLIMATES_WITH_PRESET, default=options[CONF_SYNC_CLIMATES_WITH_PRESET]), bool), |
660 | | - (vol.Required(CONF_PUSH_SETPOINT_TO_THERMOSTAT, default=options[CONF_PUSH_SETPOINT_TO_THERMOSTAT]), bool), |
661 | | - ] |
| 706 | + overrides = options.get(CONF_PRESET_ROOM_OVERRIDES) or {} |
| 707 | + |
| 708 | + preset_overrides = overrides.get(preset, {}) |
| 709 | + preset_default = float(options[preset_option_key]) |
| 710 | + |
| 711 | + schema_fields: dict[Marker, Any] = { |
| 712 | + vol.Required(primary_key, default=preset_default): selector.NumberSelector( |
| 713 | + selector.NumberSelectorConfig(min=5, max=35, step=0.5, unit_of_measurement="°C") |
| 714 | + ) |
| 715 | + } |
| 716 | + |
| 717 | + for entity_id in self._config_entry.data.get(CONF_ROOMS, []): |
| 718 | + default_value = preset_overrides.get(entity_id, preset_default) |
| 719 | + schema_fields[vol.Required(entity_id, default=default_value)] = selector.NumberSelector(selector.NumberSelectorConfig(min=5, max=35, step=0.5, unit_of_measurement="°C")) |
662 | 720 |
|
663 | 721 | return self.async_show_form( |
664 | | - step_id="presets", |
665 | | - data_schema=vol.Schema({key: value for key, value in schema_entries}) |
| 722 | + step_id=f"preset_{preset}", |
| 723 | + data_schema=vol.Schema(schema_fields), |
666 | 724 | ) |
667 | 725 |
|
668 | 726 | async def async_step_areas(self, user_input: Optional[dict[str, Any]] = None): |
669 | 727 | room_weights: dict[str, float] = dict(self._options.get(CONF_ROOM_WEIGHTS, {})) |
670 | | - |
671 | 728 | room_entity_ids: list[str] = list(self._config_entry.data.get(CONF_ROOMS, [])) |
672 | 729 |
|
673 | 730 | # Build stable schema keys (entity_id) and friendly labels separately |
|
0 commit comments