Restfull sensor: when is it updated, how to extract values?

Hello,
I’m trying to get the very first RESTfull sensor sensor working without success so far despite many readings on the forum (and the documentation). After many tries, the current is:

sensor:
  - platform: rest
    name: "jf"
    unique_id: "joursferies"
    scan_interval: 30
    resource: "https://calendrier.api.gouv.fr/jours-feries/metropole/2023.json"
    value_template: "{{ value_json }}"

Question 1:
When is the sensor updated? In other words what triggers its update?
Question 2:
With the above code no sensor is created, I couldn’t figure it out. Any idea?
Question 3:
Is scan_interval still allowed?

The api send the following result:

{"2023-01-01": "1er janvier", "2023-04-10": "Lundi de Pâques", "2023-05-01": "1er mai", "2023-05-08": "8 mai", "2023-05-18": "Ascension", "2023-05-29": "Lundi de Pentecôte", "2023-07-14": "14 juillet", "2023-08-15": "Assomption", "2023-11-01": "Toussaint", "2023-11-11": "11 novembre", "2023-12-25": "Jour de Noël"}

API documentation

Thank you

its updated every scan_interval

Your json output is over 254 characters, states are limited to 254 charactesr.

Yes

Thank you petro, I get it. What would be then the right approach to extract the json result?
Why scan_interval is not defined in the documentation? Is it a generic statement that can be used in many different places or shall I PR a documentation change?

Depends on the information that you want.

I don’t know.

it’s available on all sensors in the sensor section that poll devices. It would be a large PR.

I need to process all data that is returned

Then you should use the rest integration and not a single rest sensor. Put each value into it’s own sensor. If the dictionary that’s returned changes size (every year is different), then you probably will have to make a separate api call that doesn’t use dates as the key’s of the dictionary.

Thanks I’ll try that. As a matter of fact I need only to extract two dates: ascension and Pentecôte that change every year. All others are obviously static.
I would prefer as well to trigger the update once a year, for instance every 1st of december . I’m under the impression that REST is not the right approach. What route shall I’ll take then?

If the names of the holidays are always the same, I can help with the templates

Indeed name of holidays are always the same.

I think I have a working set of sensors, using the rest platform. Place this in your configuration.yaml (removing any previous jf sensors). To be clear, don’t place it under the ‘sensor:’ yaml, ‘rest:’ goes in the top level of the config yaml hierarchy.

rest:
  - resource_template: "https://calendrier.api.gouv.fr/jours-feries/metropole/{{ now().year if (now().month < 7) else now().year + 1 }}.json"
    scan_interval: 31536000
    sensor:
      - name: "JF Ascension"
        value_template: >-
          {% for value in value_json %}{{ value if 'Ascension' in value_json[value] }}{% endfor %}
      - name: "JF Lundi de Pentecôte"
        value_template: >-
          {% for value in value_json %}{{ value if 'Lundi de Pentecôte' in value_json[value]  }}{% endfor %}

I’ve tested this and get the expected dates as strings in the two sensors. I’ve set the scan_interval to 1 year. It also changes the pulled year json to next year once we hit July (so for a few days or weeks after Lundi de Pentecôte it will continue to show the current year’s dates. If this is very important we can probably work out the date math to be more exact.).

You may want to set an automation up to poll the site at an exact date and time of your choosing (which would also allow you to run it on-demand), using the Update Entity service:

service: homeassistant.update_entity
target:
  entity_id:
    - sensor.jf_ascension
    - sensor.jf_lundi_de_pentecote

1 Like

Sorry, didn’t see your response. FYI if you reply to someone, use the reply on their comment, not the reply button to the full thread.

rest:
  - resource_template: "https://calendrier.api.gouv.fr/jours-feries/metropole/{{ now().year if (now().month < 7) else now().year + 1 }}.json"
    scan_interval: 31536000
    sensor:
      - name: Ascension
        value_template: >
          {{ value_json.items() | selectattr('1', 'eq', 'Ascension') | map(attribute='0') | first | default }}
      - name: Lundi de Pentecôte
        value_template: >
          {{ value_json.items() | selectattr('1', 'eq', 'Lundi de Pentecôte') | map(attribute='0') | first | default }}

Hi petro,
I’ve read a few jinja templating articles and I’m still having a hard time wrapping my head around selectattr and map…If you don’t mind explaining a bit…I think I understand the gist of how you created this template, but why does selectattr use a ‘1’ and map use a ‘0’? And (in this particular example) what is the reason for including default? Just to prevent the sensor from ever being ‘unavailable’? I understand it’s general use, e.g. in numeric sensors…just not sure how it applies here. Thanks in advance!

His response in value_json is a dictionary. Dictionaries have a built in function called .items(). It returns a list of key value pair. I.e. {"x":1}.items()[("x", 1)], where the first object is ("x", 1). This is called a tuple by the way. To get the value "x" out of a tuple, you’d use [0], to get the value 1, you’d use [1]. selectattr iterates a list of objects and allows you to select them based on attributes.

In his case the .items() returns. [... stuff..., ("2023-05-18", "Ascension"), ... stuff... ].

So we are trying find the 1’s attribute that matches the "Ascension"selectattr('1', 'eq', "Ascension").
The value we want is in the 0 attribute, which is "2023-05-18". That’s where map comes into play. selectattr selected the object we cared about, map transforms the object into the exact thing we want, which is just the date. map(attribute='0').

Then the rest is popping the item out of the list because selectattr returns a list and we want the first item.

4 Likes

Thank you to both @gonzotek and @petro for the detailed explanations. This opens up many opportunities. I will integrate this in my code.
Just a quick question: I guess it needs a full restart of HA each time a piece of code is changed?
Second question: I guess each time HA is restarted the code is executed once, and waits for a year to be executed again ?

I’m wondering where in the documentation there is a description of this service. I could find information related to update of addons, HA instance etc. but not this specific one. I’m more in favor of an update process at a specific time in the year using a time trigger

You can restart template integrations in the developer tools → states page. The code (partly provide by gonzotek) will automatically update once a year. You can change your scan interval to be weekly or daily by putting in the number of seconds in that timeframe. I.e. 24 * 60 * 60 for daily and 7 * 24 * 60 * 60 for weekly. Yearly would be 365 * 24 * 60 * 60 but you definitely don’t want that because it wont restart until this time next year. I’d just go daily and be done with it, the calc is pretty mundane. You could also leave it to a really large number and manually update it through an automation on the first of the year like gonz suggested. Lastly, it will update every restart regardless what you do.

The update_entity service is defined here: Home Assistant Core Integration - Home Assistant

Other than hitting that server every so often, there isn’t really a downside to polling with, for example, daily or weekly frequency. The internal sensor state won’t change unless the templated value changes, so with these sensors, you won’t be filling up the db with state changes.

Some context: As integrations are being brought into the UI, Home Assistant is moving away from the naive scan_intervals and instead they are recommending disabling polling and using the update_entity service in automations. This can be done with any core polled entity that is set up in the UI, but can’t be done in your case since they haven’t updated REST in this way yet. So if you really want specific control over the polling of a REST entity, since we can’t disable the naive scan interval, using an extremely long polling period and an automation is the workaround. But petro’s advice stands, for these sensors, a simple daily, weekly or monthly interval is probably ‘good enough’.

Also keep in mind, the server may change the url or the data format, or some other external ‘breaking’ change could happen in the intervening months, and you’d notice it much later if you’re polling too infrequently.

Thank you very much for the link and detailed information. Sometimes it is hard to hit the right information in the documentation. Yes I will most probably go for the monthly update at least to make sure there is no breaking change. Last question, I hope, do you confirm that every HA reboot triggers the sensor?

Yes, it will poll again on reboot or reload of the rest entities (e.g. from the yaml tab of the developer tools).

I noticed this approach is not working. Instead, the automation has to call rest.reload

- id: fc70353e-11ec-4e6a-8248-5510654eb6ca
  alias: Mise à jour jours fériés
  trigger:
    - platform: time
      at: input_datetime.jour_ferie_update
  action:
    service: rest.reload

Is there a more granular way of doing it?