RESTfull JSON extract value

Hi.
I need help extracting the values from the “precAcumulada” field from the following API (Portuguese weather): https://api.ipma.pt/open-data/observation/meteorology/stations/observations.json.

My setup is:

rest:
  resource: https://api.ipma.pt/open-data/observation/meteorology/stations/observations.json
  scan_interval: 3600
  sensor:
    - name: "IPMA precipitacao acumulada"
      json_attributes_path: $..1210604 #I used "https://jsonpath.com/" to extract the "location" I want. There are always 24 entries
      value_template: "{{ state_attr('sensor.ipma_precAcumulada', 'value_json[2].precAcumulada') }}"
      json_attributes:
        - "precAcumulada"
    - name: "IPMA humidade acumulada"
      json_attributes_path: $..1210604
      value_template: "{{ state_attr('sensor.ipma_humidade', 'humidade') }}" #for test, tryed other field but here show the first element of 24 
      json_attributes:
        - "humidade"

For now I’m just trying to extract an element but what I really want is to extract the 24 values from this “precCumulative” field and calculate their average.

In the tests I did in the developers tools, it works without problems but in the state of the entity it is unknown.

Thanks for help.

The issue is that your json path is not unique as this station occurs (as you state) 24 times
IPMA have chosen a different setup then I have seen before, instead of grouping FIRST by station and then by hour they did this vv, which makes it quite a challenge as I assume you want to have both the hour as well as the value returned. Can I ask what the goal is?

There’s probably a neater way to do it, but this works (still under a top-level rest: declaration):

- resource: https://api.ipma.pt/open-data/observation/meteorology/stations/observations.json
  scan_interval: 3600
  sensor:
    - name: "IPMA precipitacao acumulada"
      value_template: >
        {% set ns = namespace() %}
        {% set ns.pa_sum = 0 %}
        {% set ns.pa_count = 0 %}
        {% set loc = '1210604' %}
        {% for date in value_json %}
          {% if loc in value_json[date] %}
            {% if 'precAcumulada' in value_json[date][loc] %}
              {% set ns.pa_sum = ns.pa_sum + value_json[date][loc]['precAcumulada'] %}
              {% set ns.pa_count = ns.pa_count + 1 %}
            {% endif %}
          {% endif %}
        {% endfor %}
        {% if ns.pa_count > 0 %}
          {{ ns.pa_sum / ns.pa_count }}
        {% else %}
          unavailable
        {% endif %}

Clear but in this case there is no relation between the time of day and the value.
Meaning one has to hardcode (?) the sensor per time of day
Assuming (?) this is a rolling forecast, I (but that is me) would like to have all of them as attributes in one sensor for this particular station. Possibly this is more a cli thing with jq but this is far from my experience

I was answering OP’s question:

Ah… yes, I did miss that, sorry !

No problem. To do what you need, you might want to try modifying my code to give a sensor state that is a list of values effectively refactoring the original JSON into a more helpful structure, then using another sensor to read that into attributes. I’m not sure it’s feasible to do all of that in one step.

If you do that, watch out for the 256-character limit on sensor state.

Off topic question… how would you go about to extract all forecasts for a specific station in this case? Not asking for a solution but what tech/method would this require?

Personally, I’d use AppDaemon, because I already have it set up. It basically allows you to use Python scripting of arbitrary complexity to create whatever sensor structure you want.

1 Like

Thanks @vingerha
What I want is for an automation to run at a certain time of the day (eg 11pm) that consults this API and tells me the averages, for the last 24 hours, of the “precAcumulada” field for a given station, in this case 1210604. I don’t need dates because the API records the weather values, in this case the accumulated precipitation, every hour.

In that case, in the code I gave above, set the scan_interval to something bigger than 86400 (one day); and set up an automation like this:

- alias: "Update precipitation average"
  id: c997c784-5c46-4d3c-96b9-b9a71b35c386

  trigger:
    - platform: time
      at: "23:00:00"

  action:
    - service: homeassistant.update_entity
      target:
        entity_id: sensor.ipma_precipitacao_acumulada

Yes thank you @Troon .
I’ll test the code later and let you know how it went.

1 Like

Hello @Troon
Strange but for me it’s not working. The value_template is “old school” but that’s the logic. Something is not going well because the state is always the one in the last “else”.

I had already slightly changed my configuration to support multiple sensors and it looks like this:

  - platform: rest
    resource: https://api.ipma.pt/open-data/observation/meteorology/stations/observations.json
    name: "ipma_observations"
    scan_interval: 3600
    #json_attributes:
    #  - precAcumulada
    #  - humidade
    #json_attributes_path: $..
    value_template: "OK"

  - platform: template
    sensors:
      ipma_precipitacao_acumulada:
        friendly_name: "Precipitação acumulada"
        #value_template: "{{ state_attr('sensor.ipma_observations', 'value_json[0].precAcumulada')|string }}"
        value_template: >-
          {% set ns = namespace() %}
          {% set ns.pa_sum = 0 %}
          {% set ns.pa_count = 0 %}
          {% set loc = '1210604' %}
          {% for date in value_json %}
            {% if loc in value_json[date] %}
              {% if 'precAcumulada' in value_json[date][loc] %}
                {% set ns.pa_sum = ns.pa_sum + value_json[date][loc]['precAcumulada'] %}
                {% set ns.pa_count = ns.pa_count + 1 %}
              {% endif %}
            {% endif %}
          {% endfor %}
          {% if ns.pa_count > 0 %}
            {{ ns.pa_sum / ns.pa_count }}
          {% else %}
            unavailableee
          {% endif %}
        entity_id: sensor.ipma_observations
      ipma_humidade_acumulada:
        friendly_name: "Humidade acumulada"
        value_template: "{{ state_attr('sensor.ipma_observations', 'humidade') }}"
        entity_id: sensor.ipma_observations

Thanks for help

You have deviated the structure from what Troon suggested…the value_template should be in the rest sensor(s), check the doc below on the structure to follow

RESTful - Home Assistant (home-assistant.io)

1 Like

Yes, you’re right!
It makes all the difference and it works. I will adapt the remaining cases to this way.

I was using these examples (RESTful Sensor - Home Assistant) but at the beginning of that page there is a tip essential for anyone wanting to create multiple sensors “Tip: If you want to create multiple sensors using the same endpoint, use the RESTful configuration instructions.”

Thank you for your help.

By the way, one more question for these two sensors:

  - resource: https://api.ipma.pt/open-data/forecast/meteorology/cities/daily/hp-daily-forecast-day1.json
    scan_interval: 43200
    sensor:
      - name: "IPMA_previsao_prec_amanha"
        json_attributes_path: $.*[?(@.globalIdLocal==1160900)]
        json_attributes:
          - precipitaProb
        value_template: "{{ value_json.precipitaProb }}"
        #value_template: "{{ state_attr('sensor.IPMA_previsao_prec_amanha', 'precipitaProb') }}"
      - name: "IPMA_previsao_max_amanha"
        json_attributes_path: $.*[?(@.globalIdLocal==1160900)]
        json_attributes:
          - tMax
        value_template: "{{ state_attr('sensor.IPMA_previsao_max_amanha', 'tMax') }}"

How can I put the values of precipitaProb and tMax in the status of these two sensors?
Thanks

I don’t understand why your method of referencing the attribute into the state didn’t work, but this does:

- resource: https://api.ipma.pt/open-data/forecast/meteorology/cities/daily/hp-daily-forecast-day1.json
  scan_interval: 43200
  sensor:
    - name: "IPMA_previsao_prec_amanha"
      value_template: "{{ (value_json['data']|selectattr('globalIdLocal','equalto',1160900)|list)[0]['precipitaProb'] }}"
    - name: "IPMA_previsao_max_amanha"
      value_template: "{{ (value_json['data']|selectattr('globalIdLocal','equalto',1160900)|list)[0]['tMax'] }}"

image

Thanks @Troon
Yes, me too.
If it’s as a template, like:

sensor:
- platform: rest
    resource: xxxx
    name: "yyyy"
    scan_interval: 3600
    value_template: "OK"

  - platform: template
    sensors:
      ipma_precipitacao_acumulada:
        friendly_name: "MAx tomor"
        value:template: {{ ... }}
        entity_id: sensor.yyyy

Work well