Extracting multiple attributes from JSON?

I’m using the RESTful integration to acquire data for my bus stop, especially the next three departures for a specific bus line. I’m trying to fetch these values from the JSON response and use them in a sensor. My sensor configuration is below:

  - platform: rest
    method: POST
    name: HSL_LPV_550
    resource: https://api.digitransit.fi/routing/v1/routers/hsl/index/graphql
    payload: '{  stop(id: "HSL:1463113")   {    stopTimesForPattern(id: "HSL:2550:0:01", numberOfDepartures: 3)     {    	realtimeArrival      }  }}'
    headers:
      Content-Type: application/graphql

The POST request gives a response of:

{
  "data": {
    "stop": {
      "stopTimesForPattern": [
        {
          "realtimeArrival": 71746
        },
        {
          "realtimeArrival": 72527
        },
        {
          "realtimeArrival": 72892
        }
      ]
    }
  }
}

The above response contains the desired next three departures, the format is seconds from midnight.

However, here comes the tricky part. I would like to use the values to determine the sensor value and a sensor attribute according to the following formula (I’m comparing the realtimeArrival to the current time):

IF:
the difference on first timestamp and current time is under 4 minutes, set the second timestamp difference as sensor value and third timestamp difference as sensor attribute called next.
ELSE:
set the first timestamp difference as sensor value and second timestamp difference as sensor attribute called next.

I could extract the time difference of first arrival and current time in minutes using the following:

{% set current_time = ((now().hour*60+now().minute)*60+now().second) %}
{% set arrival_time = (value_json.data.stop.stopTimesForPattern[0].realtimeArrival) %}
{% set ETA = ((arrival_time-current_time)/60)  | int %}

My issue could be broken to the following parts:

  1. I don’t know how to extract all three values of the JSON reply and use them in value_template, as they have same names
  2. I don’t know how I can use IF-ELSE statement as described above, this seems trivial as long as I have the three values available somewhere.

But you do. You’re already doing it in your example. You’re getting the zeroth (first) item in the array.

value_json.data.stop.stopTimesForPattern[0].realtimeArrival

Just increment the array index to get the next two values:

{% set delta_t0 = ((value_json.data.stop.stopTimesForPattern[0].realtimeArrival - current_time)/60) | int %}
{% set delta_t1 = ((value_json.data.stop.stopTimesForPattern[1].realtimeArrival - current_time)/60) | int %}
{% set delta_t2 = ((value_json.data.stop.stopTimesForPattern[2].realtimeArrival - current_time)/60) | int %}

Then proceed to compare delta_t0 to delta_t1.

Now that you have said it, it sounds logical. Thank you for your help, got it working.

  - platform: rest
    method: POST
    name: HSL_LPV_550
    resource: https://api.digitransit.fi/routing/v1/routers/hsl/index/graphql
    payload: '{  stop(id: "HSL:1463113")   {    stopTimesForPattern(id: "HSL:2550:0:01", numberOfDepartures: 3)     {    	realtimeArrival      }  }}'
    headers:
      Content-Type: application/graphql
    value_template: >-
      {% set current_time = ((now().hour*60+now().minute)*60+now().second) %}
      {% set delta_t0 = ((value_json.data.stop.stopTimesForPattern[0].realtimeArrival - current_time)/60) | int %}
      {% set delta_t1 = ((value_json.data.stop.stopTimesForPattern[1].realtimeArrival - current_time)/60) | int %}
      {% set delta_t2 = ((value_json.data.stop.stopTimesForPattern[2].realtimeArrival - current_time)/60) | int %}
      {% if delta_t0 > 3 %}
        {{ delta_t0 }}
      {% else %}
        {{ delta_t1 }}
      {% endif %}

Do you know how I could add a sensor attribute called next? If I’ve understood correctly, the REST sensor can create attributes only from JSON values (using json_attributes variables). If it is not possible, I the workaround would probably be to create a second sensor using the code above, but just using delta_t1 and delta_t2 values for the sensor HSL_LPV_550_next.

Hey, I remember helping you on reddit lol. Or someone doing the exact same thing on the exact same website.

123 Taras has it right for parsing the values.

These variables are only valid inside the same template block you define them in.

Oh, you posted your update while I was typing this. Ok, next question…

You can store the entire json reply in the attributes. The json_attributes is pretty limited and I’m not 100% sure it will be able to lookup the embedded json values.

json_attributes:
  - data

That will store pretty much the entire message in the attributes. You can try calling out stopTimesForPattern to see if can indeed add that…

json_attributes:
  - data.stop.stopTimesForPattern

It might work if you do the embedded values? No clue really lol.

There isn’t a real good way to set sensor attributes manually that I can find.

You can follow the example in the RESTful sensor’s documentation. It uses a RESTful sensor purely to retrieve the data and store it in attributes. Separate Template Sensors use to the RESTful sensor’s attributes.

In your case a single separate Template Sensor would use the RESTful sensor’s attribute data to set its own state and its own attribute (called next).