Today I stumbled across an article about energy-charts.info from Fraunhofer ISE in Germany which offers data including a sustainability traffic light that should assist with better automation. I found this interesting because using this webservice various aspects of home assistant need to be addressed:
Receiving data from an restful API
Visualizing graphs with given data
Visualizing graphs with historic data
Automation dependent on these data
Although I don’t possess an electrical car or any other device with certainly demands for smarter control, this still might enhance my already existing automations I use with my dishwasher and washing machine. Right now they only depend on realtime information about the sun, the active PV generation and the battery level, which can easily be used in homeassistant.
Tools
- https://api.energy-charts.info/, version 1.4 on 19.12.2024
- ApexCharts card by RomRider v2.1.2 installed via HACS
Gather the data using RESTful API
First you might wanna check the API documentation at https://api.energy-charts.info or even the website https://energy-charts.info to determine if and what might be interesting to you.
They have several services - I will focus on the electricity ‘traffic signal’, but here some more:
- Public power
- Total power
- Cross border electricity trading
- Day ahead price
- Solar share
- Wind onshore share
- Wind offshore share
- and some more
In this example I want to gather the “signal”, which is the API call for the electrical traffic light “signal” which shows green for high renewable share, yellow for average renewable share and red for low renewable share or grid congestion. On the API-Page you can even call the service with the possible parameters country and postal_code.
The response will be something like:
{
"unix_seconds": [
1734649200,
1734650100,
...
],
"share": [
101.7,
103.2,
...
],
"signal": [
2,
2,
...
],
"substitute": false,
"deprecated": false
}
Now we can configure the RESTful sensor platform (RESTful - Home Assistant) - you can change the country and postal_code in the resource attribute to your needs.
Here I will load the whole data for one day into a sensor. The sensor value will just be a boolean argument which tells wether the sensor has valid data or not.
authentication: basic
# Update the data every hour
# Don't use to small numbers here to respect the free service!
scan_interval: 3600
# You'll better use ssl verification, but need to handle the certificate then
verify_ssl: false
headers:
Content-Type: application/json
User-Agent: Home Assistant
Accept-Encoding: identity
resource: https://api.energy-charts.info/signal?country=de&postal_code=86842
sensor:
- name: Electricity traffic signal
unique_id: electricity_traffic_signal
value_template: >
{% if value_json.signal is defined %}
{{ value_json.signal | default([]) | count > 0 }}
{%- else -%}
False
{%- endif -%}
json_attributes:
- unix_seconds
- share
- signal
- substitute
- deprecated
Another possibility is to create several sensors like signal_now, signal_in_one_hour, … to save just one value. Then you’ll need to extract the relevant value. Using the first column unix_seconds you can identify the index you’ll want to extract from signal or even from share. A simple example how to read one single value is
value_template: "{{ value_json['share'][-1] | float(0) }}"
which will return the last value from the list (index -1 is the last item in the list which is at 23:45 just before midnight).
After having Homeassistant restarted, I can find the new sensor with state = True and all json attributes as sensor attributes.
Binary sensors
Two parts of the payload I think can be relevant on a daily use with automation:
- ‘deprecated’ because it will tell you in advance that the service might ‘malfunction’ in your automation within the next months
- ‘substitute’ because it might tell you not to trust the data to much as they are guessed from historical data rather then taken from primary data providers.
This must be appended to your rest-block:
binary_sensor:
- name: Electricity traffic signal webservice version deprecated
unique_id: electricity_traffic_signal_webservice_version_deprecated
value_template: "{{ value_json.deprecated }}"
- name: Electricity traffic signal using historic data
unique_id: electricity_traffic_signal_using_historic_data
value_template: "{{ value_json.substitute }}"
These sensors will either be True, False or unavaliable in case the payload was invalid or service not available.
Possible errors
The sensor gets “unavailable” in case the service cannot be reached or fails somehow.
The structure might change from time to time. This example refers to the API v. 1.4. Using the value_template query I try to evaluate the payload. In case the sensor is used at different automations or widgets the sensor value can be evaluated first. The possible cause why the payload might not be valid is when the webservice has been updated changing the response. energy-chargs.info would first set the ‘deprecated’ attribute to true for I think they’ve written 6 months in advance.
Graph
ApexCharts can be used to visualize the data. I will show the share value as a line. The traffic light signal will be shown as collored area.
type: custom:apexcharts-card
experimental:
color_threshold: true
header:
show: true
title: ApexCharts-Card
show_states: true
colorize_states: true
now:
show: true
label: Now
graph_span: 1d
span:
start: day
series:
- entity: sensor.electricity_traffic_signal
name: Share
yaxis_id: normal
data_generator: |
return entity.attributes.unix_seconds.map((time, index) =>
{return[new Date(time*1000).getTime(),
entity.attributes.share[index]]});
- entity: sensor.electricity_traffic_signal
name: Signal
yaxis_id: special
data_generator: |
return entity.attributes.unix_seconds.map((time, index) =>
{return[new Date(time*1000).getTime(),
entity.attributes.signal[index]]});
type: area
stroke_width: 0
opacity: 0.5
show:
datalabels: false
extremas: false
color_threshold:
- value: 2
color: green
- value: 1
color: yellow
- value: 0
color: red
- value: -1
color: red
yaxis:
- id: normal
max: auto
- id: special
opposite: true
align_to: 1