Return the listeners with the template result for the websocket api (#39925)
This commit is contained in:
parent
9b29d09d45
commit
741487a1fc
4 changed files with 118 additions and 11 deletions
|
@ -253,9 +253,11 @@ def handle_render_template(hass, connection, msg):
|
|||
template.hass = hass
|
||||
|
||||
variables = msg.get("variables")
|
||||
info = None
|
||||
|
||||
@callback
|
||||
def _template_listener(event, updates):
|
||||
nonlocal info
|
||||
track_template_result = updates.pop()
|
||||
result = track_template_result.result
|
||||
if isinstance(result, TemplateError):
|
||||
|
@ -267,7 +269,11 @@ def handle_render_template(hass, connection, msg):
|
|||
|
||||
result = None
|
||||
|
||||
connection.send_message(messages.event_message(msg["id"], {"result": result}))
|
||||
connection.send_message(
|
||||
messages.event_message(
|
||||
msg["id"], {"result": result, "listeners": info.listeners} # type: ignore
|
||||
)
|
||||
)
|
||||
|
||||
info = async_track_template_result(
|
||||
hass, [TrackTemplate(template, variables)], _template_listener
|
||||
|
|
|
@ -581,6 +581,15 @@ class _TrackTemplateResultInfo:
|
|||
self._last_info = self._info.copy()
|
||||
self._create_listeners()
|
||||
|
||||
@property
|
||||
def listeners(self) -> Dict:
|
||||
"""State changes that will cause a re-render."""
|
||||
return {
|
||||
"all": self._all_listener is not None,
|
||||
"entities": self._last_entities,
|
||||
"domains": self._last_domains,
|
||||
}
|
||||
|
||||
@property
|
||||
def _needs_all_listener(self) -> bool:
|
||||
for track_template_ in self._track_templates:
|
||||
|
|
|
@ -420,14 +420,20 @@ async def test_render_template_renders_template(
|
|||
assert msg["id"] == 5
|
||||
assert msg["type"] == "event"
|
||||
event = msg["event"]
|
||||
assert event == {"result": "State is: on"}
|
||||
assert event == {
|
||||
"result": "State is: on",
|
||||
"listeners": {"all": False, "domains": [], "entities": ["light.test"]},
|
||||
}
|
||||
|
||||
hass.states.async_set("light.test", "off")
|
||||
msg = await websocket_client.receive_json()
|
||||
assert msg["id"] == 5
|
||||
assert msg["type"] == "event"
|
||||
event = msg["event"]
|
||||
assert event == {"result": "State is: off"}
|
||||
assert event == {
|
||||
"result": "State is: off",
|
||||
"listeners": {"all": False, "domains": [], "entities": ["light.test"]},
|
||||
}
|
||||
|
||||
|
||||
async def test_render_template_manual_entity_ids_no_longer_needed(
|
||||
|
@ -453,14 +459,20 @@ async def test_render_template_manual_entity_ids_no_longer_needed(
|
|||
assert msg["id"] == 5
|
||||
assert msg["type"] == "event"
|
||||
event = msg["event"]
|
||||
assert event == {"result": "State is: on"}
|
||||
assert event == {
|
||||
"result": "State is: on",
|
||||
"listeners": {"all": False, "domains": [], "entities": ["light.test"]},
|
||||
}
|
||||
|
||||
hass.states.async_set("light.test", "off")
|
||||
msg = await websocket_client.receive_json()
|
||||
assert msg["id"] == 5
|
||||
assert msg["type"] == "event"
|
||||
event = msg["event"]
|
||||
assert event == {"result": "State is: off"}
|
||||
assert event == {
|
||||
"result": "State is: off",
|
||||
"listeners": {"all": False, "domains": [], "entities": ["light.test"]},
|
||||
}
|
||||
|
||||
|
||||
async def test_render_template_with_error(
|
||||
|
@ -480,7 +492,10 @@ async def test_render_template_with_error(
|
|||
assert msg["id"] == 5
|
||||
assert msg["type"] == "event"
|
||||
event = msg["event"]
|
||||
assert event == {"result": None}
|
||||
assert event == {
|
||||
"result": None,
|
||||
"listeners": {"all": True, "domains": [], "entities": []},
|
||||
}
|
||||
|
||||
assert "my_unknown_var" in caplog.text
|
||||
assert "TemplateError" in caplog.text
|
||||
|
|
|
@ -809,20 +809,33 @@ async def test_track_template_result_complex(hass):
|
|||
hass.states.async_set("light.one", "on")
|
||||
hass.states.async_set("lock.one", "locked")
|
||||
|
||||
async_track_template_result(
|
||||
info = async_track_template_result(
|
||||
hass, [TrackTemplate(template_complex, None)], specific_run_callback
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert info.listeners == {"all": True, "domains": set(), "entities": set()}
|
||||
|
||||
hass.states.async_set("sensor.domain", "light")
|
||||
await hass.async_block_till_done()
|
||||
assert len(specific_runs) == 1
|
||||
assert specific_runs[0].strip() == "['light.one']"
|
||||
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": {"light"},
|
||||
"entities": {"sensor.domain"},
|
||||
}
|
||||
|
||||
hass.states.async_set("sensor.domain", "lock")
|
||||
await hass.async_block_till_done()
|
||||
assert len(specific_runs) == 2
|
||||
assert specific_runs[1].strip() == "['lock.one']"
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": {"lock"},
|
||||
"entities": {"sensor.domain"},
|
||||
}
|
||||
|
||||
hass.states.async_set("sensor.domain", "all")
|
||||
await hass.async_block_till_done()
|
||||
|
@ -830,11 +843,17 @@ async def test_track_template_result_complex(hass):
|
|||
assert "light.one" in specific_runs[2]
|
||||
assert "lock.one" in specific_runs[2]
|
||||
assert "sensor.domain" in specific_runs[2]
|
||||
assert info.listeners == {"all": True, "domains": set(), "entities": set()}
|
||||
|
||||
hass.states.async_set("sensor.domain", "light")
|
||||
await hass.async_block_till_done()
|
||||
assert len(specific_runs) == 4
|
||||
assert specific_runs[3].strip() == "['light.one']"
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": {"light"},
|
||||
"entities": {"sensor.domain"},
|
||||
}
|
||||
|
||||
hass.states.async_set("light.two", "on")
|
||||
await hass.async_block_till_done()
|
||||
|
@ -842,6 +861,11 @@ async def test_track_template_result_complex(hass):
|
|||
assert "light.one" in specific_runs[4]
|
||||
assert "light.two" in specific_runs[4]
|
||||
assert "sensor.domain" not in specific_runs[4]
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": {"light"},
|
||||
"entities": {"sensor.domain"},
|
||||
}
|
||||
|
||||
hass.states.async_set("light.three", "on")
|
||||
await hass.async_block_till_done()
|
||||
|
@ -850,26 +874,51 @@ async def test_track_template_result_complex(hass):
|
|||
assert "light.two" in specific_runs[5]
|
||||
assert "light.three" in specific_runs[5]
|
||||
assert "sensor.domain" not in specific_runs[5]
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": {"light"},
|
||||
"entities": {"sensor.domain"},
|
||||
}
|
||||
|
||||
hass.states.async_set("sensor.domain", "lock")
|
||||
await hass.async_block_till_done()
|
||||
assert len(specific_runs) == 7
|
||||
assert specific_runs[6].strip() == "['lock.one']"
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": {"lock"},
|
||||
"entities": {"sensor.domain"},
|
||||
}
|
||||
|
||||
hass.states.async_set("sensor.domain", "single_binary_sensor")
|
||||
await hass.async_block_till_done()
|
||||
assert len(specific_runs) == 8
|
||||
assert specific_runs[7].strip() == "unknown"
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": set(),
|
||||
"entities": {"binary_sensor.single", "sensor.domain"},
|
||||
}
|
||||
|
||||
hass.states.async_set("binary_sensor.single", "binary_sensor_on")
|
||||
await hass.async_block_till_done()
|
||||
assert len(specific_runs) == 9
|
||||
assert specific_runs[8].strip() == "binary_sensor_on"
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": set(),
|
||||
"entities": {"binary_sensor.single", "sensor.domain"},
|
||||
}
|
||||
|
||||
hass.states.async_set("sensor.domain", "lock")
|
||||
await hass.async_block_till_done()
|
||||
assert len(specific_runs) == 10
|
||||
assert specific_runs[9].strip() == "['lock.one']"
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": {"lock"},
|
||||
"entities": {"sensor.domain"},
|
||||
}
|
||||
|
||||
|
||||
async def test_track_template_result_with_wildcard(hass):
|
||||
|
@ -893,7 +942,7 @@ async def test_track_template_result_with_wildcard(hass):
|
|||
hass.states.async_set("cover.office_window", "closed")
|
||||
hass.states.async_set("cover.office_skylight", "open")
|
||||
|
||||
async_track_template_result(
|
||||
info = async_track_template_result(
|
||||
hass, [TrackTemplate(template_complex, None)], specific_run_callback
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -901,6 +950,7 @@ async def test_track_template_result_with_wildcard(hass):
|
|||
hass.states.async_set("cover.office_window", "open")
|
||||
await hass.async_block_till_done()
|
||||
assert len(specific_runs) == 1
|
||||
assert info.listeners == {"all": True, "domains": set(), "entities": set()}
|
||||
|
||||
assert "cover.office_drapes=closed" in specific_runs[0]
|
||||
assert "cover.office_window=open" in specific_runs[0]
|
||||
|
@ -935,11 +985,22 @@ async def test_track_template_result_with_group(hass):
|
|||
def specific_run_callback(event, updates):
|
||||
specific_runs.append(updates.pop().result)
|
||||
|
||||
async_track_template_result(
|
||||
info = async_track_template_result(
|
||||
hass, [TrackTemplate(template_complex, None)], specific_run_callback
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": set(),
|
||||
"entities": {
|
||||
"group.power_sensors",
|
||||
"sensor.power_1",
|
||||
"sensor.power_2",
|
||||
"sensor.power_3",
|
||||
},
|
||||
}
|
||||
|
||||
hass.states.async_set("sensor.power_1", 100.1)
|
||||
await hass.async_block_till_done()
|
||||
assert len(specific_runs) == 1
|
||||
|
@ -978,10 +1039,11 @@ async def test_track_template_result_and_conditional(hass):
|
|||
def specific_run_callback(event, updates):
|
||||
specific_runs.append(updates.pop().result)
|
||||
|
||||
async_track_template_result(
|
||||
info = async_track_template_result(
|
||||
hass, [TrackTemplate(template, None)], specific_run_callback
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert info.listeners == {"all": False, "domains": set(), "entities": {"light.a"}}
|
||||
|
||||
hass.states.async_set("light.b", "on")
|
||||
await hass.async_block_till_done()
|
||||
|
@ -991,11 +1053,21 @@ async def test_track_template_result_and_conditional(hass):
|
|||
await hass.async_block_till_done()
|
||||
assert len(specific_runs) == 1
|
||||
assert specific_runs[0] == "on"
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": set(),
|
||||
"entities": {"light.a", "light.b"},
|
||||
}
|
||||
|
||||
hass.states.async_set("light.b", "off")
|
||||
await hass.async_block_till_done()
|
||||
assert len(specific_runs) == 2
|
||||
assert specific_runs[1] == "off"
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": set(),
|
||||
"entities": {"light.a", "light.b"},
|
||||
}
|
||||
|
||||
hass.states.async_set("light.a", "off")
|
||||
await hass.async_block_till_done()
|
||||
|
@ -1051,7 +1123,7 @@ async def test_track_template_result_iterator(hass):
|
|||
def filter_callback(event, updates):
|
||||
filter_runs.append(updates.pop().result)
|
||||
|
||||
async_track_template_result(
|
||||
info = async_track_template_result(
|
||||
hass,
|
||||
[
|
||||
TrackTemplate(
|
||||
|
@ -1066,6 +1138,11 @@ async def test_track_template_result_iterator(hass):
|
|||
filter_callback,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert info.listeners == {
|
||||
"all": False,
|
||||
"domains": {"sensor"},
|
||||
"entities": {"sensor.test"},
|
||||
}
|
||||
|
||||
hass.states.async_set("sensor.test", 6)
|
||||
await hass.async_block_till_done()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue