Improved Alexa ThermostatController thermostatMode handling (#28176)
* Update ThermostatController to map directives to supported modes and add support for CUSTOM mode. * Removed erroneous config value from test. * Removed unnecessary use of a comprehension by dumbing down comment so pylint could comprehend. * Removed erroneous import variable caused by removing erroneous config value from test. * Removed unnecessary use of a comprehension. * Reverted Removal or erroneous import variable and erroneous config value from test. Apparently need for additional tests outside this component. Whoops.
This commit is contained in:
parent
f4341c1546
commit
d44bfa8e88
5 changed files with 105 additions and 11 deletions
|
@ -736,6 +736,33 @@ class AlexaThermostatController(AlexaCapability):
|
|||
|
||||
return {"value": temp, "scale": API_TEMP_UNITS[unit]}
|
||||
|
||||
def configuration(self):
|
||||
"""Return configuration object.
|
||||
|
||||
Translates climate HVAC_MODES and PRESETS to supported Alexa ThermostatMode Values.
|
||||
ThermostatMode Value must be AUTO, COOL, HEAT, ECO, OFF, or CUSTOM.
|
||||
"""
|
||||
supported_modes = []
|
||||
hvac_modes = self.entity.attributes.get(climate.ATTR_HVAC_MODES)
|
||||
for mode in hvac_modes:
|
||||
thermostat_mode = API_THERMOSTAT_MODES.get(mode)
|
||||
if thermostat_mode:
|
||||
supported_modes.append(thermostat_mode)
|
||||
|
||||
preset_modes = self.entity.attributes.get(climate.ATTR_PRESET_MODES)
|
||||
for mode in preset_modes:
|
||||
thermostat_mode = API_THERMOSTAT_PRESETS.get(mode)
|
||||
if thermostat_mode:
|
||||
supported_modes.append(thermostat_mode)
|
||||
|
||||
# Return False for supportsScheduling until supported with event listener in handler.
|
||||
configuration = {"supportsScheduling": False}
|
||||
|
||||
if supported_modes:
|
||||
configuration["supportedModes"] = supported_modes
|
||||
|
||||
return configuration
|
||||
|
||||
|
||||
class AlexaPowerLevelController(AlexaCapability):
|
||||
"""Implements Alexa.PowerLevelController.
|
||||
|
|
|
@ -56,9 +56,10 @@ API_THERMOSTAT_MODES = OrderedDict(
|
|||
(climate.HVAC_MODE_AUTO, "AUTO"),
|
||||
(climate.HVAC_MODE_OFF, "OFF"),
|
||||
(climate.HVAC_MODE_FAN_ONLY, "OFF"),
|
||||
(climate.HVAC_MODE_DRY, "OFF"),
|
||||
(climate.HVAC_MODE_DRY, "CUSTOM"),
|
||||
]
|
||||
)
|
||||
API_THERMOSTAT_MODES_CUSTOM = {climate.HVAC_MODE_DRY: "DEHUMIDIFY"}
|
||||
API_THERMOSTAT_PRESETS = {climate.PRESET_ECO: "ECO"}
|
||||
|
||||
PERCENTAGE_FAN_MAP = {
|
||||
|
|
|
@ -38,6 +38,7 @@ from homeassistant.util.temperature import convert as convert_temperature
|
|||
|
||||
from .const import (
|
||||
API_TEMP_UNITS,
|
||||
API_THERMOSTAT_MODES_CUSTOM,
|
||||
API_THERMOSTAT_MODES,
|
||||
API_THERMOSTAT_PRESETS,
|
||||
Cause,
|
||||
|
@ -767,11 +768,28 @@ async def async_api_set_thermostat_mode(hass, config, directive, context):
|
|||
raise AlexaUnsupportedThermostatModeError(msg)
|
||||
|
||||
service = climate.SERVICE_SET_PRESET_MODE
|
||||
data[climate.ATTR_PRESET_MODE] = climate.PRESET_ECO
|
||||
data[climate.ATTR_PRESET_MODE] = ha_preset
|
||||
|
||||
elif mode == "CUSTOM":
|
||||
operation_list = entity.attributes.get(climate.ATTR_HVAC_MODES)
|
||||
custom_mode = directive.payload["thermostatMode"]["customName"]
|
||||
custom_mode = next(
|
||||
(k for k, v in API_THERMOSTAT_MODES_CUSTOM.items() if v == custom_mode),
|
||||
None,
|
||||
)
|
||||
if custom_mode not in operation_list:
|
||||
msg = (
|
||||
f"The requested thermostat mode {mode}: {custom_mode} is not supported"
|
||||
)
|
||||
raise AlexaUnsupportedThermostatModeError(msg)
|
||||
|
||||
service = climate.SERVICE_SET_HVAC_MODE
|
||||
data[climate.ATTR_HVAC_MODE] = custom_mode
|
||||
|
||||
else:
|
||||
operation_list = entity.attributes.get(climate.ATTR_HVAC_MODES)
|
||||
ha_mode = next((k for k, v in API_THERMOSTAT_MODES.items() if v == mode), None)
|
||||
ha_modes = {k: v for k, v in API_THERMOSTAT_MODES.items() if v == mode}
|
||||
ha_mode = next(iter(set(ha_modes).intersection(operation_list)), None)
|
||||
if ha_mode not in operation_list:
|
||||
msg = f"The requested thermostat mode {mode} is not supported"
|
||||
raise AlexaUnsupportedThermostatModeError(msg)
|
||||
|
|
|
@ -472,11 +472,7 @@ async def test_report_climate_state(hass):
|
|||
{"value": 34.0, "scale": "CELSIUS"},
|
||||
)
|
||||
|
||||
for off_modes in (
|
||||
climate.HVAC_MODE_OFF,
|
||||
climate.HVAC_MODE_FAN_ONLY,
|
||||
climate.HVAC_MODE_DRY,
|
||||
):
|
||||
for off_modes in (climate.HVAC_MODE_OFF, climate.HVAC_MODE_FAN_ONLY):
|
||||
hass.states.async_set(
|
||||
"climate.downstairs",
|
||||
off_modes,
|
||||
|
@ -495,6 +491,23 @@ async def test_report_climate_state(hass):
|
|||
{"value": 34.0, "scale": "CELSIUS"},
|
||||
)
|
||||
|
||||
# assert dry is reported as CUSTOM
|
||||
hass.states.async_set(
|
||||
"climate.downstairs",
|
||||
"dry",
|
||||
{
|
||||
"friendly_name": "Climate Downstairs",
|
||||
"supported_features": 91,
|
||||
climate.ATTR_CURRENT_TEMPERATURE: 34,
|
||||
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
|
||||
},
|
||||
)
|
||||
properties = await reported_properties(hass, "climate.downstairs")
|
||||
properties.assert_equal("Alexa.ThermostatController", "thermostatMode", "CUSTOM")
|
||||
properties.assert_equal(
|
||||
"Alexa.TemperatureSensor", "temperature", {"value": 34.0, "scale": "CELSIUS"}
|
||||
)
|
||||
|
||||
hass.states.async_set(
|
||||
"climate.heat",
|
||||
"heat",
|
||||
|
|
|
@ -1267,7 +1267,7 @@ async def test_thermostat(hass):
|
|||
"current_temperature": 75.0,
|
||||
"friendly_name": "Test Thermostat",
|
||||
"supported_features": 1 | 2 | 4 | 128,
|
||||
"hvac_modes": ["heat", "cool", "auto", "off"],
|
||||
"hvac_modes": ["off", "heat", "cool", "auto", "dry"],
|
||||
"preset_mode": None,
|
||||
"preset_modes": ["eco"],
|
||||
"min_temp": 50,
|
||||
|
@ -1280,7 +1280,7 @@ async def test_thermostat(hass):
|
|||
assert appliance["displayCategories"][0] == "THERMOSTAT"
|
||||
assert appliance["friendlyName"] == "Test Thermostat"
|
||||
|
||||
assert_endpoint_capabilities(
|
||||
capabilities = assert_endpoint_capabilities(
|
||||
appliance,
|
||||
"Alexa.PowerController",
|
||||
"Alexa.ThermostatController",
|
||||
|
@ -1299,6 +1299,15 @@ async def test_thermostat(hass):
|
|||
"Alexa.TemperatureSensor", "temperature", {"value": 75.0, "scale": "FAHRENHEIT"}
|
||||
)
|
||||
|
||||
thermostat_capability = get_capability(capabilities, "Alexa.ThermostatController")
|
||||
assert thermostat_capability is not None
|
||||
configuration = thermostat_capability["configuration"]
|
||||
assert configuration["supportsScheduling"] is False
|
||||
|
||||
supported_modes = ["OFF", "HEAT", "COOL", "AUTO", "ECO", "CUSTOM"]
|
||||
for mode in supported_modes:
|
||||
assert mode in configuration["supportedModes"]
|
||||
|
||||
call, msg = await assert_request_calls_service(
|
||||
"Alexa.ThermostatController",
|
||||
"SetTargetTemperature",
|
||||
|
@ -1447,6 +1456,30 @@ async def test_thermostat(hass):
|
|||
properties = ReportedProperties(msg["context"]["properties"])
|
||||
properties.assert_equal("Alexa.ThermostatController", "thermostatMode", "HEAT")
|
||||
|
||||
# Assert we can call custom modes
|
||||
call, msg = await assert_request_calls_service(
|
||||
"Alexa.ThermostatController",
|
||||
"SetThermostatMode",
|
||||
"climate#test_thermostat",
|
||||
"climate.set_hvac_mode",
|
||||
hass,
|
||||
payload={"thermostatMode": {"value": "CUSTOM", "customName": "DEHUMIDIFY"}},
|
||||
)
|
||||
assert call.data["hvac_mode"] == "dry"
|
||||
properties = ReportedProperties(msg["context"]["properties"])
|
||||
properties.assert_equal("Alexa.ThermostatController", "thermostatMode", "CUSTOM")
|
||||
|
||||
# assert unsupported custom mode
|
||||
msg = await assert_request_fails(
|
||||
"Alexa.ThermostatController",
|
||||
"SetThermostatMode",
|
||||
"climate#test_thermostat",
|
||||
"climate.set_hvac_mode",
|
||||
hass,
|
||||
payload={"thermostatMode": {"value": "CUSTOM", "customName": "INVALID"}},
|
||||
)
|
||||
assert msg["event"]["payload"]["type"] == "UNSUPPORTED_THERMOSTAT_MODE"
|
||||
|
||||
msg = await assert_request_fails(
|
||||
"Alexa.ThermostatController",
|
||||
"SetThermostatMode",
|
||||
|
@ -1456,7 +1489,6 @@ async def test_thermostat(hass):
|
|||
payload={"thermostatMode": {"value": "INVALID"}},
|
||||
)
|
||||
assert msg["event"]["payload"]["type"] == "UNSUPPORTED_THERMOSTAT_MODE"
|
||||
hass.config.units.temperature_unit = TEMP_CELSIUS
|
||||
|
||||
call, _ = await assert_request_calls_service(
|
||||
"Alexa.ThermostatController",
|
||||
|
@ -1479,6 +1511,9 @@ async def test_thermostat(hass):
|
|||
)
|
||||
assert call.data["preset_mode"] == "eco"
|
||||
|
||||
# Reset config temperature_unit back to CELSIUS, required for additional tests outside this component.
|
||||
hass.config.units.temperature_unit = TEMP_CELSIUS
|
||||
|
||||
|
||||
async def test_exclude_filters(hass):
|
||||
"""Test exclusion filters."""
|
||||
|
|
Loading…
Add table
Reference in a new issue