Fix temperature setting for multi-setpoint z-wave device (#102395)

* Fix temperature setting for multi-setpoint z-wave device

* Add missing fixture file

* Apply suggestions from code review

---------

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
pull/102408/head
kpine 2023-10-20 10:57:00 -07:00 committed by GitHub
parent 3cfcffc6f2
commit c7affa75d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 4720 additions and 3 deletions

View File

@ -259,9 +259,11 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
def _current_mode_setpoint_enums(self) -> list[ThermostatSetpointType]:
"""Return the list of enums that are relevant to the current thermostat mode."""
if self._current_mode is None or self._current_mode.value is None:
# Thermostat(valve) with no support for setting a mode
# is considered heating-only
return [ThermostatSetpointType.HEATING]
# Thermostat with no support for setting a mode is just a setpoint
if self.info.primary_value.property_key is None:
return []
return [ThermostatSetpointType(int(self.info.primary_value.property_key))]
return THERMOSTAT_MODE_SETPOINT_MAP.get(int(self._current_mode.value), [])
@property

View File

@ -662,6 +662,12 @@ def logic_group_zdb5100_state_fixture():
return json.loads(load_fixture("zwave_js/logic_group_zdb5100_state.json"))
@pytest.fixture(name="climate_intermatic_pe653_state", scope="session")
def climate_intermatic_pe653_state_fixture():
"""Load Intermatic PE653 Pool Control node state fixture data."""
return json.loads(load_fixture("zwave_js/climate_intermatic_pe653_state.json"))
# model fixtures
@ -1290,3 +1296,11 @@ def logic_group_zdb5100_fixture(client, logic_group_zdb5100_state):
node = Node(client, copy.deepcopy(logic_group_zdb5100_state))
client.driver.controller.nodes[node.node_id] = node
return node
@pytest.fixture(name="climate_intermatic_pe653")
def climate_intermatic_pe653_fixture(client, climate_intermatic_pe653_state):
"""Mock an Intermatic PE653 node."""
node = Node(client, copy.deepcopy(climate_intermatic_pe653_state))
client.driver.controller.nodes[node.node_id] = node
return node

File diff suppressed because it is too large Load Diff

View File

@ -792,3 +792,196 @@ async def test_thermostat_raise_repair_issue_and_warning_when_setting_fan_preset
"Dry and Fan preset modes are deprecated and will be removed in Home Assistant 2024.2. Please use the corresponding Dry and Fan HVAC modes instead"
in caplog.text
)
async def test_multi_setpoint_thermostat(
hass: HomeAssistant, client, climate_intermatic_pe653, integration
) -> None:
"""Test a thermostat with multiple setpoints."""
node = climate_intermatic_pe653
heating_entity_id = "climate.pool_control_2"
heating = hass.states.get(heating_entity_id)
assert heating
assert heating.state == HVACMode.HEAT
assert heating.attributes[ATTR_TEMPERATURE] == 3.9
assert heating.attributes[ATTR_HVAC_MODES] == [HVACMode.HEAT]
assert (
heating.attributes[ATTR_SUPPORTED_FEATURES]
== ClimateEntityFeature.TARGET_TEMPERATURE
)
furnace_entity_id = "climate.pool_control"
furnace = hass.states.get(furnace_entity_id)
assert furnace
assert furnace.state == HVACMode.HEAT
assert furnace.attributes[ATTR_TEMPERATURE] == 15.6
assert furnace.attributes[ATTR_HVAC_MODES] == [HVACMode.HEAT]
assert (
furnace.attributes[ATTR_SUPPORTED_FEATURES]
== ClimateEntityFeature.TARGET_TEMPERATURE
)
client.async_send_command_no_wait.reset_mock()
# Test setting temperature of heating setpoint
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_TEMPERATURE,
{
ATTR_ENTITY_ID: heating_entity_id,
ATTR_TEMPERATURE: 20.0,
},
blocking=True,
)
# Test setting temperature of furnace setpoint
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_TEMPERATURE,
{
ATTR_ENTITY_ID: furnace_entity_id,
ATTR_TEMPERATURE: 2.0,
},
blocking=True,
)
# Test setting illegal mode raises an error
with pytest.raises(ValueError):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,
{
ATTR_ENTITY_ID: heating_entity_id,
ATTR_HVAC_MODE: HVACMode.COOL,
},
blocking=True,
)
with pytest.raises(ValueError):
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,
{
ATTR_ENTITY_ID: furnace_entity_id,
ATTR_HVAC_MODE: HVACMode.COOL,
},
blocking=True,
)
# this is a no-op since there's no mode
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,
{
ATTR_ENTITY_ID: heating_entity_id,
ATTR_HVAC_MODE: HVACMode.HEAT,
},
blocking=True,
)
# this is a no-op since there's no mode
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_SET_HVAC_MODE,
{
ATTR_ENTITY_ID: furnace_entity_id,
ATTR_HVAC_MODE: HVACMode.HEAT,
},
blocking=True,
)
assert len(client.async_send_command.call_args_list) == 2
args = client.async_send_command.call_args_list[0][0][0]
assert args["command"] == "node.set_value"
assert args["nodeId"] == 19
assert args["valueId"] == {
"endpoint": 1,
"commandClass": 67,
"property": "setpoint",
"propertyKey": 1,
}
assert args["value"] == 68.0
args = client.async_send_command.call_args_list[1][0][0]
assert args["command"] == "node.set_value"
assert args["nodeId"] == 19
assert args["valueId"] == {
"endpoint": 0,
"commandClass": 67,
"property": "setpoint",
"propertyKey": 7,
}
assert args["value"] == 35.6
client.async_send_command.reset_mock()
# Test heating setpoint value update from value updated event
event = Event(
type="value updated",
data={
"source": "node",
"event": "value updated",
"nodeId": 19,
"args": {
"commandClassName": "Thermostat Setpoint",
"commandClass": 67,
"endpoint": 1,
"property": "setpoint",
"propertyKey": 1,
"propertyKeyName": "Heating",
"propertyName": "setpoint",
"newValue": 23,
"prevValue": 21.5,
},
},
)
node.receive_event(event)
state = hass.states.get(heating_entity_id)
assert state
assert state.state == HVACMode.HEAT
assert state.attributes[ATTR_TEMPERATURE] == -5
# furnace not changed
state = hass.states.get(furnace_entity_id)
assert state
assert state.state == HVACMode.HEAT
assert state.attributes[ATTR_TEMPERATURE] == 15.6
client.async_send_command.reset_mock()
# Test furnace setpoint value update from value updated event
event = Event(
type="value updated",
data={
"source": "node",
"event": "value updated",
"nodeId": 19,
"args": {
"commandClassName": "Thermostat Setpoint",
"commandClass": 67,
"endpoint": 0,
"property": "setpoint",
"propertyKey": 7,
"propertyKeyName": "Furnace",
"propertyName": "setpoint",
"newValue": 68,
"prevValue": 21.5,
},
},
)
node.receive_event(event)
# heating not changed
state = hass.states.get(heating_entity_id)
assert state
assert state.state == HVACMode.HEAT
assert state.attributes[ATTR_TEMPERATURE] == -5
state = hass.states.get(furnace_entity_id)
assert state
assert state.state == HVACMode.HEAT
assert state.attributes[ATTR_TEMPERATURE] == 20
client.async_send_command.reset_mock()