Compare commits
5 commits
dev
...
manual_tri
Author | SHA1 | Date | |
---|---|---|---|
|
d9eada044c | ||
|
d9e35ac385 | ||
|
40e866f221 | ||
|
f09cea640e | ||
|
cfe681f441 |
4 changed files with 139 additions and 9 deletions
|
@ -176,18 +176,43 @@ class TriggerBaseEntity(Entity):
|
||||||
extra_state_attributes[attr] = last_state.attributes[attr]
|
extra_state_attributes[attr] = last_state.attributes[attr]
|
||||||
self._rendered[CONF_ATTRIBUTES] = extra_state_attributes
|
self._rendered[CONF_ATTRIBUTES] = extra_state_attributes
|
||||||
|
|
||||||
|
def _render_availability_template(self, variables: dict[str, Any]) -> None:
|
||||||
|
"""Render availability template."""
|
||||||
|
rendered = dict(self._static_rendered)
|
||||||
|
self._rendered = self._static_rendered
|
||||||
|
try:
|
||||||
|
key = CONF_AVAILABILITY
|
||||||
|
if key in self._to_render_simple:
|
||||||
|
rendered[key] = self._config[key].async_render(
|
||||||
|
variables,
|
||||||
|
parse_result=key in self._parse_result,
|
||||||
|
)
|
||||||
|
elif key in self._to_render_complex:
|
||||||
|
rendered[key] = render_complex(
|
||||||
|
self._config[key],
|
||||||
|
variables,
|
||||||
|
)
|
||||||
|
except TemplateError as err:
|
||||||
|
logging.getLogger(f"{__package__}.{self.entity_id.split('.')[0]}").error(
|
||||||
|
"Error rendering %s template for %s: %s", key, self.entity_id, err
|
||||||
|
)
|
||||||
|
self._rendered = rendered
|
||||||
|
|
||||||
def _render_templates(self, variables: dict[str, Any]) -> None:
|
def _render_templates(self, variables: dict[str, Any]) -> None:
|
||||||
"""Render templates."""
|
"""Render templates."""
|
||||||
|
rendered = dict(self._rendered)
|
||||||
try:
|
try:
|
||||||
rendered = dict(self._static_rendered)
|
|
||||||
|
|
||||||
for key in self._to_render_simple:
|
for key in self._to_render_simple:
|
||||||
|
if key == CONF_AVAILABILITY:
|
||||||
|
continue
|
||||||
rendered[key] = self._config[key].async_render(
|
rendered[key] = self._config[key].async_render(
|
||||||
variables,
|
variables,
|
||||||
parse_result=key in self._parse_result,
|
parse_result=key in self._parse_result,
|
||||||
)
|
)
|
||||||
|
|
||||||
for key in self._to_render_complex:
|
for key in self._to_render_complex:
|
||||||
|
if key == CONF_AVAILABILITY:
|
||||||
|
continue
|
||||||
rendered[key] = render_complex(
|
rendered[key] = render_complex(
|
||||||
self._config[key],
|
self._config[key],
|
||||||
variables,
|
variables,
|
||||||
|
@ -204,7 +229,6 @@ class TriggerBaseEntity(Entity):
|
||||||
logging.getLogger(f"{__package__}.{self.entity_id.split('.')[0]}").error(
|
logging.getLogger(f"{__package__}.{self.entity_id.split('.')[0]}").error(
|
||||||
"Error rendering %s template for %s: %s", key, self.entity_id, err
|
"Error rendering %s template for %s: %s", key, self.entity_id, err
|
||||||
)
|
)
|
||||||
self._rendered = self._static_rendered
|
|
||||||
|
|
||||||
|
|
||||||
class ManualTriggerEntity(TriggerBaseEntity):
|
class ManualTriggerEntity(TriggerBaseEntity):
|
||||||
|
@ -231,16 +255,22 @@ class ManualTriggerEntity(TriggerBaseEntity):
|
||||||
Ex: self._process_manual_data(payload)
|
Ex: self._process_manual_data(payload)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
run_variables: dict[str, Any] = {"value": value}
|
||||||
|
this = None
|
||||||
|
if state := self.hass.states.get(self.entity_id):
|
||||||
|
this = state.as_dict()
|
||||||
|
# Silently try if variable is a json and store result in `value_json` if it is.
|
||||||
|
with contextlib.suppress(*JSON_DECODE_EXCEPTIONS):
|
||||||
|
run_variables["value_json"] = json_loads(run_variables["value"])
|
||||||
|
variables = {"this": this, **(run_variables or {})}
|
||||||
|
self._render_availability_template(variables)
|
||||||
|
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
this = None
|
this = None
|
||||||
if state := self.hass.states.get(self.entity_id):
|
if state := self.hass.states.get(self.entity_id):
|
||||||
this = state.as_dict()
|
this = state.as_dict()
|
||||||
|
|
||||||
run_variables: dict[str, Any] = {"value": value}
|
variables["this"] = this
|
||||||
# Silently try if variable is a json and store result in `value_json` if it is.
|
|
||||||
with contextlib.suppress(*JSON_DECODE_EXCEPTIONS):
|
|
||||||
run_variables["value_json"] = json_loads(run_variables["value"])
|
|
||||||
variables = {"this": this, **(run_variables or {})}
|
|
||||||
|
|
||||||
self._render_templates(variables)
|
self._render_templates(variables)
|
||||||
|
|
||||||
|
|
|
@ -808,3 +808,52 @@ async def test_availability(
|
||||||
entity_state = hass.states.get("sensor.test")
|
entity_state = hass.states.get("sensor.test")
|
||||||
assert entity_state
|
assert entity_state
|
||||||
assert entity_state.state == STATE_UNAVAILABLE
|
assert entity_state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"get_config",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"command_line": [
|
||||||
|
{
|
||||||
|
"sensor": {
|
||||||
|
"name": "Test",
|
||||||
|
"command": "echo {{ states.sensor.input_sensor.state }}",
|
||||||
|
"availability": "{{ value|is_number}}",
|
||||||
|
"unit_of_measurement": " ",
|
||||||
|
"state_class": "measurement",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_template_render_not_break_for_availability(
|
||||||
|
hass: HomeAssistant, load_yaml_integration: None
|
||||||
|
) -> None:
|
||||||
|
"""Ensure command with templates get rendered properly."""
|
||||||
|
hass.states.async_set("sensor.input_sensor", "sensor_value")
|
||||||
|
|
||||||
|
# Give time for template to load
|
||||||
|
async_fire_time_changed(
|
||||||
|
hass,
|
||||||
|
dt_util.utcnow() + timedelta(minutes=1),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
|
|
||||||
|
entity_state = hass.states.get("sensor.test")
|
||||||
|
assert entity_state
|
||||||
|
assert entity_state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.input_sensor", "1")
|
||||||
|
|
||||||
|
# Give time for template to load
|
||||||
|
async_fire_time_changed(
|
||||||
|
hass,
|
||||||
|
dt_util.utcnow() + timedelta(minutes=1),
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
|
|
||||||
|
entity_state = hass.states.get("sensor.test")
|
||||||
|
assert entity_state
|
||||||
|
assert entity_state.state == "1"
|
||||||
|
|
|
@ -564,7 +564,7 @@ async def test_templating(hass: HomeAssistant) -> None:
|
||||||
"command_off": f"echo 0 > {path}",
|
"command_off": f"echo 0 > {path}",
|
||||||
"value_template": '{{ value=="1" }}',
|
"value_template": '{{ value=="1" }}',
|
||||||
"icon": (
|
"icon": (
|
||||||
'{% if states("switch.test2")=="on" %} mdi:on {% else %} mdi:off {% endif %}'
|
'{% if states("switch.test")=="on" %} mdi:on {% else %} mdi:off {% endif %}'
|
||||||
),
|
),
|
||||||
"name": "Test2",
|
"name": "Test2",
|
||||||
},
|
},
|
||||||
|
|
|
@ -1054,3 +1054,54 @@ async def test_availability_in_config(hass: HomeAssistant) -> None:
|
||||||
|
|
||||||
state = hass.states.get("sensor.rest_sensor")
|
state = hass.states.get("sensor.rest_sensor")
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
|
@respx.mock
|
||||||
|
async def test_json_response_with_availability(hass: HomeAssistant) -> None:
|
||||||
|
"""Test availability with complex json."""
|
||||||
|
|
||||||
|
respx.get("http://localhost").respond(
|
||||||
|
status_code=HTTPStatus.OK,
|
||||||
|
json={"heartbeatList": {"1": [{"status": 1, "ping": 21.4}]}},
|
||||||
|
)
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
{
|
||||||
|
DOMAIN: [
|
||||||
|
{
|
||||||
|
"resource": "http://localhost",
|
||||||
|
"sensor": [
|
||||||
|
{
|
||||||
|
"unique_id": "complex_json",
|
||||||
|
"name": "complex_json",
|
||||||
|
"value_template": '{% set v = value_json.heartbeatList["1"][-1] %}{{ v.ping }}',
|
||||||
|
"availability": '{% set v = value_json.heartbeatList["1"][-1] %}{{ v.status == 1 and is_number(v.ping) }}',
|
||||||
|
"unit_of_measurement": "ms",
|
||||||
|
"state_class": "measurement",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await async_setup_component(hass, "homeassistant", {})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(hass.states.async_all(SENSOR_DOMAIN)) == 1
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.complex_json")
|
||||||
|
assert state.state == "21.4"
|
||||||
|
|
||||||
|
respx.get("http://localhost").respond(
|
||||||
|
status_code=HTTPStatus.OK,
|
||||||
|
json={"heartbeatList": {"1": [{"status": 0, "ping": None}]}},
|
||||||
|
)
|
||||||
|
await hass.services.async_call(
|
||||||
|
"homeassistant",
|
||||||
|
"update_entity",
|
||||||
|
{ATTR_ENTITY_ID: ["sensor.complex_json"]},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
state = hass.states.get("sensor.complex_json")
|
||||||
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue