Need some help returning a variable defined in the script as a dictionary, but when returned it generates an error as returning a string.
Here is the code:
alias: HVAC Status
variables:
result: >
{# Seed Results #} {% set tp = namespace() %} {% set tp.name = 'Off' %} {%
set tp.start = '01:01:01' %} {% set tp.stop = '23:23:23' %} {% set tp.eco =
away_temperature %} {% set tp.comfort = away_temperature %} {% set tp.fan =
'' %} {% set tp.vertical = '' %} {% set tp.horizontal = '' %} {% set
tp.days_of_week = [] %} {% set tp.new_hvac_mode = 'off' %}
{{ tp }}
sequence:
- stop: All done.
response_variable: result
mode: single
and the error is:
ERROR (MainThread) [homeassistant.components.automation.ground_hvac_control] Ground HVAC Control: Error executing script. Error for call_service at pos 2: Failed to process the returned action response data, expected a dictionary, but got <class ‘str’>
Sir Good Enough,
Thanks for the reply. I have no issue creating dictions variables. I will to pass the variable back to the calling script, with having to break it all open manually, which is the only way I have found to pass the variable back to the calling script.
So:
{{ { 'name': tp.name, 'fan': tp.fan} }}
works to pass back a dictionary,
but
{{ tp }}
does not work, where ‘tp’ is a variable of type dictionary.
p.s. I think it is a namespace issue, so a small script that iterates over the dictionary and sends it back is probably what I will have to settle for, but that eludes me as well.
Thanks,
The dictionary is in the correct format, as
alias: HVAC Control Status
variables:
result: >-
{# Seed Results #}
{% set tp = namespace() %}
{% set tp.name = 'Off' %}
{% set tp.start = '01:01:01' %}
{% set tp.stop = '23:23:23' %}
{{ {'name':tp.name, 'start':tp.start, 'stop':tp.stop} }}
sequence:
- stop: All done.
response_variable: result
mode: single
works correctly, no errors.
I am looking for a solution that allows the dictionary to be passed back to the calling script/automation as a dictionary. I believe that what is happening is the dictionary fails to pass as it moves out of the defined namespace, and is turned into a string by the process of return.
You can just create the dictionary in YAML, no templates needed. But if you want to do this in templates there are options also. Here’s 3 ways to get to the same result:
Edit: I should clarify that the namespace() function will create a namespace object, which is not a dictionary. It does behave similar to a dictionary, with the exception that you can modify it, and it has special scope. But it isn’t a dictionary, and you need a dictionary.
2024-11-21 11:17:36.132 ERROR (MainThread) [homeassistant.components.automation.ground_heating] Ground Heating: Error executing script. Error for call_service at pos 1: Failed to process the returned action response data, expected a dictionary, but got <class 'str'>
2024-11-21 11:17:36.132 ERROR (MainThread) [homeassistant.components.automation.ground_heating] Error while executing automation automation.ground_heating: Failed to process the returned action response data, expected a dictionary, but got <class 'str'>
So it appears that a dictionary is not a dictionary. I am beginning to hate Home Assistant / Jinja2. The documentation talks of namespace, all the examples I have found talk of namespace, but does any of it work, no.
I wish HA used Twig for templating. So much better documented and implemented.
I will just list them all out, as that works, but is a pain in the neck to program even the smallest change.
You’ve got to pay a little better attention to my examples. All 3 work.
The first is YAML and should be fairly simple to follow. The next is how you’d write a dictionary in JSON, inside a template. The last uses python functions to create a dictionary from a list of tuples.
Pay attention to which ones need quotes for the keys and/or values, and also note that each method is going to have different rules for how (or if) you can add/remove keys or modify values.
If you let me know what you objective is I can probably help.
There are many methods to create dictionaries, but namespace() is not one of them.
You don’t need a namespace to specify computed values in a dict that’s defined in YAML. Use a template for each key’s value.
In the following example, the variable result contains a dictionary where several of its keys have statically assigned values and others are dynamically assigned using templates.
and none of these work when you try and alter them within for loops in the script.
Why?
Because for loops MUST USE A NAMESPACE VARIABLE to return a value from inside the for loop, as any variable defined in the for loop can only be used in the scope of the for loop. The fact that a for loop holds a scope separate to the script in which it resides is a mystery.
I think you’re conflating separate issues, but also I think you’ve pounded the square peg hard enough into the round hole that you achieved the result you wanted anyway.
Yes you do have to use a namespace object inside a for loop if you want to access the changed variable outside of that for loop. That does not require a dictionary.
And yes creating a new dictionary (using the 2nd form I showed in my example) will of course work to output a dictionary. That does not require a namespace.
If you’re happy with what you’ve created, then let it be. I was typing this out before I saw your latest post, and now I don’t think it will be helpful for your current situation, but you may find it useful if you decide to actually use dictionaries in the future on another project:
Working with Dictionaries
You can’t directly change a key or value in a dictionary. You have to break it apart into something else that you can change, like a list, and then modify it, and then save it back as a new (or copy it over the old) dictionary.
True, but as mentioned before, namespace != dict. That first example you posted claimed to define a dict but it wasn’t (it was a namespace).
Plus we’re now 14 posts deep into this topic and you finally reveal that your application employs a for-loop (perhaps you knew all along you would use a for-loop but overlooked to mention it) . Every example you posted before that was an attempt to define a dictionary (with no mention of using a for-loop).
Your application doesn’t need a for-loop or a namespace … unless this is part of some sort of coding game that obliges you to employ them.
The reason you’re having trouble is because you aren’t embracing yaml & jinja. I can tell that you provide those scripts with separate lists of items, which forces you to use indexed values. Which ultimately makes this harder in general. You spend so much time in your if statements and loops setting variables equal to things when it can be completely avoided if you provide your script with a single list of dictionaries. If you post how you plan to use the script, I can help you reduce that code to 25 or 30 lines of code that will be much easier to use.
As for your complaints about documentation, you should read up on Jinja. HA documentation does not cover namespace because it’s a built-in for jinja. At the top of the templating page is a link to Jinja docs, which covers namespace.