Add water_heater to google_assistant (#105915)
* Add water_heater to google_assistant * Follow up comments * Add water_heater to default exposed domains
This commit is contained in:
parent
c57cc85174
commit
f5f9b89848
4 changed files with 373 additions and 11 deletions
|
@ -22,6 +22,7 @@ from homeassistant.components import (
|
|||
sensor,
|
||||
switch,
|
||||
vacuum,
|
||||
water_heater,
|
||||
)
|
||||
|
||||
DOMAIN = "google_assistant"
|
||||
|
@ -64,6 +65,7 @@ DEFAULT_EXPOSED_DOMAINS = [
|
|||
"sensor",
|
||||
"switch",
|
||||
"vacuum",
|
||||
"water_heater",
|
||||
]
|
||||
|
||||
# https://developers.google.com/assistant/smarthome/guides
|
||||
|
@ -93,6 +95,7 @@ TYPE_THERMOSTAT = f"{PREFIX_TYPES}THERMOSTAT"
|
|||
TYPE_TV = f"{PREFIX_TYPES}TV"
|
||||
TYPE_WINDOW = f"{PREFIX_TYPES}WINDOW"
|
||||
TYPE_VACUUM = f"{PREFIX_TYPES}VACUUM"
|
||||
TYPE_WATERHEATER = f"{PREFIX_TYPES}WATERHEATER"
|
||||
|
||||
SERVICE_REQUEST_SYNC = "request_sync"
|
||||
HOMEGRAPH_URL = "https://homegraph.googleapis.com/"
|
||||
|
@ -147,6 +150,7 @@ DOMAIN_TO_GOOGLE_TYPES = {
|
|||
sensor.DOMAIN: TYPE_SENSOR,
|
||||
switch.DOMAIN: TYPE_SWITCH,
|
||||
vacuum.DOMAIN: TYPE_VACUUM,
|
||||
water_heater.DOMAIN: TYPE_WATERHEATER,
|
||||
}
|
||||
|
||||
DEVICE_CLASS_TO_GOOGLE_TYPES = {
|
||||
|
|
|
@ -29,6 +29,7 @@ from homeassistant.components import (
|
|||
sensor,
|
||||
switch,
|
||||
vacuum,
|
||||
water_heater,
|
||||
)
|
||||
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature
|
||||
from homeassistant.components.camera import CameraEntityFeature
|
||||
|
@ -40,6 +41,7 @@ from homeassistant.components.light import LightEntityFeature
|
|||
from homeassistant.components.lock import STATE_JAMMED, STATE_UNLOCKING
|
||||
from homeassistant.components.media_player import MediaPlayerEntityFeature, MediaType
|
||||
from homeassistant.components.vacuum import VacuumEntityFeature
|
||||
from homeassistant.components.water_heater import WaterHeaterEntityFeature
|
||||
from homeassistant.const import (
|
||||
ATTR_ASSUMED_STATE,
|
||||
ATTR_BATTERY_LEVEL,
|
||||
|
@ -139,6 +141,7 @@ COMMAND_PAUSEUNPAUSE = f"{PREFIX_COMMANDS}PauseUnpause"
|
|||
COMMAND_BRIGHTNESS_ABSOLUTE = f"{PREFIX_COMMANDS}BrightnessAbsolute"
|
||||
COMMAND_COLOR_ABSOLUTE = f"{PREFIX_COMMANDS}ColorAbsolute"
|
||||
COMMAND_ACTIVATE_SCENE = f"{PREFIX_COMMANDS}ActivateScene"
|
||||
COMMAND_SET_TEMPERATURE = f"{PREFIX_COMMANDS}SetTemperature"
|
||||
COMMAND_THERMOSTAT_TEMPERATURE_SETPOINT = (
|
||||
f"{PREFIX_COMMANDS}ThermostatTemperatureSetpoint"
|
||||
)
|
||||
|
@ -417,6 +420,9 @@ class OnOffTrait(_Trait):
|
|||
@staticmethod
|
||||
def supported(domain, features, device_class, _):
|
||||
"""Test if state is supported."""
|
||||
if domain == water_heater.DOMAIN and features & WaterHeaterEntityFeature.ON_OFF:
|
||||
return True
|
||||
|
||||
return domain in (
|
||||
group.DOMAIN,
|
||||
input_boolean.DOMAIN,
|
||||
|
@ -894,38 +900,97 @@ class StartStopTrait(_Trait):
|
|||
|
||||
@register_trait
|
||||
class TemperatureControlTrait(_Trait):
|
||||
"""Trait for devices (other than thermostats) that support controlling temperature. Workaround for Temperature sensors.
|
||||
"""Trait for devices (other than thermostats) that support controlling temperature.
|
||||
|
||||
Control the target temperature of water heaters.
|
||||
Offers a workaround for Temperature sensors by setting queryOnlyTemperatureControl
|
||||
in the response.
|
||||
|
||||
https://developers.google.com/assistant/smarthome/traits/temperaturecontrol
|
||||
"""
|
||||
|
||||
name = TRAIT_TEMPERATURE_CONTROL
|
||||
|
||||
commands = [
|
||||
COMMAND_SET_TEMPERATURE,
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def supported(domain, features, device_class, _):
|
||||
"""Test if state is supported."""
|
||||
return (
|
||||
domain == water_heater.DOMAIN
|
||||
and features & WaterHeaterEntityFeature.TARGET_TEMPERATURE
|
||||
) or (
|
||||
domain == sensor.DOMAIN
|
||||
and device_class == sensor.SensorDeviceClass.TEMPERATURE
|
||||
)
|
||||
|
||||
def sync_attributes(self):
|
||||
"""Return temperature attributes for a sync request."""
|
||||
return {
|
||||
"temperatureUnitForUX": _google_temp_unit(
|
||||
self.hass.config.units.temperature_unit
|
||||
),
|
||||
"queryOnlyTemperatureControl": True,
|
||||
"temperatureRange": {
|
||||
response = {}
|
||||
domain = self.state.domain
|
||||
attrs = self.state.attributes
|
||||
unit = self.hass.config.units.temperature_unit
|
||||
response["temperatureUnitForUX"] = _google_temp_unit(unit)
|
||||
|
||||
if domain == water_heater.DOMAIN:
|
||||
min_temp = round(
|
||||
TemperatureConverter.convert(
|
||||
float(attrs[water_heater.ATTR_MIN_TEMP]),
|
||||
unit,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
)
|
||||
)
|
||||
max_temp = round(
|
||||
TemperatureConverter.convert(
|
||||
float(attrs[water_heater.ATTR_MAX_TEMP]),
|
||||
unit,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
)
|
||||
)
|
||||
response["temperatureRange"] = {
|
||||
"minThresholdCelsius": min_temp,
|
||||
"maxThresholdCelsius": max_temp,
|
||||
}
|
||||
else:
|
||||
response["queryOnlyTemperatureControl"] = True
|
||||
response["temperatureRange"] = {
|
||||
"minThresholdCelsius": -100,
|
||||
"maxThresholdCelsius": 100,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return response
|
||||
|
||||
def query_attributes(self):
|
||||
"""Return temperature states."""
|
||||
response = {}
|
||||
domain = self.state.domain
|
||||
unit = self.hass.config.units.temperature_unit
|
||||
if domain == water_heater.DOMAIN:
|
||||
target_temp = self.state.attributes[water_heater.ATTR_TEMPERATURE]
|
||||
current_temp = self.state.attributes[water_heater.ATTR_CURRENT_TEMPERATURE]
|
||||
if target_temp not in (STATE_UNKNOWN, STATE_UNAVAILABLE):
|
||||
response["temperatureSetpointCelsius"] = round(
|
||||
TemperatureConverter.convert(
|
||||
float(target_temp),
|
||||
unit,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
),
|
||||
1,
|
||||
)
|
||||
if current_temp is not None:
|
||||
response["temperatureAmbientCelsius"] = round(
|
||||
TemperatureConverter.convert(
|
||||
float(current_temp),
|
||||
unit,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
),
|
||||
1,
|
||||
)
|
||||
return response
|
||||
|
||||
# domain == sensor.DOMAIN
|
||||
current_temp = self.state.state
|
||||
if current_temp not in (STATE_UNKNOWN, STATE_UNAVAILABLE):
|
||||
temp = round(
|
||||
|
@ -940,8 +1005,35 @@ class TemperatureControlTrait(_Trait):
|
|||
return response
|
||||
|
||||
async def execute(self, command, data, params, challenge):
|
||||
"""Unsupported."""
|
||||
raise SmartHomeError(ERR_NOT_SUPPORTED, "Execute is not supported by sensor")
|
||||
"""Execute a temperature point or mode command."""
|
||||
# All sent in temperatures are always in Celsius
|
||||
domain = self.state.domain
|
||||
unit = self.hass.config.units.temperature_unit
|
||||
|
||||
if domain == water_heater.DOMAIN and command == COMMAND_SET_TEMPERATURE:
|
||||
min_temp = self.state.attributes[water_heater.ATTR_MIN_TEMP]
|
||||
max_temp = self.state.attributes[water_heater.ATTR_MAX_TEMP]
|
||||
temp = TemperatureConverter.convert(
|
||||
params["temperature"], UnitOfTemperature.CELSIUS, unit
|
||||
)
|
||||
if unit == UnitOfTemperature.FAHRENHEIT:
|
||||
temp = round(temp)
|
||||
if temp < min_temp or temp > max_temp:
|
||||
raise SmartHomeError(
|
||||
ERR_VALUE_OUT_OF_RANGE,
|
||||
f"Temperature should be between {min_temp} and {max_temp}",
|
||||
)
|
||||
|
||||
await self.hass.services.async_call(
|
||||
water_heater.DOMAIN,
|
||||
water_heater.SERVICE_SET_TEMPERATURE,
|
||||
{ATTR_ENTITY_ID: self.state.entity_id, ATTR_TEMPERATURE: temp},
|
||||
blocking=not self.config.should_report_state,
|
||||
context=data.context,
|
||||
)
|
||||
return
|
||||
|
||||
raise SmartHomeError(ERR_NOT_SUPPORTED, f"Execute is not supported by {domain}")
|
||||
|
||||
|
||||
@register_trait
|
||||
|
@ -1696,6 +1788,12 @@ class ModesTrait(_Trait):
|
|||
if domain == light.DOMAIN and features & LightEntityFeature.EFFECT:
|
||||
return True
|
||||
|
||||
if (
|
||||
domain == water_heater.DOMAIN
|
||||
and features & WaterHeaterEntityFeature.OPERATION_MODE
|
||||
):
|
||||
return True
|
||||
|
||||
if domain != media_player.DOMAIN:
|
||||
return False
|
||||
|
||||
|
@ -1736,6 +1834,7 @@ class ModesTrait(_Trait):
|
|||
(select.DOMAIN, select.ATTR_OPTIONS, "option"),
|
||||
(humidifier.DOMAIN, humidifier.ATTR_AVAILABLE_MODES, "mode"),
|
||||
(light.DOMAIN, light.ATTR_EFFECT_LIST, "effect"),
|
||||
(water_heater.DOMAIN, water_heater.ATTR_OPERATION_LIST, "operation mode"),
|
||||
):
|
||||
if self.state.domain != domain:
|
||||
continue
|
||||
|
@ -1769,6 +1868,11 @@ class ModesTrait(_Trait):
|
|||
elif self.state.domain == humidifier.DOMAIN:
|
||||
if ATTR_MODE in attrs:
|
||||
mode_settings["mode"] = attrs.get(ATTR_MODE)
|
||||
elif self.state.domain == water_heater.DOMAIN:
|
||||
if water_heater.ATTR_OPERATION_MODE in attrs:
|
||||
mode_settings["operation mode"] = attrs.get(
|
||||
water_heater.ATTR_OPERATION_MODE
|
||||
)
|
||||
elif self.state.domain == light.DOMAIN and (
|
||||
effect := attrs.get(light.ATTR_EFFECT)
|
||||
):
|
||||
|
@ -1840,6 +1944,20 @@ class ModesTrait(_Trait):
|
|||
)
|
||||
return
|
||||
|
||||
if self.state.domain == water_heater.DOMAIN:
|
||||
requested_mode = settings["operation mode"]
|
||||
await self.hass.services.async_call(
|
||||
water_heater.DOMAIN,
|
||||
water_heater.SERVICE_SET_OPERATION_MODE,
|
||||
{
|
||||
water_heater.ATTR_OPERATION_MODE: requested_mode,
|
||||
ATTR_ENTITY_ID: self.state.entity_id,
|
||||
},
|
||||
blocking=not self.config.should_report_state,
|
||||
context=data.context,
|
||||
)
|
||||
return
|
||||
|
||||
if self.state.domain == light.DOMAIN:
|
||||
requested_effect = settings["effect"]
|
||||
await self.hass.services.async_call(
|
||||
|
|
|
@ -103,6 +103,7 @@
|
|||
'sensor',
|
||||
'switch',
|
||||
'vacuum',
|
||||
'water_heater',
|
||||
]),
|
||||
'project_id': '1234',
|
||||
'report_state': False,
|
||||
|
|
|
@ -27,6 +27,7 @@ from homeassistant.components import (
|
|||
sensor,
|
||||
switch,
|
||||
vacuum,
|
||||
water_heater,
|
||||
)
|
||||
from homeassistant.components.alarm_control_panel import AlarmControlPanelEntityFeature
|
||||
from homeassistant.components.camera import CameraEntityFeature
|
||||
|
@ -44,6 +45,7 @@ from homeassistant.components.media_player import (
|
|||
MediaType,
|
||||
)
|
||||
from homeassistant.components.vacuum import VacuumEntityFeature
|
||||
from homeassistant.components.water_heater import WaterHeaterEntityFeature
|
||||
from homeassistant.config import async_process_ha_core_config
|
||||
from homeassistant.const import (
|
||||
ATTR_ASSUMED_STATE,
|
||||
|
@ -75,6 +77,7 @@ from homeassistant.core import (
|
|||
State,
|
||||
)
|
||||
from homeassistant.util import color
|
||||
from homeassistant.util.unit_conversion import TemperatureConverter
|
||||
|
||||
from . import BASIC_CONFIG, MockConfig
|
||||
|
||||
|
@ -393,6 +396,35 @@ async def test_onoff_humidifier(hass: HomeAssistant) -> None:
|
|||
assert off_calls[0].data == {ATTR_ENTITY_ID: "humidifier.bla"}
|
||||
|
||||
|
||||
async def test_onoff_water_heater(hass: HomeAssistant) -> None:
|
||||
"""Test OnOff trait support for water_heater domain."""
|
||||
assert helpers.get_google_type(water_heater.DOMAIN, None) is not None
|
||||
assert trait.OnOffTrait.supported(
|
||||
water_heater.DOMAIN, WaterHeaterEntityFeature.ON_OFF, None, None
|
||||
)
|
||||
|
||||
trt_on = trait.OnOffTrait(hass, State("water_heater.bla", STATE_ON), BASIC_CONFIG)
|
||||
|
||||
assert trt_on.sync_attributes() == {}
|
||||
|
||||
assert trt_on.query_attributes() == {"on": True}
|
||||
|
||||
trt_off = trait.OnOffTrait(hass, State("water_heater.bla", STATE_OFF), BASIC_CONFIG)
|
||||
|
||||
assert trt_off.query_attributes() == {"on": False}
|
||||
|
||||
on_calls = async_mock_service(hass, water_heater.DOMAIN, SERVICE_TURN_ON)
|
||||
await trt_on.execute(trait.COMMAND_ONOFF, BASIC_DATA, {"on": True}, {})
|
||||
assert len(on_calls) == 1
|
||||
assert on_calls[0].data == {ATTR_ENTITY_ID: "water_heater.bla"}
|
||||
|
||||
off_calls = async_mock_service(hass, water_heater.DOMAIN, SERVICE_TURN_OFF)
|
||||
|
||||
await trt_on.execute(trait.COMMAND_ONOFF, BASIC_DATA, {"on": False}, {})
|
||||
assert len(off_calls) == 1
|
||||
assert off_calls[0].data == {ATTR_ENTITY_ID: "water_heater.bla"}
|
||||
|
||||
|
||||
async def test_dock_vacuum(hass: HomeAssistant) -> None:
|
||||
"""Test dock trait support for vacuum domain."""
|
||||
assert helpers.get_google_type(vacuum.DOMAIN, None) is not None
|
||||
|
@ -1246,6 +1278,135 @@ async def test_temperature_control(hass: HomeAssistant) -> None:
|
|||
assert err.value.code == const.ERR_NOT_SUPPORTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("unit_in", "unit_out", "temp_in", "temp_out", "current_in", "current_out"),
|
||||
[
|
||||
(UnitOfTemperature.CELSIUS, "C", "120", 120, "130", 130),
|
||||
(UnitOfTemperature.FAHRENHEIT, "F", "248", 120, "266", 130),
|
||||
],
|
||||
)
|
||||
async def test_temperature_control_water_heater(
|
||||
hass: HomeAssistant,
|
||||
unit_in: UnitOfTemperature,
|
||||
unit_out: str,
|
||||
temp_in: str,
|
||||
temp_out: float,
|
||||
current_in: str,
|
||||
current_out: float,
|
||||
) -> None:
|
||||
"""Test TemperatureControl trait support for water heater domain."""
|
||||
hass.config.units.temperature_unit = unit_in
|
||||
|
||||
min_temp = TemperatureConverter.convert(
|
||||
water_heater.DEFAULT_MIN_TEMP,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
unit_in,
|
||||
)
|
||||
max_temp = TemperatureConverter.convert(
|
||||
water_heater.DEFAULT_MAX_TEMP,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
unit_in,
|
||||
)
|
||||
|
||||
trt = trait.TemperatureControlTrait(
|
||||
hass,
|
||||
State(
|
||||
"water_heater.bla",
|
||||
"attributes",
|
||||
{
|
||||
"min_temp": min_temp,
|
||||
"max_temp": max_temp,
|
||||
"temperature": temp_in,
|
||||
"current_temperature": current_in,
|
||||
},
|
||||
),
|
||||
BASIC_CONFIG,
|
||||
)
|
||||
|
||||
assert trt.sync_attributes() == {
|
||||
"temperatureUnitForUX": unit_out,
|
||||
"temperatureRange": {
|
||||
"maxThresholdCelsius": water_heater.DEFAULT_MAX_TEMP,
|
||||
"minThresholdCelsius": water_heater.DEFAULT_MIN_TEMP,
|
||||
},
|
||||
}
|
||||
assert trt.query_attributes() == {
|
||||
"temperatureSetpointCelsius": temp_out,
|
||||
"temperatureAmbientCelsius": current_out,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("unit", "temp_init", "temp_in", "temp_out", "current_init"),
|
||||
[
|
||||
(UnitOfTemperature.CELSIUS, "180", 220, 220, "180"),
|
||||
(UnitOfTemperature.FAHRENHEIT, "356", 220, 428, "356"),
|
||||
],
|
||||
)
|
||||
async def test_temperature_control_water_heater_set_temperature(
|
||||
hass: HomeAssistant,
|
||||
unit: UnitOfTemperature,
|
||||
temp_init: str,
|
||||
temp_in: float,
|
||||
temp_out: float,
|
||||
current_init: str,
|
||||
) -> None:
|
||||
"""Test TemperatureControl trait support for water heater domain - SetTemperature."""
|
||||
hass.config.units.temperature_unit = unit
|
||||
|
||||
min_temp = TemperatureConverter.convert(
|
||||
40,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
unit,
|
||||
)
|
||||
max_temp = TemperatureConverter.convert(
|
||||
230,
|
||||
UnitOfTemperature.CELSIUS,
|
||||
unit,
|
||||
)
|
||||
|
||||
trt = trait.TemperatureControlTrait(
|
||||
hass,
|
||||
State(
|
||||
"water_heater.bla",
|
||||
"attributes",
|
||||
{
|
||||
"min_temp": min_temp,
|
||||
"max_temp": max_temp,
|
||||
"temperature": temp_init,
|
||||
"current_temperature": current_init,
|
||||
},
|
||||
),
|
||||
BASIC_CONFIG,
|
||||
)
|
||||
|
||||
assert trt.can_execute(trait.COMMAND_SET_TEMPERATURE, {})
|
||||
|
||||
calls = async_mock_service(
|
||||
hass, water_heater.DOMAIN, water_heater.SERVICE_SET_TEMPERATURE
|
||||
)
|
||||
|
||||
with pytest.raises(helpers.SmartHomeError):
|
||||
await trt.execute(
|
||||
trait.COMMAND_SET_TEMPERATURE,
|
||||
BASIC_DATA,
|
||||
{"temperature": -100},
|
||||
{},
|
||||
)
|
||||
|
||||
await trt.execute(
|
||||
trait.COMMAND_SET_TEMPERATURE,
|
||||
BASIC_DATA,
|
||||
{"temperature": temp_in},
|
||||
{},
|
||||
)
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data == {
|
||||
ATTR_ENTITY_ID: "water_heater.bla",
|
||||
ATTR_TEMPERATURE: temp_out,
|
||||
}
|
||||
|
||||
|
||||
async def test_humidity_setting_humidifier_setpoint(hass: HomeAssistant) -> None:
|
||||
"""Test HumiditySetting trait support for humidifier domain - setpoint."""
|
||||
assert helpers.get_google_type(humidifier.DOMAIN, None) is not None
|
||||
|
@ -2411,6 +2572,84 @@ async def test_modes_humidifier(hass: HomeAssistant) -> None:
|
|||
}
|
||||
|
||||
|
||||
async def test_modes_water_heater(hass: HomeAssistant) -> None:
|
||||
"""Test Humidifier Mode trait."""
|
||||
assert helpers.get_google_type(water_heater.DOMAIN, None) is not None
|
||||
assert trait.ModesTrait.supported(
|
||||
water_heater.DOMAIN, WaterHeaterEntityFeature.OPERATION_MODE, None, None
|
||||
)
|
||||
|
||||
trt = trait.ModesTrait(
|
||||
hass,
|
||||
State(
|
||||
"water_heater.water_heater",
|
||||
STATE_OFF,
|
||||
attributes={
|
||||
water_heater.ATTR_OPERATION_LIST: [
|
||||
water_heater.STATE_ECO,
|
||||
water_heater.STATE_HEAT_PUMP,
|
||||
water_heater.STATE_GAS,
|
||||
],
|
||||
ATTR_SUPPORTED_FEATURES: WaterHeaterEntityFeature.OPERATION_MODE,
|
||||
water_heater.ATTR_OPERATION_MODE: water_heater.STATE_HEAT_PUMP,
|
||||
},
|
||||
),
|
||||
BASIC_CONFIG,
|
||||
)
|
||||
|
||||
attribs = trt.sync_attributes()
|
||||
assert attribs == {
|
||||
"availableModes": [
|
||||
{
|
||||
"name": "operation mode",
|
||||
"name_values": [{"name_synonym": ["operation mode"], "lang": "en"}],
|
||||
"settings": [
|
||||
{
|
||||
"setting_name": "eco",
|
||||
"setting_values": [{"setting_synonym": ["eco"], "lang": "en"}],
|
||||
},
|
||||
{
|
||||
"setting_name": "heat_pump",
|
||||
"setting_values": [
|
||||
{"setting_synonym": ["heat_pump"], "lang": "en"}
|
||||
],
|
||||
},
|
||||
{
|
||||
"setting_name": "gas",
|
||||
"setting_values": [{"setting_synonym": ["gas"], "lang": "en"}],
|
||||
},
|
||||
],
|
||||
"ordered": False,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
assert trt.query_attributes() == {
|
||||
"currentModeSettings": {"operation mode": "heat_pump"},
|
||||
"on": False,
|
||||
}
|
||||
|
||||
assert trt.can_execute(
|
||||
trait.COMMAND_MODES, params={"updateModeSettings": {"operation mode": "gas"}}
|
||||
)
|
||||
|
||||
calls = async_mock_service(
|
||||
hass, water_heater.DOMAIN, water_heater.SERVICE_SET_OPERATION_MODE
|
||||
)
|
||||
await trt.execute(
|
||||
trait.COMMAND_MODES,
|
||||
BASIC_DATA,
|
||||
{"updateModeSettings": {"operation mode": "gas"}},
|
||||
{},
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data == {
|
||||
"entity_id": "water_heater.water_heater",
|
||||
"operation_mode": "gas",
|
||||
}
|
||||
|
||||
|
||||
async def test_sound_modes(hass: HomeAssistant) -> None:
|
||||
"""Test Mode trait."""
|
||||
assert helpers.get_google_type(media_player.DOMAIN, None) is not None
|
||||
|
|
Loading…
Add table
Reference in a new issue