mirror of
https://github.com/home-assistant/core.git
synced 2026-09-26 01:11:51 -04:00
Support number entities for HomeKit valve durations (#177410)
Co-authored-by: Markus Tuominen <3738613+Markus98@users.noreply.github.com>
This commit is contained in:
co-authored by
Markus Tuominen
parent
45d351fe7f
commit
95b1211180
@@ -20,7 +20,6 @@ from homeassistant.components.input_number import (
|
||||
CONF_MAX as INPUT_NUMBER_CONF_MAX,
|
||||
CONF_MIN as INPUT_NUMBER_CONF_MIN,
|
||||
CONF_STEP as INPUT_NUMBER_CONF_STEP,
|
||||
DOMAIN as INPUT_NUMBER_DOMAIN,
|
||||
SERVICE_SET_VALUE as INPUT_NUMBER_SERVICE_SET_VALUE,
|
||||
)
|
||||
from homeassistant.components.input_select import SERVICE_SELECT_OPTION
|
||||
@@ -404,8 +403,9 @@ class ValveBase(HomeAccessory):
|
||||
def set_duration(self, value: int) -> None:
|
||||
"""Set default duration for how long the valve should remain open."""
|
||||
_LOGGER.debug("%s: Set default run time to %s", self.entity_id, value)
|
||||
assert self.linked_duration_entity
|
||||
self.async_call_service(
|
||||
INPUT_NUMBER_DOMAIN,
|
||||
split_entity_id(self.linked_duration_entity)[0],
|
||||
INPUT_NUMBER_SERVICE_SET_VALUE,
|
||||
{
|
||||
ATTR_ENTITY_ID: self.linked_duration_entity,
|
||||
|
||||
@@ -31,6 +31,7 @@ from homeassistant.components.media_player import (
|
||||
MediaPlayerDeviceClass,
|
||||
MediaPlayerEntityFeature,
|
||||
)
|
||||
from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN
|
||||
from homeassistant.components.remote import DOMAIN as REMOTE_DOMAIN, RemoteEntityFeature
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||
@@ -290,7 +291,9 @@ SWITCH_TYPE_SCHEMA = BASIC_INFO_SCHEMA.extend(
|
||||
)
|
||||
),
|
||||
),
|
||||
vol.Optional(CONF_LINKED_VALVE_DURATION): cv.entity_domain(INPUT_NUMBER_DOMAIN),
|
||||
vol.Optional(CONF_LINKED_VALVE_DURATION): cv.entity_domain(
|
||||
[INPUT_NUMBER_DOMAIN, NUMBER_DOMAIN]
|
||||
),
|
||||
vol.Optional(CONF_LINKED_VALVE_END_TIME): cv.entity_domain(SENSOR_DOMAIN),
|
||||
}
|
||||
)
|
||||
@@ -308,7 +311,9 @@ VALVE_SCHEMA = BASIC_INFO_SCHEMA.extend(
|
||||
cv.string,
|
||||
vol.In((TYPE_FAUCET, TYPE_SHOWER, TYPE_SPRINKLER, TYPE_VALVE)),
|
||||
),
|
||||
vol.Optional(CONF_LINKED_VALVE_DURATION): cv.entity_domain(INPUT_NUMBER_DOMAIN),
|
||||
vol.Optional(CONF_LINKED_VALVE_DURATION): cv.entity_domain(
|
||||
[INPUT_NUMBER_DOMAIN, NUMBER_DOMAIN]
|
||||
),
|
||||
vol.Optional(CONF_LINKED_VALVE_END_TIME): cv.entity_domain(SENSOR_DOMAIN),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -36,6 +36,7 @@ from homeassistant.components.lawn_mower import (
|
||||
LawnMowerActivity,
|
||||
LawnMowerEntityFeature,
|
||||
)
|
||||
from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN
|
||||
from homeassistant.components.select import ATTR_OPTIONS
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||
from homeassistant.components.vacuum import (
|
||||
@@ -935,33 +936,78 @@ async def test_valve_switch_with_duration_characteristics(
|
||||
assert acc.get_duration() == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("entity_id", "state", "accessory_class", "config"),
|
||||
[
|
||||
pytest.param(
|
||||
"switch.sprinkler",
|
||||
STATE_OFF,
|
||||
ValveSwitch,
|
||||
{
|
||||
"type": "sprinkler",
|
||||
"linked_valve_duration": "number.valve_duration",
|
||||
"linked_valve_end_time": "sensor.valve_end_time",
|
||||
},
|
||||
id="switch",
|
||||
),
|
||||
pytest.param(
|
||||
"valve.sprinkler",
|
||||
STATE_CLOSED,
|
||||
Valve,
|
||||
{
|
||||
"linked_valve_duration": "number.valve_duration",
|
||||
"linked_valve_end_time": "sensor.valve_end_time",
|
||||
},
|
||||
id="valve",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_valve_with_duration_characteristics(
|
||||
hass: HomeAssistant, hk_driver, events: list[Event]
|
||||
hass: HomeAssistant,
|
||||
hk_driver: HomeDriver,
|
||||
events: list[Event],
|
||||
entity_id: str,
|
||||
state: str,
|
||||
accessory_class: type[Valve | ValveSwitch],
|
||||
config: dict[str, str],
|
||||
) -> None:
|
||||
"""Test valve with set duration and remaining duration characteristics."""
|
||||
entity_id = "switch.sprinkler"
|
||||
|
||||
# Test with duration and end time entities linked
|
||||
hass.states.async_set(entity_id, STATE_OFF)
|
||||
hass.states.async_set("input_number.valve_duration", "900")
|
||||
hass.states.async_set(entity_id, state)
|
||||
hass.states.async_set(
|
||||
"number.valve_duration",
|
||||
"900",
|
||||
{"min": 60, "max": 10800, "step": 60},
|
||||
)
|
||||
hass.states.async_set("sensor.valve_end_time", dt_util.utcnow().isoformat())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Using Valve instead of ValveSwitch
|
||||
acc = Valve(
|
||||
acc = accessory_class(
|
||||
hass,
|
||||
hk_driver,
|
||||
"Valve",
|
||||
"Sprinkler",
|
||||
entity_id,
|
||||
5,
|
||||
{
|
||||
"linked_valve_duration": "input_number.valve_duration",
|
||||
"linked_valve_end_time": "sensor.valve_end_time",
|
||||
},
|
||||
config,
|
||||
)
|
||||
acc.run()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert acc.char_set_duration.value == 900
|
||||
assert acc.char_set_duration.properties["minValue"] == 60
|
||||
assert acc.char_set_duration.properties["maxValue"] == 10800
|
||||
assert acc.char_set_duration.properties["minStep"] == 60
|
||||
|
||||
call_set_value = async_mock_service(
|
||||
hass, NUMBER_DOMAIN, INPUT_NUMBER_SERVICE_SET_VALUE
|
||||
)
|
||||
acc.char_set_duration.client_update_value(300)
|
||||
await hass.async_block_till_done()
|
||||
assert call_set_value[0].data == {
|
||||
"entity_id": "number.valve_duration",
|
||||
"value": 300,
|
||||
}
|
||||
|
||||
with freeze_time(dt_util.utcnow()):
|
||||
hass.states.async_set(
|
||||
"sensor.valve_end_time",
|
||||
|
||||
@@ -135,20 +135,29 @@ def test_validate_entity_config() -> None:
|
||||
{
|
||||
"switch.test": {
|
||||
CONF_TYPE: "sprinkler",
|
||||
# Must be input_number entity
|
||||
CONF_LINKED_VALVE_DURATION: "number.valve_duration",
|
||||
# Must be input_number or number entity
|
||||
CONF_LINKED_VALVE_DURATION: "sensor.valve_duration",
|
||||
}
|
||||
},
|
||||
{
|
||||
"switch.test": {
|
||||
CONF_TYPE: "sprinkler",
|
||||
# Must be sensor (timestamp) entity
|
||||
CONF_LINKED_VALVE_END_TIME: "datetime.valve_end_time",
|
||||
}
|
||||
},
|
||||
{"fan.test": {CONF_TYPE: "invalid_type"}},
|
||||
{"climate.test": {CONF_TYPE: "invalid_type"}},
|
||||
{
|
||||
"valve.test": {
|
||||
# Must be input_number or number entity
|
||||
CONF_LINKED_VALVE_DURATION: "sensor.valve_duration",
|
||||
}
|
||||
},
|
||||
{
|
||||
"valve.test": {
|
||||
# Must be sensor (timestamp) entity
|
||||
CONF_LINKED_VALVE_END_TIME: "datetime.valve_end_time",
|
||||
# Must be input_number
|
||||
CONF_LINKED_VALVE_DURATION: "number.valve_duration",
|
||||
}
|
||||
},
|
||||
{"valve.test": {CONF_TYPE: "invalid_type"}},
|
||||
@@ -254,6 +263,17 @@ def test_validate_entity_config() -> None:
|
||||
CONF_LOW_BATTERY_THRESHOLD: DEFAULT_LOW_BATTERY_THRESHOLD,
|
||||
}
|
||||
}
|
||||
config = {
|
||||
CONF_LINKED_VALVE_DURATION: "number.valve_duration",
|
||||
CONF_LINKED_VALVE_END_TIME: "sensor.valve_end_time",
|
||||
}
|
||||
assert vec({"valve.sprinkler": config}) == {
|
||||
"valve.sprinkler": {
|
||||
CONF_LINKED_VALVE_DURATION: "number.valve_duration",
|
||||
CONF_LINKED_VALVE_END_TIME: "sensor.valve_end_time",
|
||||
CONF_LOW_BATTERY_THRESHOLD: DEFAULT_LOW_BATTERY_THRESHOLD,
|
||||
}
|
||||
}
|
||||
assert vec({"sensor.co": {CONF_THRESHOLD_CO: 500}}) == {
|
||||
"sensor.co": {CONF_THRESHOLD_CO: 500, CONF_LOW_BATTERY_THRESHOLD: 20}
|
||||
}
|
||||
@@ -299,6 +319,19 @@ def test_validate_entity_config() -> None:
|
||||
CONF_LOW_BATTERY_THRESHOLD: DEFAULT_LOW_BATTERY_THRESHOLD,
|
||||
}
|
||||
}
|
||||
config = {
|
||||
CONF_TYPE: TYPE_SPRINKLER,
|
||||
CONF_LINKED_VALVE_DURATION: "number.valve_duration",
|
||||
CONF_LINKED_VALVE_END_TIME: "sensor.valve_end_time",
|
||||
}
|
||||
assert vec({"switch.sprinkler": config}) == {
|
||||
"switch.sprinkler": {
|
||||
CONF_TYPE: TYPE_SPRINKLER,
|
||||
CONF_LINKED_VALVE_DURATION: "number.valve_duration",
|
||||
CONF_LINKED_VALVE_END_TIME: "sensor.valve_end_time",
|
||||
CONF_LOW_BATTERY_THRESHOLD: DEFAULT_LOW_BATTERY_THRESHOLD,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def test_validate_media_player_features() -> None:
|
||||
|
||||
Reference in New Issue
Block a user