mirror of
https://github.com/home-assistant/core.git
synced 2026-04-20 16:39:02 +02:00
Fix fallback to local system unit in Tuya climate (#156999)
This commit is contained in:
@@ -24,14 +24,15 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import TuyaConfigEntry
|
||||
from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode, DPType
|
||||
from .entity import TuyaEntity
|
||||
from .models import (
|
||||
DPCodeBooleanWrapper,
|
||||
DPCodeEnumWrapper,
|
||||
DPCodeIntegerWrapper,
|
||||
find_dpcode,
|
||||
from .const import (
|
||||
CELSIUS_ALIASES,
|
||||
FAHRENHEIT_ALIASES,
|
||||
TUYA_DISCOVERY_NEW,
|
||||
DeviceCategory,
|
||||
DPCode,
|
||||
)
|
||||
from .entity import TuyaEntity
|
||||
from .models import DPCodeBooleanWrapper, DPCodeEnumWrapper, DPCodeIntegerWrapper
|
||||
|
||||
TUYA_HVAC_TO_HA = {
|
||||
"auto": HVACMode.HEAT_COOL,
|
||||
@@ -90,80 +91,82 @@ CLIMATE_DESCRIPTIONS: dict[DeviceCategory, TuyaClimateEntityDescription] = {
|
||||
}
|
||||
|
||||
|
||||
def _get_temperature_wrapper(
|
||||
wrappers: list[DPCodeIntegerWrapper | None], aliases: set[str]
|
||||
) -> DPCodeIntegerWrapper | None:
|
||||
"""Return first wrapper with matching unit."""
|
||||
return next(
|
||||
(
|
||||
wrapper
|
||||
for wrapper in wrappers
|
||||
if wrapper is not None
|
||||
and (unit := wrapper.type_information.unit)
|
||||
and unit.lower() in aliases
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
|
||||
def _get_temperature_wrappers(
|
||||
device: CustomerDevice, system_temperature_unit: UnitOfTemperature
|
||||
) -> tuple[DPCodeIntegerWrapper | None, DPCodeIntegerWrapper | None, UnitOfTemperature]:
|
||||
"""Get temperature wrappers for current and set temperatures."""
|
||||
current_temperature_wrapper: DPCodeIntegerWrapper | None = None
|
||||
set_temperature_wrapper: DPCodeIntegerWrapper | None = None
|
||||
# Get all possible temperature dpcodes
|
||||
temp_current = DPCodeIntegerWrapper.find_dpcode(
|
||||
device, (DPCode.TEMP_CURRENT, DPCode.UPPER_TEMP)
|
||||
)
|
||||
temp_current_f = DPCodeIntegerWrapper.find_dpcode(
|
||||
device, (DPCode.TEMP_CURRENT_F, DPCode.UPPER_TEMP_F)
|
||||
)
|
||||
temp_set = DPCodeIntegerWrapper.find_dpcode(
|
||||
device, DPCode.TEMP_SET, prefer_function=True
|
||||
)
|
||||
temp_set_f = DPCodeIntegerWrapper.find_dpcode(
|
||||
device, DPCode.TEMP_SET_F, prefer_function=True
|
||||
)
|
||||
|
||||
# Default to System Temperature Unit
|
||||
temperature_unit = system_temperature_unit
|
||||
# Get wrappers for celsius and fahrenheit
|
||||
# We need to check the unit of measurement
|
||||
current_celsius = _get_temperature_wrapper(
|
||||
[temp_current, temp_current_f], CELSIUS_ALIASES
|
||||
)
|
||||
current_fahrenheit = _get_temperature_wrapper(
|
||||
[temp_current_f, temp_current], FAHRENHEIT_ALIASES
|
||||
)
|
||||
set_celsius = _get_temperature_wrapper([temp_set, temp_set_f], CELSIUS_ALIASES)
|
||||
set_fahrenheit = _get_temperature_wrapper(
|
||||
[temp_set_f, temp_set], FAHRENHEIT_ALIASES
|
||||
)
|
||||
|
||||
# If both temperature values for celsius and fahrenheit are present,
|
||||
# use whatever the device is set to, with a fallback to celsius.
|
||||
preferred_temperature_unit = None
|
||||
if all(
|
||||
dpcode in device.status
|
||||
for dpcode in (DPCode.TEMP_CURRENT, DPCode.TEMP_CURRENT_F)
|
||||
) or all(
|
||||
dpcode in device.status for dpcode in (DPCode.TEMP_SET, DPCode.TEMP_SET_F)
|
||||
):
|
||||
preferred_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
if any(
|
||||
"f" in device.status[dpcode].lower()
|
||||
for dpcode in (DPCode.C_F, DPCode.TEMP_UNIT_CONVERT)
|
||||
if isinstance(device.status.get(dpcode), str)
|
||||
# Return early if we have the right wrappers for the system unit
|
||||
if system_temperature_unit == UnitOfTemperature.FAHRENHEIT:
|
||||
if (
|
||||
(current_fahrenheit and set_fahrenheit)
|
||||
or (current_fahrenheit and not set_celsius)
|
||||
or (set_fahrenheit and not current_celsius)
|
||||
):
|
||||
preferred_temperature_unit = UnitOfTemperature.FAHRENHEIT
|
||||
|
||||
# Figure out current temperature, use preferred unit or what is available
|
||||
celsius_type = find_dpcode(
|
||||
device, (DPCode.TEMP_CURRENT, DPCode.UPPER_TEMP), dptype=DPType.INTEGER
|
||||
)
|
||||
fahrenheit_type = find_dpcode(
|
||||
device,
|
||||
(DPCode.TEMP_CURRENT_F, DPCode.UPPER_TEMP_F),
|
||||
dptype=DPType.INTEGER,
|
||||
)
|
||||
if fahrenheit_type and (
|
||||
preferred_temperature_unit == UnitOfTemperature.FAHRENHEIT
|
||||
or (
|
||||
preferred_temperature_unit == UnitOfTemperature.CELSIUS and not celsius_type
|
||||
)
|
||||
return current_fahrenheit, set_fahrenheit, UnitOfTemperature.FAHRENHEIT
|
||||
if (
|
||||
(current_celsius and set_celsius)
|
||||
or (current_celsius and not set_fahrenheit)
|
||||
or (set_celsius and not current_fahrenheit)
|
||||
):
|
||||
temperature_unit = UnitOfTemperature.FAHRENHEIT
|
||||
current_temperature_wrapper = DPCodeIntegerWrapper(
|
||||
fahrenheit_type.dpcode, fahrenheit_type
|
||||
)
|
||||
elif celsius_type:
|
||||
temperature_unit = UnitOfTemperature.CELSIUS
|
||||
current_temperature_wrapper = DPCodeIntegerWrapper(
|
||||
celsius_type.dpcode, celsius_type
|
||||
return current_celsius, set_celsius, UnitOfTemperature.CELSIUS
|
||||
|
||||
# If we don't have the right wrappers, return whatever is available
|
||||
# and assume system unit
|
||||
if system_temperature_unit == UnitOfTemperature.FAHRENHEIT:
|
||||
return (
|
||||
temp_current_f or temp_current,
|
||||
temp_set_f or temp_set,
|
||||
UnitOfTemperature.FAHRENHEIT,
|
||||
)
|
||||
|
||||
# Figure out setting temperature, use preferred unit or what is available
|
||||
celsius_type = find_dpcode(
|
||||
device, DPCode.TEMP_SET, dptype=DPType.INTEGER, prefer_function=True
|
||||
return (
|
||||
temp_current or temp_current_f,
|
||||
temp_set or temp_set_f,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
)
|
||||
fahrenheit_type = find_dpcode(
|
||||
device, DPCode.TEMP_SET_F, dptype=DPType.INTEGER, prefer_function=True
|
||||
)
|
||||
if fahrenheit_type and (
|
||||
preferred_temperature_unit == UnitOfTemperature.FAHRENHEIT
|
||||
or (
|
||||
preferred_temperature_unit == UnitOfTemperature.CELSIUS and not celsius_type
|
||||
)
|
||||
):
|
||||
set_temperature_wrapper = DPCodeIntegerWrapper(
|
||||
fahrenheit_type.dpcode, fahrenheit_type
|
||||
)
|
||||
elif celsius_type:
|
||||
set_temperature_wrapper = DPCodeIntegerWrapper(
|
||||
celsius_type.dpcode, celsius_type
|
||||
)
|
||||
|
||||
return current_temperature_wrapper, set_temperature_wrapper, temperature_unit
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
||||
@@ -49,6 +49,9 @@ TUYA_RESPONSE_QR_CODE = "qrcode"
|
||||
TUYA_RESPONSE_RESULT = "result"
|
||||
TUYA_RESPONSE_SUCCESS = "success"
|
||||
|
||||
CELSIUS_ALIASES = {"°c", "c", "celsius", "℃"}
|
||||
FAHRENHEIT_ALIASES = {"°f", "f", "fahrenheit", "℉"}
|
||||
|
||||
PLATFORMS = [
|
||||
Platform.ALARM_CONTROL_PANEL,
|
||||
Platform.BINARY_SENSOR,
|
||||
@@ -1159,12 +1162,12 @@ UNITS = (
|
||||
),
|
||||
UnitOfMeasurement(
|
||||
unit=UnitOfTemperature.CELSIUS,
|
||||
aliases={"°c", "c", "celsius", "℃"},
|
||||
aliases=CELSIUS_ALIASES,
|
||||
device_classes={SensorDeviceClass.TEMPERATURE},
|
||||
),
|
||||
UnitOfMeasurement(
|
||||
unit=UnitOfTemperature.FAHRENHEIT,
|
||||
aliases={"°f", "f", "fahrenheit"},
|
||||
aliases=FAHRENHEIT_ALIASES,
|
||||
device_classes={SensorDeviceClass.TEMPERATURE},
|
||||
),
|
||||
UnitOfMeasurement(
|
||||
|
||||
@@ -1375,11 +1375,11 @@
|
||||
# ---
|
||||
# name: test_us_customary_system[climate.air_conditioner]
|
||||
ReadOnlyDict({
|
||||
'current_temperature': 72,
|
||||
'max_temp': 187,
|
||||
'min_temp': 61,
|
||||
'current_temperature': 22,
|
||||
'max_temp': 86,
|
||||
'min_temp': 16,
|
||||
'target_temp_step': 1.0,
|
||||
'temperature': 73,
|
||||
'temperature': 23,
|
||||
})
|
||||
# ---
|
||||
# name: test_us_customary_system[climate.anbau]
|
||||
@@ -1435,11 +1435,11 @@
|
||||
# ---
|
||||
# name: test_us_customary_system[climate.floor_thermostat_kitchen]
|
||||
ReadOnlyDict({
|
||||
'current_temperature': 68,
|
||||
'max_temp': 95,
|
||||
'min_temp': 41,
|
||||
'current_temperature': -4,
|
||||
'max_temp': 66,
|
||||
'min_temp': 12,
|
||||
'target_temp_step': 1.0,
|
||||
'temperature': 36,
|
||||
'temperature': 4,
|
||||
})
|
||||
# ---
|
||||
# name: test_us_customary_system[climate.geti_solar_pv_water_heater]
|
||||
@@ -1470,11 +1470,11 @@
|
||||
# ---
|
||||
# name: test_us_customary_system[climate.mini_split]
|
||||
ReadOnlyDict({
|
||||
'current_temperature': 156,
|
||||
'max_temp': 194,
|
||||
'min_temp': 61,
|
||||
'current_temperature': 69,
|
||||
'max_temp': 90,
|
||||
'min_temp': 16,
|
||||
'target_temp_step': 1.0,
|
||||
'temperature': 151,
|
||||
'temperature': 66,
|
||||
})
|
||||
# ---
|
||||
# name: test_us_customary_system[climate.mr_pure]
|
||||
@@ -1487,10 +1487,10 @@
|
||||
# ---
|
||||
# name: test_us_customary_system[climate.polotentsosushitel]
|
||||
ReadOnlyDict({
|
||||
'current_temperature': 78,
|
||||
'current_temperature': 32,
|
||||
'max_temp': 104,
|
||||
'min_temp': 41,
|
||||
'target_temp_step': 0.5,
|
||||
'target_temp_step': 1.0,
|
||||
'temperature': 41,
|
||||
})
|
||||
# ---
|
||||
|
||||
Reference in New Issue
Block a user