Add this
object to MQTT templates (#77142)
* Add `this` object to MQTT templates * Only set once, remove hass guard * Set once if there is a state * Add tests TemplateStateFromEntityId calls once
This commit is contained in:
parent
c76dec138a
commit
be2366d773
2 changed files with 50 additions and 6 deletions
|
@ -17,6 +17,8 @@ from homeassistant.helpers.typing import TemplateVarsType
|
|||
|
||||
_SENTINEL = object()
|
||||
|
||||
ATTR_THIS = "this"
|
||||
|
||||
PublishPayloadType = Union[str, bytes, int, float, None]
|
||||
|
||||
|
||||
|
@ -57,7 +59,8 @@ class MqttCommandTemplate:
|
|||
entity: Entity | None = None,
|
||||
) -> None:
|
||||
"""Instantiate a command template."""
|
||||
self._attr_command_template = command_template
|
||||
self._template_state: template.TemplateStateFromEntityId | None = None
|
||||
self._command_template = command_template
|
||||
if command_template is None:
|
||||
return
|
||||
|
||||
|
@ -91,17 +94,23 @@ class MqttCommandTemplate:
|
|||
|
||||
return payload
|
||||
|
||||
if self._attr_command_template is None:
|
||||
if self._command_template is None:
|
||||
return value
|
||||
|
||||
values = {"value": value}
|
||||
values: dict[str, Any] = {"value": value}
|
||||
if self._entity:
|
||||
values[ATTR_ENTITY_ID] = self._entity.entity_id
|
||||
values[ATTR_NAME] = self._entity.name
|
||||
if not self._template_state:
|
||||
self._template_state = template.TemplateStateFromEntityId(
|
||||
self._command_template.hass, self._entity.entity_id
|
||||
)
|
||||
values[ATTR_THIS] = self._template_state
|
||||
|
||||
if variables is not None:
|
||||
values.update(variables)
|
||||
return _convert_outgoing_payload(
|
||||
self._attr_command_template.async_render(values, parse_result=False)
|
||||
self._command_template.async_render(values, parse_result=False)
|
||||
)
|
||||
|
||||
|
||||
|
@ -117,6 +126,7 @@ class MqttValueTemplate:
|
|||
config_attributes: TemplateVarsType = None,
|
||||
) -> None:
|
||||
"""Instantiate a value template."""
|
||||
self._template_state: template.TemplateStateFromEntityId | None = None
|
||||
self._value_template = value_template
|
||||
self._config_attributes = config_attributes
|
||||
if value_template is None:
|
||||
|
@ -150,6 +160,11 @@ class MqttValueTemplate:
|
|||
if self._entity:
|
||||
values[ATTR_ENTITY_ID] = self._entity.entity_id
|
||||
values[ATTR_NAME] = self._entity.name
|
||||
if not self._template_state and self._value_template.hass:
|
||||
self._template_state = template.TemplateStateFromEntityId(
|
||||
self._value_template.hass, self._entity.entity_id
|
||||
)
|
||||
values[ATTR_THIS] = self._template_state
|
||||
|
||||
if default == _SENTINEL:
|
||||
return self._value_template.async_render_with_possible_json_value(
|
||||
|
|
|
@ -299,7 +299,7 @@ async def test_command_template_variables(hass, mqtt_mock_entry_with_yaml_config
|
|||
"command_topic": topic,
|
||||
"name": "Test Select",
|
||||
"options": ["milk", "beer"],
|
||||
"command_template": '{"option": "{{ value }}", "entity_id": "{{ entity_id }}", "name": "{{ name }}"}',
|
||||
"command_template": '{"option": "{{ value }}", "entity_id": "{{ entity_id }}", "name": "{{ name }}", "this_object_state": "{{ this.state }}"}',
|
||||
}
|
||||
},
|
||||
)
|
||||
|
@ -319,7 +319,7 @@ async def test_command_template_variables(hass, mqtt_mock_entry_with_yaml_config
|
|||
|
||||
mqtt_mock.async_publish.assert_called_once_with(
|
||||
topic,
|
||||
'{"option": "beer", "entity_id": "select.test_select", "name": "Test Select"}',
|
||||
'{"option": "beer", "entity_id": "select.test_select", "name": "Test Select", "this_object_state": "milk"}',
|
||||
0,
|
||||
False,
|
||||
)
|
||||
|
@ -327,6 +327,20 @@ async def test_command_template_variables(hass, mqtt_mock_entry_with_yaml_config
|
|||
state = hass.states.get("select.test_select")
|
||||
assert state.state == "beer"
|
||||
|
||||
# Test that TemplateStateFromEntityId is not called again
|
||||
with patch(
|
||||
"homeassistant.helpers.template.TemplateStateFromEntityId", MagicMock()
|
||||
) as template_state_calls:
|
||||
await hass.services.async_call(
|
||||
"select",
|
||||
"select_option",
|
||||
{"entity_id": "select.test_select", "option": "milk"},
|
||||
blocking=True,
|
||||
)
|
||||
assert template_state_calls.call_count == 0
|
||||
state = hass.states.get("select.test_select")
|
||||
assert state.state == "milk"
|
||||
|
||||
|
||||
async def test_value_template_value(hass):
|
||||
"""Test the rendering of MQTT value template."""
|
||||
|
@ -359,10 +373,25 @@ async def test_value_template_value(hass):
|
|||
# test value template with entity
|
||||
entity = Entity()
|
||||
entity.hass = hass
|
||||
entity.entity_id = "select.test"
|
||||
tpl = template.Template("{{ value_json.id }}")
|
||||
val_tpl = mqtt.MqttValueTemplate(tpl, entity=entity)
|
||||
assert val_tpl.async_render_with_possible_json_value('{"id": 4321}') == "4321"
|
||||
|
||||
# test this object in a template
|
||||
tpl2 = template.Template("{{ this.entity_id }}")
|
||||
val_tpl2 = mqtt.MqttValueTemplate(tpl2, entity=entity)
|
||||
assert val_tpl2.async_render_with_possible_json_value("bla") == "select.test"
|
||||
|
||||
with patch(
|
||||
"homeassistant.helpers.template.TemplateStateFromEntityId", MagicMock()
|
||||
) as template_state_calls:
|
||||
tpl3 = template.Template("{{ this.entity_id }}")
|
||||
val_tpl3 = mqtt.MqttValueTemplate(tpl3, entity=entity)
|
||||
val_tpl3.async_render_with_possible_json_value("call1")
|
||||
val_tpl3.async_render_with_possible_json_value("call2")
|
||||
assert template_state_calls.call_count == 1
|
||||
|
||||
|
||||
async def test_service_call_without_topic_does_not_publish(
|
||||
hass, mqtt_mock_entry_no_yaml_config
|
||||
|
|
Loading…
Add table
Reference in a new issue