Use energy-charts.info api with Home Assistant in germany

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

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.

grafik

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

2 Likes