Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions homeassistant/components/esphome/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
from homeassistant.core import callback
from homeassistant.exceptions import ServiceValidationError

from .const import DOMAIN
from .const import DOMAIN, TEMPERATURE_UNIT_MAP
from .entity import (
EsphomeEntity,
convert_api_error_ha_error,
Expand Down Expand Up @@ -133,7 +133,6 @@
class EsphomeClimateEntity(EsphomeEntity[ClimateInfo, ClimateState], ClimateEntity):
"""A climate implementation for ESPHome."""

_attr_temperature_unit = UnitOfTemperature.CELSIUS
_attr_translation_key = "climate"
_feature_flags = ClimateFeature(0)

Expand All @@ -145,6 +144,9 @@ def _on_static_info_update(self, static_info: EntityInfo) -> None:
self._feature_flags = ClimateFeature(
static_info.supported_feature_flags_compat(self._api_version)
)
self._attr_temperature_unit = TEMPERATURE_UNIT_MAP.get(
static_info.temperature_unit, UnitOfTemperature.CELSIUS
)
self._attr_precision = self._get_precision()
self._attr_hvac_modes = [
_CLIMATE_MODES.from_esphome(mode) for mode in static_info.supported_modes
Expand Down
9 changes: 9 additions & 0 deletions homeassistant/components/esphome/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

from typing import Final

from aioesphomeapi import TemperatureUnit
from awesomeversion import AwesomeVersion

from homeassistant.const import UnitOfTemperature

DOMAIN = "esphome"

CONF_ALLOW_SERVICE_CALLS = "allow_service_calls"
Expand All @@ -30,3 +33,9 @@

WAKE_WORDS_DIR_NAME = "custom_wake_words"
WAKE_WORDS_API_PATH = "/api/esphome/wake_words"

TEMPERATURE_UNIT_MAP: dict[TemperatureUnit | None, UnitOfTemperature] = {
TemperatureUnit.CELSIUS: UnitOfTemperature.CELSIUS,
TemperatureUnit.FAHRENHEIT: UnitOfTemperature.FAHRENHEIT,
TemperatureUnit.KELVIN: UnitOfTemperature.KELVIN,
}
5 changes: 4 additions & 1 deletion homeassistant/components/esphome/water_heater.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from homeassistant.const import ATTR_TEMPERATURE, PRECISION_TENTHS, UnitOfTemperature
from homeassistant.core import callback

from .const import TEMPERATURE_UNIT_MAP
from .entity import (
EsphomeEntity,
convert_api_error_ha_error,
Expand Down Expand Up @@ -51,14 +52,16 @@ class EsphomeWaterHeater(
):
"""A water heater implementation for ESPHome."""

_attr_temperature_unit = UnitOfTemperature.CELSIUS
_attr_precision = PRECISION_TENTHS

@callback
def _on_static_info_update(self, static_info: EntityInfo) -> None:
"""Set attrs from static info."""
super()._on_static_info_update(static_info)
static_info = self._static_info
self._attr_temperature_unit = TEMPERATURE_UNIT_MAP.get(
static_info.temperature_unit, UnitOfTemperature.CELSIUS
)
self._attr_min_temp = static_info.min_temperature
self._attr_max_temp = static_info.max_temperature
self._attr_target_temperature_step = static_info.target_temperature_step
Expand Down
44 changes: 43 additions & 1 deletion tests/components/esphome/test_climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
ClimatePreset,
ClimateState,
ClimateSwingMode,
TemperatureUnit,
)
import pytest
from syrupy.assertion import SnapshotAssertion
Expand All @@ -30,6 +31,7 @@
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
ATTR_TEMPERATURE,
DATA_COMPONENT,
DOMAIN as CLIMATE_DOMAIN,
FAN_HIGH,
SERVICE_SET_FAN_MODE,
Expand All @@ -41,7 +43,7 @@
SWING_BOTH,
HVACMode,
)
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.const import ATTR_ENTITY_ID, UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError

Expand Down Expand Up @@ -685,3 +687,43 @@ async def test_climate_entity_attribute_current_temperature_unsupported(
state = hass.states.get("climate.test_my_climate")
assert state is not None
assert state.attributes[ATTR_CURRENT_TEMPERATURE] is None


@pytest.mark.parametrize(
("temperature_unit", "expected_unit"),
[
(TemperatureUnit.CELSIUS, UnitOfTemperature.CELSIUS),
(TemperatureUnit.FAHRENHEIT, UnitOfTemperature.FAHRENHEIT),
(TemperatureUnit.KELVIN, UnitOfTemperature.KELVIN),
(
3,
UnitOfTemperature.CELSIUS,
), # unknown value maps to Celsius via aioesphomeapi
],
)
async def test_climate_entity_temperature_unit(
hass: HomeAssistant,
mock_client: APIClient,
mock_generic_device_entry: MockGenericDeviceEntryType,
temperature_unit: TemperatureUnit | int,
expected_unit: UnitOfTemperature,
) -> None:
"""Test that the temperature unit is passed through correctly."""
entity_info = [
ClimateInfo(
object_id="myclimate",
key=1,
name="my climate",
temperature_unit=temperature_unit,
)
]
states = [ClimateState(key=1, mode=ClimateMode.COOL, target_temperature=22)]
await mock_generic_device_entry(
mock_client=mock_client,
entity_info=entity_info,
states=states,
)
assert hass.states.get("climate.test_my_climate") is not None
entity = hass.data[DATA_COMPONENT].get_entity("climate.test_my_climate")
assert entity is not None
assert entity.temperature_unit == expected_unit
45 changes: 45 additions & 0 deletions tests/components/esphome/test_water_heater.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from aioesphomeapi import (
APIClient,
TemperatureUnit,
WaterHeaterFeature,
WaterHeaterInfo,
WaterHeaterMode,
Expand All @@ -15,6 +16,7 @@
from homeassistant.components.water_heater import (
ATTR_AWAY_MODE,
ATTR_OPERATION_LIST,
DATA_COMPONENT,
DOMAIN as WATER_HEATER_DOMAIN,
SERVICE_SET_AWAY_MODE,
SERVICE_SET_OPERATION_MODE,
Expand All @@ -27,6 +29,7 @@
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
ATTR_TEMPERATURE,
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant

Expand Down Expand Up @@ -462,3 +465,45 @@ async def test_water_heater_set_away_mode(
mock_client.water_heater_command.assert_has_calls(
[call(key=1, away=away_mode, device_id=0)]
)


@pytest.mark.parametrize(
("temperature_unit", "expected_unit"),
[
(TemperatureUnit.CELSIUS, UnitOfTemperature.CELSIUS),
(TemperatureUnit.FAHRENHEIT, UnitOfTemperature.FAHRENHEIT),
(TemperatureUnit.KELVIN, UnitOfTemperature.KELVIN),
(
3,
UnitOfTemperature.CELSIUS,
), # unknown value maps to Celsius via aioesphomeapi
],
)
async def test_water_heater_temperature_unit(
hass: HomeAssistant,
mock_client: APIClient,
mock_generic_device_entry: MockGenericDeviceEntryType,
temperature_unit: TemperatureUnit | int,
expected_unit: UnitOfTemperature,
) -> None:
"""Test that the temperature unit is passed through correctly."""
entity_info = [
WaterHeaterInfo(
object_id="my_boiler",
key=1,
name="My Boiler",
min_temperature=10.0,
max_temperature=85.0,
temperature_unit=temperature_unit,
)
]
states = [WaterHeaterState(key=1, target_temperature=50.0)]
await mock_generic_device_entry(
mock_client=mock_client,
entity_info=entity_info,
states=states,
)
assert hass.states.get("water_heater.test_my_boiler") is not None
entity = hass.data[DATA_COMPONENT].get_entity("water_heater.test_my_boiler")
assert entity is not None
assert entity.temperature_unit == expected_unit
Loading