home-assistant / core

:house_with_garden: Open source home automation that puts local control and privacy first.
https://www.home-assistant.io
Apache License 2.0
72.82k stars 30.51k forks source link

Quote order can break automations using scripts #38288

Closed EricWarnke closed 4 years ago

EricWarnke commented 4 years ago

The problem

When a script is created, using the script editor, the type of quotes matters even though it sometimes doesn't.

This script saves in the script editor: node_id: "{{ state_attr(entity_id,'node_id') }}" and is converted to node_id: '{{ state_attr(entity_id,''node_id'') }}'. It then works if you test the script via Developer Tools > Services. It breaks, however, if you call that script from an automation.

This script saves in the script editor: node_id: '{{ state_attr(entity_id,"node_id") }}' , does not get converted, and then works from an automation.

Whatever is converting quotes doesn't seem to be doing them properly, or at least not respecting the consistently in different areas, like automation vs services.

Environment

Problem-relevant configuration.yaml

Traceback/Error logs

Traceback (most recent call last):
File “/usr/src/homeassistant/homeassistant/helpers/script.py”, line 181, in _async_step
await getattr(
File “/usr/src/homeassistant/homeassistant/helpers/script.py”, line 373, in _async_call_service_step
await self._async_run_long_action(service_task)
File “/usr/src/homeassistant/homeassistant/helpers/script.py”, line 332, in _async_run_long_action
long_task.result()
File “/usr/src/homeassistant/homeassistant/core.py”, line 1265, in async_call
task.result()
File “/usr/src/homeassistant/homeassistant/core.py”, line 1300, in _execute_service
await handler.func(service_call)
File “/usr/src/homeassistant/homeassistant/components/script/init.py”, line 212, in service_handler
await script_entity.async_turn_on(
File “/usr/src/homeassistant/homeassistant/components/script/init.py”, line 314, in async_turn_on
await coro
File “/usr/src/homeassistant/homeassistant/helpers/script.py”, line 764, in async_run
await asyncio.shield(run.async_run())
File “/usr/src/homeassistant/homeassistant/helpers/script.py”, line 173, in async_run
await self._async_step(log_exceptions=False)
File “/usr/src/homeassistant/homeassistant/helpers/script.py”, line 181, in _async_step
await getattr(
File “/usr/src/homeassistant/homeassistant/helpers/script.py”, line 342, in _async_call_service_step
domain, service, service_data = async_prepare_call_from_config(
File “/usr/src/homeassistant/homeassistant/helpers/service.py”, line 132, in async_prepare_call_from_config
template.render_complex(config[CONF_SERVICE_DATA_TEMPLATE], variables)
File “/usr/src/homeassistant/homeassistant/helpers/template.py”, line 73, in render_complex
return {key: render_complex(item, variables) for key, item in value.items()}
File “/usr/src/homeassistant/homeassistant/helpers/template.py”, line 73, in
return {key: render_complex(item, variables) for key, item in value.items()}
File “/usr/src/homeassistant/homeassistant/helpers/template.py”, line 75, in render_complex
return value.async_render(variables)
File “/usr/src/homeassistant/homeassistant/helpers/template.py”, line 229, in async_render
return compiled.render(kwargs).strip()
File “/usr/local/lib/python3.8/site-packages/jinja2/environment.py”, line 1090, in render
self.environment.handle_exception()
File “/usr/local/lib/python3.8/site-packages/jinja2/environment.py”, line 832, in handle_exception
reraise(*rewrite_traceback_stack(source=source))
File “/usr/local/lib/python3.8/site-packages/jinja2/_compat.py”, line 28, in reraise
raise value.with_traceback(tb)
File “”, line 1, in top-level template code
File “/usr/local/lib/python3.8/site-packages/jinja2/sandbox.py”, line 462, in call
return __context.call(__obj, *args, **kwargs)
File “/usr/src/homeassistant/homeassistant/helpers/template.py”, line 1023, in wrapper
return func(hass, *args[1:], **kwargs)
File “/usr/src/homeassistant/homeassistant/helpers/template.py”, line 671, in state_attr
state_obj = _get_state(hass, entity_id)
File “/usr/src/homeassistant/homeassistant/helpers/template.py”, line 480, in _get_state
state = hass.states.get(entity_id)
File “/usr/src/homeassistant/homeassistant/core.py”, line 900, in get
return self._states.get(entity_id.lower())
AttributeError: ‘list’ object has no attribute ‘lower’

Additional information

pnbruckner commented 4 years ago

I just tested this with this script:

script1:
  sequence:
  - event: test
    event_data_template:
      node_id: '{{ state_attr(entity_id,''node_id'') }}'

and this automation:

- trigger:
  - platform: time
    at: 00:00:00
  action:
  - service: script.script1
    data:
      entity_id: zwave.abc

(I also put a fake entity in the state machine with the entity_id zwave.abc and a node_id attribute of 123.)

I ran the script via the SERVICES page giving it service data "entity_id: zwave.abc", and I also manually triggered the automation. In both cases it worked just fine.

Next I tried calling the script via the SERVICES page again, but this time gave it data "entity_id: [zwave.abc]". This time I got the same exception as you observed.

Bottom line, it seems the way your automation is calling the service is causing entity_id to be a list of entity_id's instead of a single entity_id.

I think this may be a duplicate of #28633.

pnbruckner commented 4 years ago

Could you post the automation that calls the script?

pnbruckner commented 4 years ago

BTW, from triggering the automation shown above:

2020-07-27 13:45:44 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: domain=script, service=script1, service_data=entity_id=zwave.abc>

Then I changed the automation to:

- trigger:
  - platform: time
    at: 00:00:00
  action:
  - service: script.script1
    entity_id: zwave.abc

When this automation is triggered (which results in the exception):

2020-07-27 14:07:19 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: domain=script, service=script1, service_data=entity_id=['zwave.abc']>

Notice with the original automation: service_data=entity_id=zwave.abc And with the second automation: service_data=entity_id=['zwave.abc']

So, you should probably change your automation to pass entity_id under data: instead of inline with service:.

EricWarnke commented 4 years ago

Been passing the entity_id under data the entire time. I've only used the YAML editor in the automation page to edit it.

This is my automation (I grabbed it from the YAML editor):

data:
  color: random
  duration: 2 seconds
  effect: chase
  entity_id: zwave.media_room_ls_back_row
  level: 10
service: script.inovelli_led

image

pnbruckner commented 4 years ago

Ok, then I still can't explain what you're seeing.

Please do the following. First, just to be absolutely sure there's nothing else going on, restart HA. Then get the automation to run (e.g., trigger it manually if that allows it to work normally.) Does it still happen? If so, please post the entire automation and script, copied directly from the .yaml files.

EricWarnke commented 4 years ago

I flipped the quotes back around. Restarted HA, then tried to run the automation. It worked... I have HA auto-update and I'm now on Home Assistant 0.113.2... perhaps this has been resolved in the latest version?

probot-home-assistant[bot] commented 4 years ago

script documentation script source (message by IssueLinks)

probot-home-assistant[bot] commented 4 years ago

Hey there @home-assistant/core, mind taking a look at this issue as its been labeled with an integration (script) you are listed as a codeowner for? Thanks! (message by CodeOwnersMention)

pnbruckner commented 4 years ago

I just re-ran all the tests I performed, but with 0.113.1 this time, and got the same results. So I still can't explain what you observed.

I'll close this, but it can be re-opened if you can find a way to reproduce it in such a way that I can as well.