mirror of
https://github.com/esphome/esphome.git
synced 2026-07-10 08:55:36 +00:00
preen
This commit is contained in:
@@ -9,6 +9,7 @@ from esphome.const import (
|
||||
CONF_COOL_DEADBAND,
|
||||
CONF_COOL_MODE,
|
||||
CONF_COOL_OVERRUN,
|
||||
CONF_CUSTOM_FAN_MODES,
|
||||
CONF_DEFAULT_MODE,
|
||||
CONF_DEFAULT_TARGET_TEMPERATURE_HIGH,
|
||||
CONF_DEFAULT_TARGET_TEMPERATURE_LOW,
|
||||
@@ -658,6 +659,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_PRESET): cv.ensure_list(PRESET_CONFIG_SCHEMA),
|
||||
cv.Optional(CONF_CUSTOM_FAN_MODES): cv.ensure_list(cv.string_strict),
|
||||
cv.Optional(CONF_ON_BOOT_RESTORE_FROM): validate_on_boot_restore_from,
|
||||
cv.Optional(CONF_PRESET_CHANGE): automation.validate_automation(
|
||||
single=True
|
||||
@@ -1008,3 +1010,21 @@ async def to_code(config):
|
||||
await automation.build_automation(
|
||||
var.get_preset_change_trigger(), [], config[CONF_PRESET_CHANGE]
|
||||
)
|
||||
|
||||
# Collect custom preset names from preset map (non-standard preset names only)
|
||||
custom_preset_names = [
|
||||
preset_config[CONF_NAME]
|
||||
for preset_config in config.get(CONF_PRESET, [])
|
||||
if preset_config[CONF_NAME].upper() not in climate.CLIMATE_PRESETS
|
||||
]
|
||||
if custom_preset_names:
|
||||
cg.add(var.set_custom_presets(custom_preset_names))
|
||||
|
||||
# Collect custom fan modes (filter out standard enum fan modes)
|
||||
custom_fan_modes = [
|
||||
mode
|
||||
for mode in config.get(CONF_CUSTOM_FAN_MODES, [])
|
||||
if mode.upper() not in climate.CLIMATE_FAN_MODES
|
||||
]
|
||||
if custom_fan_modes:
|
||||
cg.add(var.set_custom_fan_modes(custom_fan_modes))
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
esphome:
|
||||
name: climate-custom-modes-test
|
||||
host:
|
||||
api:
|
||||
logger:
|
||||
|
||||
sensor:
|
||||
- platform: template
|
||||
id: thermostat_sensor
|
||||
lambda: "return 22.0;"
|
||||
|
||||
climate:
|
||||
- platform: thermostat
|
||||
id: test_thermostat
|
||||
name: Test Thermostat Custom Modes
|
||||
sensor: thermostat_sensor
|
||||
preset:
|
||||
- name: Away
|
||||
default_target_temperature_low: 16°C
|
||||
default_target_temperature_high: 20°C
|
||||
- name: Eco Plus
|
||||
default_target_temperature_low: 18°C
|
||||
default_target_temperature_high: 22°C
|
||||
- name: Super Saver
|
||||
default_target_temperature_low: 20°C
|
||||
default_target_temperature_high: 24°C
|
||||
- name: Vacation Mode
|
||||
default_target_temperature_low: 15°C
|
||||
default_target_temperature_high: 18°C
|
||||
custom_fan_modes:
|
||||
- "Turbo"
|
||||
- "Silent"
|
||||
- "Sleep Mode"
|
||||
idle_action:
|
||||
- logger.log: idle_action
|
||||
cool_action:
|
||||
- logger.log: cool_action
|
||||
heat_action:
|
||||
- logger.log: heat_action
|
||||
min_cooling_off_time: 10s
|
||||
min_cooling_run_time: 10s
|
||||
min_heating_off_time: 10s
|
||||
min_heating_run_time: 10s
|
||||
min_idle_time: 10s
|
||||
@@ -0,0 +1,51 @@
|
||||
"""Integration test for climate custom fan modes and presets."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from aioesphomeapi import ClimateInfo, ClimatePreset
|
||||
import pytest
|
||||
|
||||
from .types import APIClientConnectedFactory, RunCompiledFunction
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_climate_custom_fan_modes_and_presets(
|
||||
yaml_config: str,
|
||||
run_compiled: RunCompiledFunction,
|
||||
api_client_connected: APIClientConnectedFactory,
|
||||
) -> None:
|
||||
"""Test that custom fan modes and presets are properly exposed via API."""
|
||||
async with run_compiled(yaml_config), api_client_connected() as client:
|
||||
# Get entities and services
|
||||
entities, services = await client.list_entities_services()
|
||||
climate_infos = [e for e in entities if isinstance(e, ClimateInfo)]
|
||||
assert len(climate_infos) == 1, "Expected exactly 1 climate entity"
|
||||
|
||||
test_climate = climate_infos[0]
|
||||
|
||||
# Verify custom fan modes are exposed
|
||||
custom_fan_modes = test_climate.supported_custom_fan_modes
|
||||
assert len(custom_fan_modes) == 3, (
|
||||
f"Expected 3 custom fan modes, got {len(custom_fan_modes)}"
|
||||
)
|
||||
assert "Turbo" in custom_fan_modes, "Expected 'Turbo' in custom fan modes"
|
||||
assert "Silent" in custom_fan_modes, "Expected 'Silent' in custom fan modes"
|
||||
assert "Sleep Mode" in custom_fan_modes, (
|
||||
"Expected 'Sleep Mode' in custom fan modes"
|
||||
)
|
||||
|
||||
# Verify enum presets are exposed (from preset: config map)
|
||||
assert ClimatePreset.AWAY in test_climate.supported_presets, (
|
||||
"Expected AWAY in enum presets"
|
||||
)
|
||||
|
||||
# Verify custom string presets are exposed (non-standard preset names from preset map)
|
||||
custom_presets = test_climate.supported_custom_presets
|
||||
assert len(custom_presets) == 3, (
|
||||
f"Expected 3 custom presets, got {len(custom_presets)}: {custom_presets}"
|
||||
)
|
||||
assert "Eco Plus" in custom_presets, "Expected 'Eco Plus' in custom presets"
|
||||
assert "Comfort" in custom_presets, "Expected 'Comfort' in custom presets"
|
||||
assert "Vacation Mode" in custom_presets, (
|
||||
"Expected 'Vacation Mode' in custom presets"
|
||||
)
|
||||
Reference in New Issue
Block a user