Presets for single ZONNSMART TRV (#67157)
* Presets for single ZONNSMART TRV * added zonnsmart climate tests * black8 fix
This commit is contained in:
parent
636e4ed90b
commit
cbdfff25ca
2 changed files with 191 additions and 0 deletions
|
@ -771,3 +771,68 @@ class StelproFanHeater(Thermostat):
|
|||
def hvac_modes(self) -> tuple[str, ...]:
|
||||
"""Return only the heat mode, because the device can't be turned off."""
|
||||
return (HVAC_MODE_HEAT,)
|
||||
|
||||
|
||||
@STRICT_MATCH(
|
||||
channel_names=CHANNEL_THERMOSTAT,
|
||||
manufacturers={
|
||||
"_TZE200_hue3yfsn",
|
||||
},
|
||||
)
|
||||
class ZONNSMARTThermostat(Thermostat):
|
||||
"""
|
||||
ZONNSMART Thermostat implementation.
|
||||
|
||||
Notice that this device uses two holiday presets (2: HolidayMode,
|
||||
3: HolidayModeTemp), but only one of them can be set.
|
||||
"""
|
||||
|
||||
PRESET_HOLIDAY = "holiday"
|
||||
PRESET_FROST = "frost protect"
|
||||
|
||||
def __init__(self, unique_id, zha_device, channels, **kwargs):
|
||||
"""Initialize ZHA Thermostat instance."""
|
||||
super().__init__(unique_id, zha_device, channels, **kwargs)
|
||||
self._presets = [
|
||||
PRESET_NONE,
|
||||
self.PRESET_HOLIDAY,
|
||||
PRESET_SCHEDULE,
|
||||
self.PRESET_FROST,
|
||||
]
|
||||
self._supported_flags |= SUPPORT_PRESET_MODE
|
||||
|
||||
async def async_attribute_updated(self, record):
|
||||
"""Handle attribute update from device."""
|
||||
if record.attr_name == "operation_preset":
|
||||
if record.value == 0:
|
||||
self._preset = PRESET_SCHEDULE
|
||||
if record.value == 1:
|
||||
self._preset = PRESET_NONE
|
||||
if record.value == 2:
|
||||
self._preset = self.PRESET_HOLIDAY
|
||||
if record.value == 3:
|
||||
self._preset = self.PRESET_HOLIDAY
|
||||
if record.value == 4:
|
||||
self._preset = self.PRESET_FROST
|
||||
await super().async_attribute_updated(record)
|
||||
|
||||
async def async_preset_handler(self, preset: str, enable: bool = False) -> bool:
|
||||
"""Set the preset mode."""
|
||||
mfg_code = self._zha_device.manufacturer_code
|
||||
if not enable:
|
||||
return await self._thrm.write_attributes(
|
||||
{"operation_preset": 1}, manufacturer=mfg_code
|
||||
)
|
||||
if preset == PRESET_SCHEDULE:
|
||||
return await self._thrm.write_attributes(
|
||||
{"operation_preset": 0}, manufacturer=mfg_code
|
||||
)
|
||||
if preset == self.PRESET_HOLIDAY:
|
||||
return await self._thrm.write_attributes(
|
||||
{"operation_preset": 3}, manufacturer=mfg_code
|
||||
)
|
||||
if preset == self.PRESET_FROST:
|
||||
return await self._thrm.write_attributes(
|
||||
{"operation_preset": 4}, manufacturer=mfg_code
|
||||
)
|
||||
return False
|
||||
|
|
|
@ -137,9 +137,25 @@ CLIMATE_MOES = {
|
|||
SIG_EP_OUTPUT: [zigpy.zcl.clusters.general.Ota.cluster_id],
|
||||
}
|
||||
}
|
||||
|
||||
CLIMATE_ZONNSMART = {
|
||||
1: {
|
||||
SIG_EP_PROFILE: zigpy.profiles.zha.PROFILE_ID,
|
||||
SIG_EP_TYPE: zigpy.profiles.zha.DeviceType.THERMOSTAT,
|
||||
SIG_EP_INPUT: [
|
||||
zigpy.zcl.clusters.general.Basic.cluster_id,
|
||||
zigpy.zcl.clusters.hvac.Thermostat.cluster_id,
|
||||
zigpy.zcl.clusters.hvac.UserInterface.cluster_id,
|
||||
61148,
|
||||
],
|
||||
SIG_EP_OUTPUT: [zigpy.zcl.clusters.general.Ota.cluster_id],
|
||||
}
|
||||
}
|
||||
|
||||
MANUF_SINOPE = "Sinope Technologies"
|
||||
MANUF_ZEN = "Zen Within"
|
||||
MANUF_MOES = "_TZE200_ckud7u2l"
|
||||
MANUF_ZONNSMART = "_TZE200_hue3yfsn"
|
||||
|
||||
ZCL_ATTR_PLUG = {
|
||||
"abs_min_heat_setpoint_limit": 800,
|
||||
|
@ -232,6 +248,17 @@ async def device_climate_moes(device_climate_mock):
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def device_climate_zonnsmart(device_climate_mock):
|
||||
"""ZONNSMART thermostat."""
|
||||
|
||||
return await device_climate_mock(
|
||||
CLIMATE_ZONNSMART,
|
||||
manuf=MANUF_ZONNSMART,
|
||||
quirk=zhaquirks.tuya.ts0601_trv.ZonnsmartTV01_ZG,
|
||||
)
|
||||
|
||||
|
||||
def test_sequence_mappings():
|
||||
"""Test correct mapping between control sequence -> HVAC Mode -> Sysmode."""
|
||||
|
||||
|
@ -1326,3 +1353,102 @@ async def test_set_moes_operation_mode(hass, device_climate_moes):
|
|||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.attributes[ATTR_PRESET_MODE] == PRESET_COMPLEX
|
||||
|
||||
|
||||
async def test_set_zonnsmart_preset(hass, device_climate_zonnsmart):
|
||||
"""Test setting preset from homeassistant for zonnsmart trv."""
|
||||
|
||||
entity_id = await find_entity_id(Platform.CLIMATE, device_climate_zonnsmart, hass)
|
||||
thrm_cluster = device_climate_zonnsmart.device.endpoints[1].thermostat
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.attributes[ATTR_PRESET_MODE] == PRESET_NONE
|
||||
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_PRESET_MODE: PRESET_SCHEDULE},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert thrm_cluster.write_attributes.await_count == 1
|
||||
assert thrm_cluster.write_attributes.call_args_list[0][0][0] == {
|
||||
"operation_preset": 0
|
||||
}
|
||||
|
||||
thrm_cluster.write_attributes.reset_mock()
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_PRESET_MODE: "holiday"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert thrm_cluster.write_attributes.await_count == 2
|
||||
assert thrm_cluster.write_attributes.call_args_list[0][0][0] == {
|
||||
"operation_preset": 1
|
||||
}
|
||||
assert thrm_cluster.write_attributes.call_args_list[1][0][0] == {
|
||||
"operation_preset": 3
|
||||
}
|
||||
|
||||
thrm_cluster.write_attributes.reset_mock()
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_PRESET_MODE: "frost protect"},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert thrm_cluster.write_attributes.await_count == 2
|
||||
assert thrm_cluster.write_attributes.call_args_list[0][0][0] == {
|
||||
"operation_preset": 1
|
||||
}
|
||||
assert thrm_cluster.write_attributes.call_args_list[1][0][0] == {
|
||||
"operation_preset": 4
|
||||
}
|
||||
|
||||
thrm_cluster.write_attributes.reset_mock()
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_PRESET_MODE: PRESET_NONE},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert thrm_cluster.write_attributes.await_count == 1
|
||||
assert thrm_cluster.write_attributes.call_args_list[0][0][0] == {
|
||||
"operation_preset": 1
|
||||
}
|
||||
|
||||
|
||||
async def test_set_zonnsmart_operation_mode(hass, device_climate_zonnsmart):
|
||||
"""Test setting preset from trv for zonnsmart trv."""
|
||||
|
||||
entity_id = await find_entity_id(Platform.CLIMATE, device_climate_zonnsmart, hass)
|
||||
thrm_cluster = device_climate_zonnsmart.device.endpoints[1].thermostat
|
||||
|
||||
await send_attributes_report(hass, thrm_cluster, {"operation_preset": 0})
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.attributes[ATTR_PRESET_MODE] == PRESET_SCHEDULE
|
||||
|
||||
await send_attributes_report(hass, thrm_cluster, {"operation_preset": 1})
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.attributes[ATTR_PRESET_MODE] == PRESET_NONE
|
||||
|
||||
await send_attributes_report(hass, thrm_cluster, {"operation_preset": 2})
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.attributes[ATTR_PRESET_MODE] == "holiday"
|
||||
|
||||
await send_attributes_report(hass, thrm_cluster, {"operation_preset": 3})
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.attributes[ATTR_PRESET_MODE] == "holiday"
|
||||
|
||||
await send_attributes_report(hass, thrm_cluster, {"operation_preset": 4})
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.attributes[ATTR_PRESET_MODE] == "frost protect"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue