Hello everyone,
I am quite new to Home Assistant and am currently tearing my hair out regarding the correct configuration of a REST sensor to read out the current or next school vacations for Germany from www.openholidaysapi.org.
What I have so far:
- in
sensors.yaml
- platform: rest
scan_interval: 3600
name: schulferien_bw_next_json
unique_id: sensor.schulferien_bw_next_json
icon: mdi:calendar-cursor
resource_template: >-
https://openholidaysapi.org/SchoolHolidays?countryIsoCode=DE&languageIsoCode=DE&subdivisionCode=DE-BW&validFrom={{(now()).strftime('%Y-%m-%d')}}&validTo={{(now()+timedelta(days=120)).strftime('%Y-%m-%d')}}
value_template: >-
{{value_json[0]|to_json|string}}
This fills sensor.schulferien_bw_next_json
with the following:
{"id":"7c71dc62-dfe0-43e0-9d56-4599da11f959","startDate":"2024-03-23","endDate":"2024-04-05","type":"School","name":[{"language":"DE","text":"Osterferien"}],"nationwide":false,"subdivisions":[{"code":"DE-BW","shortName":"BW"}]}
or prettified:
{
"id": "7c71dc62-dfe0-43e0-9d56-4599da11f959",
"startDate": "2024-03-23",
"endDate": "2024-04-05",
"type": "School",
"name": [
{
"language": "DE",
"text": "Osterferien"
}
],
"nationwide": false,
"subdivisions": [
{
"code": "DE-BW",
"shortName": "BW"
}
]
}
As you can see, one of the most interessting entries, the name of the vacation - here “Osterferien” - is nested in name[0].text
, while other important entries such as start and end are one level above.
What I want to achieve is one entity, which is a boolean:
- true, if we have vacation actually
- false, if not
- all interesting entries as well as some calculated entries should be added as attributes to this sensor:
- name
- duration
- begins: Start datetime of the vacation
- days_until_start: Count of days until start. Zero if we have vacation actually
- end: End datetime of the vacation
- days_remaining: Count of days until end, if we have vacation actually. Zero, if we have no vacation actually.
- updated: datetime of last update
I tried to achieve this with the following template in templates.yaml
:
- trigger:
- platform: state
entity_id:
- sensor.schulferien_bw_next_json
action: []
binary_sensor:
# Schulferien?
name: schulferien_bw_next
unique_id: binary_sensor.schulferien_bw_next
icon: >-
{% set status = states('binary_sensor.schulferien_bw_next') %}
{% if status in ['off', 'unknown', 'unavailable'] %}
mdi:school
{% else %}
mdi:calendar-star
{% endif %}
state: >-
{% set value_json = states('sensor.schulferien_bw_next_json')|from_json %}
{% if ( (as_timestamp(strptime(value_json.startDate, "%Y-%m-%d"))) <= (as_timestamp(now())) ) %}
true
{% else %}
false
{% endif %}
attributes:
name: >-
{% set value_json = states('sensor.schulferien_bw_next_json')|from_json %}
{{ value_json.name[0].text }}
duration: >-
{% set value_json = states('sensor.schulferien_bw_next_json')|from_json %}
{{ ( ( (as_timestamp(strptime(value_json.endDate, "%Y-%m-%d"))) - (as_timestamp(strptime(value_json.startDate, "%Y-%m-%d"))) ) | timestamp_custom("%d") ) | float() | int }}
begins: >-
{% set value_json = states('sensor.schulferien_bw_next_json')|from_json %}
{{ strptime(value_json.startDate, "%Y-%m-%d").isoformat()}}
days_until_start: >-
{% set value_json = states('sensor.schulferien_bw_next_json')|from_json %}
{% if ( (as_timestamp(strptime(value_json.startDate, "%Y-%m-%d"))) > (as_timestamp(now())) ) %}
{{ ( ( ( (as_timestamp(strptime(value_json.startDate, "%Y-%m-%d"))) - (as_timestamp(now())) ) ) | timestamp_custom("%d") ) | float() | int }}
{% else %}
0
{% endif %}
ends: >-
{% set value_json = states('sensor.schulferien_bw_next_json')|from_json %}
{{ (((strptime(value_json.endDate, "%Y-%m-%d"))) + timedelta( hours = 23, minutes = 59, seconds = 59)).isoformat() }}
days_remaining: >-
{% set value_json = states('sensor.schulferien_bw_next_json')|from_json %}
{% if ( ( (as_timestamp(now())) > (as_timestamp(strptime(value_json.startDate, "%Y-%m-%d"))) ) and ( (as_timestamp(strptime(value_json.endDate, "%Y-%m-%d"))) > (as_timestamp(now())) )) %}
{{ ( ( (as_timestamp(strptime(value_json.endDate, "%Y-%m-%d"))) - (as_timestamp(now())) ) | timestamp_custom("%d") ) | float() | int}}
{% else %}
0
{% endif %}
updated: >-
{{ now().strftime('%Y-%m-%dT%H:%M:%S')|string }}
Just for the sake of completeness: as additional binary_sensors I have the following (for automation purposes):
- name: "Ist heute Schulfrei?"
unique_id: binary_sensor.is_schulfrei_today
icon: mdi:school-outline
state: >-
{{
is_state('binary_sensor.schulferien_bw_next', 'on')
or is_state('binary_sensor.is_feiertag_today', 'on')
or is_state('binary_sensor.is_wochenende_today', 'on')
or is_state('input_boolean.schulfrei', 'on')
}}
availability: >
{{ expand('binary_sensor.schulferien_bw_next', 'binary_sensor.is_feiertag_today', 'binary_sensor.is_wochenende_today')
| rejectattr('state', 'in', ['unknown','unavailable']) | list | count == 3 }}
- name: "Ist morgen Schulfrei?"
unique_id: binary_sensor.is_schulfrei_tomorrow
icon: mdi:school-outline
state: >-
{% set days_remaining = state_attr('binary_sensor.schulferien_bw_next', 'days_remaining') %}
{{
is_state_attr('binary_sensor.schulferien_bw_next', 'days_remaining', 1)
or days_remaining >= 1
or is_state('binary_sensor.is_feiertag_tomorrow', 'on')
or is_state('binary_sensor.is_wochenende_tomorrow', 'on')
}}
availability: >-
{{ expand('binary_sensor.schulferien_bw_next', 'binary_sensor.is_feiertag_tomorrow', 'binary_sensor.is_wochenende_tomorrow')
| rejectattr('state', 'in', ['unknown','unavailable']) | list | count == 3 }}
If I use the button to reload the REST ENTITIES AND NOTFY SERVICES
in the Developer tools the sensor is updated and filled as expected.
friendly_name: Schulferien?
name: Osterferien
duration: 14
begins: "2024-03-23T00:00:00"
days_until_start: 0
ends: "2024-04-05T23:59:59"
days_remaining: 10
updated: "2024-03-26T01:46:35"
icon: mdi:school
I thought I’d use this approach for two reasons:
- nested entries: as far as I’ve read, rest sensors don’t support them in the context of
json_attributes
- i want to have one binary sensor with attributes instead of having everything distributed on different sensors.
So far so good, but now to my problems:
-
If i reload the Rest entities I get the following Error in the
home-assistant.log
2024-03-26 01:46:35.802 ERROR (MainThread) [homeassistant.helpers.binary_sensor] Error rendering state template for binary_sensor.schulferien_bw_next: JSONDecodeError: unexpected character: line 1 column 1 (char 0)
How can I solve this? I have walidated the json, but can’t find any error in it.
-
The Template does not update automatically. I thought with the
scan_interval: 3600
the Rest-Sensorsensor.schulferien_bw_next_json
will update once a hour, and with the trigger template thebinary_sensor.schulferien_bw_next
will be updated too, but unfortunately it does not seem to work. I haven’t yet found out how to do this properly.
It would be great if someone could help me set this up correctly and cleanly.
I can well imagine that some people might be interested in this, as www.openholidaysapi.org also provides school vacations and public holidays for 23 other countries.
Best regards and Thanks in advance,
Stefan