From 5821915aadd003759492023bf40d21a159647d3a Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Sat, 1 Aug 2026 12:37:44 -0400 Subject: [PATCH] [heatpumpir] Expose configured min/max as the visual temperature range (#17985) --- esphome/components/heatpumpir/climate.py | 21 ++++++++++----- tests/component_tests/heatpumpir/__init__.py | 0 tests/component_tests/heatpumpir/test_init.py | 26 +++++++++++++++++++ 3 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 tests/component_tests/heatpumpir/__init__.py create mode 100644 tests/component_tests/heatpumpir/test_init.py diff --git a/esphome/components/heatpumpir/climate.py b/esphome/components/heatpumpir/climate.py index cd1b7d2bb06..21f7ea63938 100644 --- a/esphome/components/heatpumpir/climate.py +++ b/esphome/components/heatpumpir/climate.py @@ -8,6 +8,7 @@ from esphome.const import ( CONF_VISUAL, ) from esphome.core import CORE +from esphome.types import ConfigType CODEOWNERS = ["@rob-deutsch"] @@ -97,6 +98,18 @@ VERTICAL_DIRECTIONS = { "down": VerticalDirections.VERTICAL_DIRECTION_DOWN, } + +def _default_visual(config: ConfigType) -> ConfigType: + # Seed the visual min/max from the required min/max_temperature so the entity + # reports the configured range in Home Assistant instead of the ClimateIR + # 0-100 default. Done during validation so the effective range is visible in + # the dumped config and set before new_climate_ir() reads CONF_VISUAL. + visual = config.setdefault(CONF_VISUAL, {}) + visual.setdefault(CONF_MAX_TEMPERATURE, config[CONF_MAX_TEMPERATURE]) + visual.setdefault(CONF_MIN_TEMPERATURE, config[CONF_MIN_TEMPERATURE]) + return config + + CONFIG_SCHEMA = cv.All( climate_ir.climate_ir_with_receiver_schema(HeatpumpIRClimate).extend( { @@ -108,18 +121,12 @@ CONFIG_SCHEMA = cv.All( } ), cv.Any(cv.only_with_arduino, cv.only_on_esp32), + _default_visual, ) async def to_code(config): var = await climate_ir.new_climate_ir(config) - if CONF_VISUAL not in config: - config[CONF_VISUAL] = {} - visual = config[CONF_VISUAL] - if CONF_MAX_TEMPERATURE not in visual: - visual[CONF_MAX_TEMPERATURE] = config[CONF_MAX_TEMPERATURE] - if CONF_MIN_TEMPERATURE not in visual: - visual[CONF_MIN_TEMPERATURE] = config[CONF_MIN_TEMPERATURE] cg.add(var.set_protocol(config[CONF_PROTOCOL])) cg.add(var.set_horizontal_default(config[CONF_HORIZONTAL_DEFAULT])) cg.add(var.set_vertical_default(config[CONF_VERTICAL_DEFAULT])) diff --git a/tests/component_tests/heatpumpir/__init__.py b/tests/component_tests/heatpumpir/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/component_tests/heatpumpir/test_init.py b/tests/component_tests/heatpumpir/test_init.py new file mode 100644 index 00000000000..85da0c8bf50 --- /dev/null +++ b/tests/component_tests/heatpumpir/test_init.py @@ -0,0 +1,26 @@ +"""Tests for the heatpumpir climate config validation.""" + +from esphome.components.heatpumpir.climate import _default_visual +from esphome.const import CONF_MAX_TEMPERATURE, CONF_MIN_TEMPERATURE, CONF_VISUAL +from esphome.types import ConfigType + + +def test_default_visual_seeds_from_required_min_max() -> None: + """Without a visual block, the required min/max_temperature seed the visual + range so the entity reports it in Home Assistant instead of 0-100 (#17983).""" + config: ConfigType = {CONF_MIN_TEMPERATURE: 18, CONF_MAX_TEMPERATURE: 30} + _default_visual(config) + assert config[CONF_VISUAL][CONF_MIN_TEMPERATURE] == 18 + assert config[CONF_VISUAL][CONF_MAX_TEMPERATURE] == 30 + + +def test_default_visual_keeps_explicit() -> None: + """An explicit visual min/max is not overwritten by the required temps.""" + config: ConfigType = { + CONF_MIN_TEMPERATURE: 16, + CONF_MAX_TEMPERATURE: 32, + CONF_VISUAL: {CONF_MIN_TEMPERATURE: 18, CONF_MAX_TEMPERATURE: 30}, + } + _default_visual(config) + assert config[CONF_VISUAL][CONF_MIN_TEMPERATURE] == 18 + assert config[CONF_VISUAL][CONF_MAX_TEMPERATURE] == 30