All the code in both scripts work perfectly in the template editor. I test it there by setting the ‘room’ variable like this (which is how the original script passes it: {% set room = ['kitchen', 'sitting_room'] %}
But in a ‘live’ environment the second script doesn’t work with the data passed to it like that.
My question is, how can I pass a list from one script to another script so that it stays as a list and not as a simple string, which I suspect is what is happening now ?
However, I have experienced the same problem and I have a written a pair of filters that will be in the v.101 release. In the caller, use | to_json and in the script, use | from_json. You can then access the fields of any object (or array) just like when you created it because it’s transported from caller to script as a JSON string.
If you want to get your hands on these filters early, and you’re on a build close to current, you can take this file and copy it over the "lib/python3.x/site-packages/homeassistant/helpers/template.py" file in your home assistant installation, and then restart.
@SteveDinn
Ok, so I’m finally finding the time to try this…
I may be being a bit dim but I’m not sure I follow how to use it
I want to pass a list of rooms from an automation to a script.
That script does some stuff and then calls another script passing it that exact same list of rooms.
The last script in the chain will use that list.
So the originating Automation will call script.one like this
and script.two will act on the list, room that it has just been passed turning on input_booleans corresponding to the rooms in the list.:
#=== Set Media Players to 'in use' as appropriate
- service: input_boolean.turn_on
data_template:
entity_id: >
{#=== If passed rooms then set rooms to 'in use' as appropriate ===#}
{% if room | length != 0 %}
{%- for x in room -%}
input_boolean.announcement_on_{{ x }}_media_player{%- if not loop.last %},
{%- endif %}
{%- endfor -%}
So my question is how and where do I use the filters to_json and from_json? Presumably I convert it to JSON in the first automation (but how exactly?) but then how does it stay as JSON as it gets passed down the chain? Do I need to do something like this
room | from_json | to_json
or does it stay as JSON all the way through until the end where I simply do (bearing in mind I need to loop through the list)
has an end result of absolutely nothing. Those two filters do the opposite of each other.
The reason I introduced those filters is because when you pass an object or an array like you’ve created (['kitchen', 'sitting_room']) to a script, the parameter always comes through as a string. If you experience the same thing, you’ll notice pretty quickly that script.two won’t work as you intend.
You’ll be expecting room to be an array, when it will actuall be a string, and not even valid JSON as it uses single quotes and doesn’t escape special characters. I think this is python’s default ‘stringify’ view. The room | length != 0 will work because it’ll return the length of the string, but then the for loop will return the characters in the string one by one. So, I would do the following:
service: script.one
data:
room: ['kitchen', 'sitting_room'] | to_json <--- Convert to JSON here
service: script.two
data_template:
room: >
{{ room }} <--- This will be a string at this point, but you don't do anything with it.
Script one makes sure to convert the parameter to proper JSON before passing it.
Script two doesn’t need to make any changes, because it looks like it’s not even looking at that parameter.
Then the script.two body needs to convert the string back to an array
#=== Set Media Players to 'in use' as appropriate
- service: input_boolean.turn_on
data_template:
entity_id: >
{#=== If passed rooms then set rooms to 'in use' as appropriate ===#}
{%- set room_array = room | from_json -%} <--- Convert back to an array here.
{% if room_array | length != 0 %}
{%- for x in room_array -%}
input_boolean.announcement_on_{{ x }}_media_player{%- if not loop.last %},
{%- endif %}
{%- endfor -%}
{%- endif %}
This parses the “room” string as JSON, which will result in an array that you can access just like you instantiated it locally in script.two. Then you can just replace room with room_array in the if and for clauses, and you should be fine.
It makes perfect sense. Thank you.
Those first two paragraphs explain a lot.
I have a stupidly over engineered notification system that I want to make more flexible and robust so I need to convert it all to use this. (It’s flexible and robust enough as it is but hey, nothing that is good can’t be made better with some fiddling!)
And yes, it did seem obvious to me that room | from_json | to_json was going to end up doing nothing but I just wasn’t really sure what was happening ‘internally’ to the ‘strings’ in all the passing around…