Websocket call for rendering jinja2 templates subscription (#25614)
* Websocket call for rendering jinja2 templates * Address review comments * Address review comments * Allow MATCH_ALL, but ignore it. * Always register unsub method.
This commit is contained in:
parent
d89e8ead61
commit
e7e083c547
2 changed files with 126 additions and 0 deletions
|
@ -7,6 +7,7 @@ from homeassistant.core import callback, DOMAIN as HASS_DOMAIN
|
||||||
from homeassistant.exceptions import Unauthorized, ServiceNotFound, HomeAssistantError
|
from homeassistant.exceptions import Unauthorized, ServiceNotFound, HomeAssistantError
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.service import async_get_all_descriptions
|
from homeassistant.helpers.service import async_get_all_descriptions
|
||||||
|
from homeassistant.helpers.event import async_track_state_change
|
||||||
|
|
||||||
from . import const, decorators, messages
|
from . import const, decorators, messages
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@ def async_register_commands(hass, async_reg):
|
||||||
async_reg(hass, handle_get_services)
|
async_reg(hass, handle_get_services)
|
||||||
async_reg(hass, handle_get_config)
|
async_reg(hass, handle_get_config)
|
||||||
async_reg(hass, handle_ping)
|
async_reg(hass, handle_ping)
|
||||||
|
async_reg(hass, handle_render_template)
|
||||||
|
|
||||||
|
|
||||||
def pong_message(iden):
|
def pong_message(iden):
|
||||||
|
@ -202,3 +204,45 @@ def handle_ping(hass, connection, msg):
|
||||||
Async friendly.
|
Async friendly.
|
||||||
"""
|
"""
|
||||||
connection.send_message(pong_message(msg["id"]))
|
connection.send_message(pong_message(msg["id"]))
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
@decorators.websocket_command(
|
||||||
|
{
|
||||||
|
vol.Required("type"): "render_template",
|
||||||
|
vol.Required("template"): cv.template,
|
||||||
|
vol.Optional("entity_ids"): cv.entity_ids,
|
||||||
|
vol.Optional("variables"): dict,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
def handle_render_template(hass, connection, msg):
|
||||||
|
"""Handle render_template command.
|
||||||
|
|
||||||
|
Async friendly.
|
||||||
|
"""
|
||||||
|
template = msg["template"]
|
||||||
|
template.hass = hass
|
||||||
|
|
||||||
|
variables = msg.get("variables")
|
||||||
|
|
||||||
|
entity_ids = msg.get("entity_ids")
|
||||||
|
if entity_ids is None:
|
||||||
|
entity_ids = template.extract_entities(variables)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def state_listener(*_):
|
||||||
|
connection.send_message(
|
||||||
|
messages.event_message(
|
||||||
|
msg["id"], {"result": template.async_render(variables)}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if entity_ids and entity_ids != MATCH_ALL:
|
||||||
|
connection.subscriptions[msg["id"]] = async_track_state_change(
|
||||||
|
hass, entity_ids, state_listener
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
connection.subscriptions[msg["id"]] = lambda: None
|
||||||
|
|
||||||
|
connection.send_result(msg["id"])
|
||||||
|
state_listener()
|
||||||
|
|
|
@ -389,3 +389,85 @@ async def test_subscribe_unsubscribe_events_state_changed(
|
||||||
assert msg["type"] == "event"
|
assert msg["type"] == "event"
|
||||||
assert msg["event"]["event_type"] == "state_changed"
|
assert msg["event"]["event_type"] == "state_changed"
|
||||||
assert msg["event"]["data"]["entity_id"] == "light.permitted"
|
assert msg["event"]["data"]["entity_id"] == "light.permitted"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_render_template_renders_template(
|
||||||
|
hass, websocket_client, hass_admin_user
|
||||||
|
):
|
||||||
|
"""Test simple template is rendered and updated."""
|
||||||
|
hass.states.async_set("light.test", "on")
|
||||||
|
|
||||||
|
await websocket_client.send_json(
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"type": "render_template",
|
||||||
|
"template": "State is: {{ states('light.test') }}",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
msg = await websocket_client.receive_json()
|
||||||
|
assert msg["id"] == 5
|
||||||
|
assert msg["type"] == const.TYPE_RESULT
|
||||||
|
assert msg["success"]
|
||||||
|
|
||||||
|
msg = await websocket_client.receive_json()
|
||||||
|
assert msg["id"] == 5
|
||||||
|
assert msg["type"] == "event"
|
||||||
|
event = msg["event"]
|
||||||
|
assert event == {"result": "State is: on"}
|
||||||
|
|
||||||
|
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"}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_render_template_with_manual_entity_ids(
|
||||||
|
hass, websocket_client, hass_admin_user
|
||||||
|
):
|
||||||
|
"""Test that updates to specified entity ids cause a template rerender."""
|
||||||
|
hass.states.async_set("light.test", "on")
|
||||||
|
hass.states.async_set("light.test2", "on")
|
||||||
|
|
||||||
|
await websocket_client.send_json(
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"type": "render_template",
|
||||||
|
"template": "State is: {{ states('light.test') }}",
|
||||||
|
"entity_ids": ["light.test2"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
msg = await websocket_client.receive_json()
|
||||||
|
assert msg["id"] == 5
|
||||||
|
assert msg["type"] == const.TYPE_RESULT
|
||||||
|
assert msg["success"]
|
||||||
|
|
||||||
|
msg = await websocket_client.receive_json()
|
||||||
|
assert msg["id"] == 5
|
||||||
|
assert msg["type"] == "event"
|
||||||
|
event = msg["event"]
|
||||||
|
assert event == {"result": "State is: on"}
|
||||||
|
|
||||||
|
hass.states.async_set("light.test2", "off")
|
||||||
|
msg = await websocket_client.receive_json()
|
||||||
|
assert msg["id"] == 5
|
||||||
|
assert msg["type"] == "event"
|
||||||
|
event = msg["event"]
|
||||||
|
assert event == {"result": "State is: on"}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_render_template_returns_with_match_all(
|
||||||
|
hass, websocket_client, hass_admin_user
|
||||||
|
):
|
||||||
|
"""Test that a template that would match with all entities still return success."""
|
||||||
|
await websocket_client.send_json(
|
||||||
|
{"id": 5, "type": "render_template", "template": "State is: {{ 42 }}"}
|
||||||
|
)
|
||||||
|
|
||||||
|
msg = await websocket_client.receive_json()
|
||||||
|
assert msg["id"] == 5
|
||||||
|
assert msg["type"] == const.TYPE_RESULT
|
||||||
|
assert msg["success"]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue