I want to set my son’s alarm clock (Alexa) via Home Assistant. To do this, I want to get the substitute schedule from Stundenplan24, find my son’s class there, filter out irrelevant lessons (e.g. sports girls) and missed lessons and then get the lesson number of the first remaining lesson. The whole thing should happen via a RESTfull sensor.
I get the data as XML. The documentation says that XML from the RESTfull sensor is automatically converted to JSON and can/must be filtered using JSONPath.
As a test, I got the XML for one day, converted it at Best XML to JSON Converter Online and wrote a JSONPath (with try & error ). I can’t post the XML or JSON here. This is too long and contains sensitive data but when I test the JSONPath with JSONPath Online Evaluator, I get the following string array:
[
"2",
"3",
"4",
"5",
"6"
]
Now I have configured my REST sensor as follows (I changed the school number in the URL):
My expectation would be that the value 2 (as a string) from the upper string array comes back as a sensor value. But the sensor doesn’t work like that. In the log I get the warning:
Template variable warning: dict object has no element 0 when rendering '{{ value_json[0] }}'
It seems as if the JSONPath is not being evaluated at all and the sensor is trying to write the entire json object to value_json. What am I doing wrong here?
It’ll be the entire response and will be over 255 chars.
The value_template extracts the state from the entire response and is unaffected by the json_attributes_path, which is used for selecting the data structure level from which the attribute keys listed in json_attributes are read.
If you only want one value, you’re better off extracting it using a more involved value_template. Otherwise, adapt the JSONPath to return a dict rather than a list (a level up, perhaps?) and put its key(s) into json_attributes.
To experiment with the value_template option, copy the converted JSON into Developer Tools / Template and work from here:
{% set value_json = YOUR_JSON %}
{{ value_json['VpMobil']['Klassen'] }}
If you need further help, we’ll obviously need to see some indication of the structure. Snippets like |selectattr('Kurz','eq','7a') might help.
It’s a shame that value_json does not contain the filtered JSONPath result. That would make further processing of the result much easier. In my case, the JSON object has almost 3000 lines and I only need a single value.
Anyway. I’m now trying to build a Jinja template that I can use to get the value, but I’m not getting anywhere. Here is my current template (test stand):
{%- set first_lesson = -1 -%}
{%- if value_json|length == 0 or value_json.VpMobil.Klassen.Kl[4].Pl.Std|length == 0 -%}
{%- set first_lesson = 0 -%}
{%- else -%}
{%- set first_lesson = -2 -%}
{%- for lesson in value_json.VpMobil.Klassen.Kl[4].Pl.Std -%}
{%- set first_lesson = -3 -%}
{%- if first_lesson < 0 and lesson.Fa != '---' and lesson.Fa != 'ETH' and lesson.Fa != 'Inf1' and lesson.Fa != 'SPOw' -%}
{%- set first_lesson = -4 -%}
{%- else -%}
{%- set first_lesson = -5 -%}
{%- endif -%}
{%- else -%}
{%- set first_lesson = -6 -%}
{%- endfor -%}
{%- endif -%}
{{ first_lesson }}
value_json.VpMobil.Klassen.Kl[4].Pl.Std|length gives me the value 5. The for loop would therefore have to be run through 5 times. But it doesn’t. The else branch of the loop is not called either.
The outer if condition is false and it jumps correctly to the else branch and sets the variable from -1 to -2. The for loop is completely ignored and -2 is returned as the value at the end.
Scoping: the changes you make to first_lesson inside the for loop don’t survive outside. You need to use a namespace (docs). Try these two examples in the template editor then adapt yours:
{% set x = 1 -%}
{% for i in range(10) -%}
{% set x = x + 1 -%}
{% endfor -%}
without namespace: {{ x }}
{% set ns = namespace(x=1) -%}
{% for i in range(10) -%}
{% set ns.x = ns.x + 1 -%}
{% endfor -%}
with namespace: {{ ns.x }}
(today I learned about for-else loops…)
Put some debug print statements in them to see if you’re right, or if you’re just assuming that because first_lesson doesn’t change.
In that case, how about using the json_attributes_path / json_attributes to easily fetch the data into an attribute, then in your value_template simply fetch the state from the attribute with a state_attr(this.entity_id, 'my_attribute')? Or would that make the state out of date due to order of operations or something…