Exctract information from JSON

The JSON is not valid as it stands: I wonder if you haven’t selected all of it properly? It can be fixed by removing the technical messages at the bottom so that it ends:

      "directionFlag": "1"
    }
  ]
}

From there, we can look at your requests.

Extract “time” only from objects that also have the “departureFlag”: “2”.

departureFlag doesn’t appear in the structure. I assume you mean directionFlag?

{{ value_json['Departure']|selectattr('directionFlag','eq','2')|map(attribute='time')|list }}

# gives me ["15:21:00","15:25:00","15:29:00","15:36:00","15:44:00"]

Once you’ve given a bit more information as per @vingerha’s posts, we’ll look at the rest of the questions.

Thank you so much!
I find it amazing that people care to reply so fast.

It is very smart to make the resource a separate file.
Then I dont have to send an API call for each piece of information that I want, right?

It will be just 3-4 trains that I want the information from. But my problem is that because I dont know how to filter out only train departures with “directionFlag”: 2, I have to create a sensors for every instance in the array.
One sensor for [0], one for [1] and so on.
Then, the only way I would know how to do this would be to create a sensor:first_train
‘{{value_json[“Departure”][0].directionFlag}}’ . Then, in Home Assistant
create a script that if sensor:first_train == 2 then display ‘{{value_json[“Departure”][0].time}}’ .

I would have to create 10 different sensors and 10 corresponding “time”-states.
I think this way I would be able to do it,
but is there no way to create something like:

if (“directionFlag” of [0,9]) == 2:
print(“time”)

I dont know, I am making up my own language.
But some code that goes through every object in the array and prints the value of “time” only
if “directionFlag” is equal to 2.

I am sorry if I am explaining poorly, but I am learning.
Thank you for the tips of including line numbers for the code.

I will repost the full JSON below.
4, 78 , 152, 226 are lines where information about every new train starts.
75, 149, 223, 297 are lines where I find “directionFlag”. This is my condition.
71, 145, 219, 293 are lines where “time” is.

Hi. Thank you for replying.

You are right, I meant “directionFlag”.

I first had to delete some of the code because I could only post 32 000 characters.
I will post it again below and hope I can get all of it.

EDIT: The full JSON is 39 000 characters, so I dont know how to post all of it.

I think you suggestion gives the correct times!
If I can now somehow use these times to get a table like

Next train leaves in: x minutes
After that in: y minutes
z minutes

and so on…

Thank you

There is no option from the source to reduce this? Donot get me wrong, I have a few very long ones but I also see issues in repsonse-to-screen. With <10 a day I guess that has no impact but it would never harm to reduce the stream as at some point many small (?) streams will make one big one.

EDIT: @Troon has given the pointers and if you donot get out, maybe can add more, I am out for the day (seems I need to have a life LOL)

There is an option to reduce it to trains only going one direction, but you have to input end destination,
and there are several trains passing in the correct direction, but with different destinations.
Not possible to add several of these filters. Only one.
Thats why “directionFlag” was such a good option, but not possible to modify the JSON from the
API Call whit “directionFlag” as a condition.

The API also can maximum give the trains for the next 60 minutes.
That is about 10 trains. But I only need the information from 3-4 of these.
So its not 10 per day, but per hour.

Thank you for the help.
Have a nice day!

Urgh, can’t believe you tried to get ChatGPT to solve this.

Create a rest sensor using the line of code I gave you to extract the list of times.

Then create a series of template sensors to extract each time from the list:

sensor:
  - platform: rest
    resource: YOUR_URL
    name: Train times list
    value_template: "{{ value_json['Departure']|selectattr('directionFlag','eq','2')|map(attribute='time')|list }}"
    scan_interval: 120

template:
  - sensor:
      - name: Next train time 1
        state: >-
          {% if states('sensor.train_times_list')|from_json|length > 0 %}
            {{ (states('sensor.train_times_list')|from_json)[0] }}
          {% else %}
            unavailable
          {% endif %}

      - name: Next train time 2
        state: >-
          {% if states('sensor.train_times_list')|from_json|length > 1 %}
            {{ (states('sensor.train_times_list')|from_json)[1] }}
          {% else %}
            unavailable
          {% endif %}

…and so on.

And in future, please format any code in your posts with the </> button.

As far as I know this only works if the main/rest sensor is below 255 char…which I believe to be the ‘state’ limit. There is an option to import as attributes which seems to have no (?I have no clue?) limit

My “extract the times” template needs 11 characters per time, plus one overhead - so should be fine so long as there aren’t more than 22 times in the list. See my post above.

OK, but I was thinking about multiple train-lines, not just the time
EDIT: the OP should chime in and present their view

You can create separate lists per line; and if needs be, constrain the number of items with something like (foo|list)[:10].

Clear but if stored in state, the limit is (?) 255. If the OP is ok then this is the best (!) option indeed as putting stuff in attribs and then adding new sensor just makes is ‘less nice’

You don’t need to stuff this in the attributes, you can use the rest integration (instead of using the rest platform)

quite sometimes it is not needed to create multiple sensors with rest. I use a workaround to collect data into a single sensor with substantial attrib…this allows me to run a graph on it which I would not be able to do if it was split into sensors (in the line of weather ‘forecast’)

Hi Troon,

I apologize for this. I thought that my original post had drowned in other requests and forgotten about.
Since I am a beginner I thought instead of asking again for help (which I eventually ended up doing) I would try ChatGPT which I had never tried before and only heard and read about in the news.
The code GPT generated looked cool to me, so I thought it might work, and thought perhaps there only was some slight error that someone could point out.
I was wrong.

Thank you so much for the work you put in to create this for me.
I am not indifferent to the time people have to put in to help others, so I am very grateful.
I will repay you by learning a lot more myself so that I dont have to waste any more time of others, and perhaps be able to help someone else down the road.

Perhaps my biggest problem when learning this (I have only been at Home Assistant and Raspberry Pi and coding for abouth a month) is that sometimes I dont even know where to begin looking for information.

Tutorials on YouTube only tend to tell you what to do, not why you do it, or how it works.
And for this case there was no tutorial for my exact request.

If you could point me in a direction where to start reading to create sensors, templates or integrate stuff from the web, I assure you I will read. I am not trying to just get other people to do my work, I want to learn.

As for you last comment,
HA said I needed code and that would fix the code being displayed in my post.
Thats why I probably havent done it correctly.
Ill try and figure out how to do what you told me.

Thank you again.

1 Like

Yes. With the extraction of trains only going one direction I think it will only be about maximum of 10-11 trains. 11 characters per time x 10 will be 110. So it should work then. Thank you for helping me!

Thank you so much for helping me! I will post back if I make it work, or not.
I think I have stupidly given the impression that perhaps I am lazy and only want you to fix my problems.
I want to say that I am a very beginner, and because I think this is so much fun that I have spent quite a lot of time to get to where I am now.
I was super exited when I could just actually get a JSON file from an API! Hehe
I didnt even know what that was a month ago.

I would be very grateful if someone could point me in a direction where I can read more about how to use custom code in Home Assistant. I have done some easy Python code, which I understand HA is based on, but I have to use Jinja2 when coding a template?
And I still have to learn how to use the configuration.yaml file correctly and how to reference to other files and how to create custom stuff.
When I dont know where to start it feels like it would take forever to educate oneself. But its fun!

Thank you again for your time!

Absolutely no need to apologise. Hope it works out for you, and do come back with code and specific questions if not. Just amused me that we’ve got to the point where it’s almost reasonable to ask a general purpose machine to write code…

HA has excellent documentation — I’ve linked to some of it already but the starting point is here:

It’s better to work through this than use YouTube tutorials — HA has evolved a lot over the years, so many videos will be out of date.

Hi again!

I have been working more on my project.
With the solution that Troon gave me:

sensor:
  - platform: rest
    resource: YOUR_URL
    name: Train times list
    value_template: "{{ value_json['Departure']|selectattr('directionFlag','eq','2')|map(attribute='time')|list }}"
    scan_interval: 120

I was able to create a sensor that gave me a list, but the next part didnt work.
Also when I worked in the template editor, it intepreted the result from

{{ states('sensor.train_times_list') }} as a string I think, making it again impossible to extraxt every time as its on element. I think when a sensor gives its state it does so only as a string? I am not sure.

After a little bit of reading I was able to then take this string and turn it into a list again with the code below, so it is possible to extract every element as its own time. Also removing the [, ] and ’ from the results.

{% set traintimes = states('sensor.train_times_list').split(',') %}
{% set traintimes = ' '.join(traintimes).replace('[','').replace(']','')
.replace("'",'').split() %}
{{ traintimes[0] }}

This produces just for example 14:31:00
Which is in the nice format I want.

But now I dont know how to get it into a sensor?
My sensors.yaml file accepts many things, but the config check alway rejects it.

Currently the sensors.yaml file looks only like this:


# Extracting list of train times into sensor

  - platform: rest
    resource: https://api.resrobot.se/v2.1/departureBoard?id=740000775&duration=60&maxJourneys=-1&products=16&passlist=0&lang=sv&format=json&requestId=random%20string&accessId=db5f04e0-7fa1-403d-8a2c-bba3641e105b
    name: Train times list
    value_template: "{{ value_json['Departure']|selectattr('directionFlag','eq','2')|map(attribute='time')|list }}"
    scan_interval: 120
    

    

        

All sensor states are strings. What bit of my solution above in post #9 didn’t work? Please post what the output of this in the template editor (Developer Tools / Template) gives:

{{ states('sensor.train_times_list') }}
{% if states('sensor.train_times_list')|from_json|length > 0 %}
  {{ (states('sensor.train_times_list')|from_json)[0] }}
{% else %}
  unavailable
{% endif %}

The from_json filter turns a string that looks like JSON into an actual object.

It gives me this in the template editor:

JSONDecodeError: unexpected character: line 1 column 2 (char 1)