Tibber - Schedul prices upcoming 24 hours prices!

Hi, I’m trying to set up your node red integration but cant get my head around how you enter the helper entities. Could you please share what values you use and how you enter them in the helpers and also expand a bit on what the purpose for each is
For example gransvarde_low vs granspris_lag ? or gransvarde_hog vs granspris_hog.

Cheers!

Hi,
I am trying to replicate your nicely mad node-red application for Tibber.
However, I get a error of t2 nodes:
Flows stopped due to missing node types.

  • tibber-api-endpoint
  • tibber-data
    It looks like these are not recognised and need to be installed?

Sorry, I was too fast.
Saw this node comes from tibber :slight_smile:

I installed everything and made the helpers (numeric input). All went well.
However, I keep getting some errors. Maybe I missed something?
This is what I get:

Any suggestions?

Could you please share your settings regarding the numeric input and inform me of their meaning if you don’t mind?

Thanks!!

I imported this and made requested inputs, restarted HA and there is more music!!
Maybe you can help with 2 (hopefully) minor/easy errors:

Price import is working perfect. (I guess the error comes from not having the tomorrow pricing available)

What I don’t understand is why the treshold high and treshhold low have the same value.
Also runappliance high and runappliance low got the same status.

Thanks for clearing that up :slight_smile:

To be complete, the helpers config & values:
image



image

When importing this view, a couple of fields are probably missing.
Do I need to setup these inputfields or does this need to come from Node-red?

Edit: I discovered that a lot of these fields were renamed by node-red companion. After updating this, most of the fields worked.
Got two questions left:
1:
I am missing the sensor.tresholdprices
Where can I find this? Or does this come from tibber?

2:
Below fields; what is the calculation behind & should they auto-update from node-red with actual prices?
image

And… ; would it be possible to integrate a function wher you can put in an amount of hours and the system comes back with the cheapest time to start.
So if I put in 3 hours, it comes with the cheapest 3 hour timeframe / starttime.

Hi, I’m nearly having it working.
Only the entity: ‘sensor.tresholdprices’ I cannot find. Can you let me know what that is / where to find?

Nive work i got one problem . My sensor for W is upside down

I am using apex-charts, too and wanted to re-create the current view from the App (just showing prices as far as possible). Also color-highlighting certain price levels (when its expensive/cheap) is something i like.
Maybe it helps someone.

configuration.yaml:

  - platform: rest
    name: Tibber prices
    resource: https://api.tibber.com/v1-beta/gql
    method: POST
    scan_interval: 60
    payload: '{ "query": "{ viewer { homes { currentSubscription { priceInfo { today { total startsAt } tomorrow { total startsAt }}}}}}" }'
    json_attributes_path: "$.data.viewer.homes[0].currentSubscription.priceInfo"
    json_attributes:
      - today
      - tomorrow
    value_template: Ok
    headers:
      Authorization: "TIBBER DEVELOPER API KEY HERE"
      Content-Type: application/json
      User-Agent: REST

card config:

type: custom:apexcharts-card
experimental:
  color_threshold: true
apex_config: null
header:
  show: true
  title: Power price
  show_states: true
  colorize_states: true
hours_12: false
graph_span: 36h
span:
  start: hour
yaxis:
  - id: kWh
    decimals: 3
    opposite: true
    max: 500
    apex_config:
      tickAmount: 4
  - id: EUR
    decimals: 3
series:
  - entity: sensor.tibber_prices
    stroke_width: 8
    float_precision: 3
    curve: smooth
    color: black
    opacity: 1
    color_threshold:
      - value: 0.26
        color: '#a83232'
      - value: 0.23
        color: '#f0ec16'
      - value: 0.18
        color: '#00ff2f'
    show:
      legend_value: false
      extremas: false
      in_header: false
    extend_to: now
    name: Tibber
    yaxis_id: EUR
    data_generator: |
      var today = entity.attributes.today.map((record, index) => {
              return [record.startsAt, record.total];
            });
      var tomorrow = entity.attributes.tomorrow.map((record, index) => {
              return [record.startsAt, record.total];
            });

      return today.concat(tomorrow);
  - entity: sensor.electricity_price_XXX-YOUR-ADDRESS
    extend_to: now
    float_precision: 3
    show:
      extremas: false
      in_chart: false
    stroke_width: 5
    yaxis_id: EUR
    name: Price now

3 Likes

Thank you very much. It helped me a lot

Thank you very much, jonas21 - that helped me so much :grin: :+1:

Hi everyone,

I have now also tinkered with it a bit and am very happy with the result. Since the code in this thread helped me so much, I’ll post mine here too. Maybe it will help one or the other.

Many greetings
MrM

image

Apex Chart Config:

type: custom:apexcharts-card
experimental:
  color_threshold: true
apex_config: null
header:
  show: true
  title: Tibber Preisvorschau
  standard_format: true
  show_states: true
  colorize_states: false
now:
  show: true
hours_12: false
graph_span: 30h
span:
  start: day
yaxis:
  - id: kWh
    decimals: 3
    opposite: true
    max: 1000
    apex_config:
      tickAmount: 4
  - id: EUR
    decimals: 3
series:
  # Aktueller Verbrauch als Graph
  - entity: sensor.energieverbrauch_aktuell  # <--- You may edit this to your sensor
    type: area
    show:
      legend_value: false
      extremas: false
    name: Verbrauch
    stroke_width: 5
    curve: smooth
    color: '#ffbd5c'
    opacity: 0.5
    yaxis_id: kWh
    group_by:
      func: avg
      duration: 60min
  # Tibber - Verlauf
  - entity: sensor.tibber_preise  # <--- You may edit this to your sensor (if you use the configuration.yaml code from jonas21 it would be "tibber_prices" [generated from name])
    name: Tibber
    stroke_width: 5
    float_precision: 3
    curve: smooth
    color: '#ffbd5c'
    opacity: 1
    color_threshold:
      - value: 0.35
        color: '#a83232'
      - value: 0.27
        color: '#f0ec16'
      - value: 0.2
        color: '#00ff2f'
    show:
      legend_value: false
      extremas: false
      in_header: false
    extend_to: now
    yaxis_id: EUR
    data_generator: |
      var today = entity.attributes.today.map((record, index) => {
              return [record.startsAt, record.total];
            });
      var tomorrow = entity.attributes.tomorrow.map((record, index) => {
              return [record.startsAt, record.total];
            });

      return today.concat(tomorrow);
  # Tibber - Aktueller Preis
  - entity: sensor.electricity_price_tibber # <--- You may edit this to your sensor
    name: Aktueller Preis
    extend_to: now
    float_precision: 3
    show:
      extremas: false
      in_chart: false
    stroke_width: 5
    yaxis_id: EUR
2 Likes

im trying to use the rest sensor but i keep getting errors for each entry. i have several other rest sensors so i cant simply state this as a new one and none of the other lines work (json attribute, path ) etc.

has anyone modified this sensors to work with other sensors in config?

Never worked with “rest” but everything i try results in a failure. If i use the original template ill get:

"Error loading /config/configuration.yaml: mapping values are not allowed here
in "/config/configuration.yaml", line 68, column 9"
tibber_custom:
- platform: rest
    name: Tibber prices
    resource: https://api.tibber.com/v1-beta/gql
    method: POST
    scan_interval: 60
    payload: '{ "query": "{ viewer { homes { currentSubscription { priceInfo { today { total startsAt } tomorrow { total startsAt }}}}}}" }'
    json_attributes_path: "$.data.viewer.homes[0].currentSubscription.priceInfo"
    json_attributes:
      - today
      - tomorrow
    value_template: Ok
    headers:
      Authorization: "XYZ"
      Content-Type: application/json
      User-Agent: REST

Anyone could help please?

1 Like

This looks like it works quite well. I still have to see if it is more consistent than Nordpool and I have to get it to show me the full 48 hours (I already changed the config, but it didn’t seem to stick) but apart from that … great work!

Since this thread helped me a lot, I’ll also post my solution. It involves:

First I set up a rest sensor which gets the price data from tibber API:

- platform: rest
  name: Tibber Prices
  resource: https://api.tibber.com/v1-beta/gql
  method: POST
  payload: '{ "query": "{ viewer { homes { currentSubscription { status priceInfo { current { total } today { total } tomorrow { total } } } } } }" }'
  json_attributes_path: "$.data.viewer.homes[0].currentSubscription.priceInfo"
  json_attributes:
    - today
    - tomorrow
  value_template: "{{ value_json.data.viewer.homes[0].currentSubscription.priceInfo.current.total | float }}"
  scan_interval: 30
  headers:
    Authorization: !secret tibber_token
    Content-Type: application/json
    User-Agent: REST
  unit_of_measurement: EUR/kWh

This sensor will have 2 attributes “today” and “tomorrow” which will contain the prices. As a bonus, the sensor state will always be the current price.

With that you can create an apex chart like this:

type: custom:apexcharts-card
experimental:
  color_threshold: true
all_series_config:
  unit: Cent/kWh
apex_config:
  grid:
    show: true
    borderColor: '#E0E0E0'
  chart:
    height: 250px
  tooltip:
    enabled: true
    followCursor: false
    x:
      show: false
    fixed:
      enabled: true
header:
  show: true
  title: Strompreis
  show_states: true
  colorize_states: true
  standard_format: false
graph_span: 48h
now:
  show: true
  color: 9E9E9E
span:
  start: day
series:
  - entity: sensor.tibber_prices
    show:
      in_header: before_now
      name_in_header: false
    color_threshold:
      - value: 0
        color: 4DD0E1
      - value: 10
        color: 26A69A
      - value: 15
        color: 4CAF50
      - value: 20
        color: 7CB342
      - value: 25
        color: FBC02D
      - value: 30
        color: EF6C00
      - value: 40
        color: B71C1C
    type: line
    curve: stepline
    extend_to: false
    stroke_width: 4
    float_precision: 2
    data_generator: |
      const noon = new Date()
      noon.setHours(0, 0, 0, 0)
      const prices = entity.attributes.today.concat(entity.attributes.tomorrow);
      const data = [];
      for(let i = 0; i < prices.length; i++) {
        data.push([noon.getTime() + i * 1000 * 3600, prices[i].total * 100])
      }
      return data;

I’ll update this post as I improve this. Honestly, I do not know how this chart behaves tomorrow when future prices are not (yet) available. I hope it’s somehow robust to paste those two arrays and loop over the length.

Edit 1:

  • Removed the tibber_data HACS component because it fails to populate future prices.
  • Added a rest sensor that directly requests the tibber API (surprisingly simple).
17 Likes

good work my friend

Hi As a work around I implemented a simple Node-RED flow and use apex card to visualize.
NodeRED requests the data from tibber (you have to use your credentials) and updates a sensor with state and attributes.

The apex chard has the following code:

type: custom:apexcharts-card
header:
  show: true
  title: Tibber Price Today & Tomorrow(€-cent)
  show_states: false
graph_span: 36h
span:
  start: hour
yaxis:
  - decimals: 1
experimental:
  color_threshold: true
series:
  - entity: sensor.tibber_price_series
    transform: return x * 100;
    type: line
    curve: stepline
    extend_to: false
    stroke_width: 5
    data_generator: |
      return entity.attributes.timeseries.map((value, index) => {
        return [new Date(value).getTime(), 100 * entity.attributes.priceseries[index]];
      });
    color_threshold:
      - value: 30
        color: red
      - value: 25
        color: yellow
      - value: 20
        color: darkgreen

and the flow is here (scheduled every day at 13:15 as in Germany the update is on 13:00):

[{"id":"ac89eec644b66b2e","type":"ha-sensor","z":"7b21a369cedefa85","name":"Tibber Prices Time Series","entityConfig":"815231582d01f1bb","version":0,"state":"payload.status","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":1090,"y":158,"wires":[[]]},{"id":"82dd34b7e63dd046","type":"json","z":"7b21a369cedefa85","name":"","property":"payload.attributes","action":"obj","pretty":false,"x":904,"y":158,"wires":[["ac89eec644b66b2e"]]},{"id":"ff5842d205ad0e39","type":"inject","z":"7b21a369cedefa85","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"15 13 * * *","once":true,"onceDelay":"300","topic":"","payload":"","payloadType":"date","x":104,"y":86,"wires":[["05e9b1460206b41b"]]},{"id":"55a48a0776be8d1f","type":"http request","z":"7b21a369cedefa85","name":"","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://api.tibber.com/v1-beta/gql","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"bearer","senderr":false,"headers":[{"keyType":"other","keyValue":"Content-Type","valueType":"other","valueValue":"application/json; charset=utf-8"}],"credentials":{},"x":444,"y":86,"wires":[["f318d09f3f936614"]]},{"id":"f318d09f3f936614","type":"change","z":"7b21a369cedefa85","name":"Select price arrays","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.data.viewer.homes[0].currentSubscription.priceInfo","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":624,"y":86,"wires":[["f598e25f6df9363a","0c740a237787e3e9"]]},{"id":"f598e25f6df9363a","type":"change","z":"7b21a369cedefa85","name":"merge today, tomorrow","rules":[{"t":"set","p":"merged","pt":"msg","to":" $append($.payload.today, $.payload.tomorrow)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":852,"y":86,"wires":[["5a6f2365c28a9d85","2c9ec11c453528df"]]},{"id":"5a6f2365c28a9d85","type":"change","z":"7b21a369cedefa85","name":"reset payload status and attributes","rules":[{"t":"set","p":"attributes","pt":"msg","to":"{ \"timeseries\": $.merged.startsAt, \"priceseries\": $.merged.total } ","tot":"jsonata"},{"t":"delete","p":"payload","pt":"msg"},{"t":"set","p":"payload.status","pt":"msg","to":"$min($.merged.total)","tot":"jsonata"},{"t":"move","p":"attributes","pt":"msg","to":"payload.attributes","tot":"msg"},{"t":"set","p":"tibber_data","pt":"flow","to":"payload.attributes","tot":"msg","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":674,"y":158,"wires":[["82dd34b7e63dd046","09a3af0f0dce6909"]]},{"id":"c320d7b8ecf23ea0","type":"comment","z":"7b21a369cedefa85","name":"Read Me: Get tibber prices and prepare to be send to sensor","info":"# Result\nSensor with: \n- status: minimum price today, tomorrow\nand 2 attributes\n- timeseries: array of time points as text\n- priceseries: array of prices as dobule\n\n# Customization\nin http request you have to enter your token\n\n# trigger\ninject at 13:15 every day as at that time the price\nfor next day are available.\n\n# error handling\nnone\n\n","x":230,"y":40,"wires":[]},{"id":"e1d268a9ce9e454a","type":"comment","z":"7b21a369cedefa85","name":"! Modify","info":"Use your token from tibber developer portal","x":424,"y":117,"wires":[],"icon":"font-awesome/fa-arrow-up"},{"id":"0c740a237787e3e9","type":"debug","z":"7b21a369cedefa85","name":"original","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":634,"y":40,"wires":[]},{"id":"2c9ec11c453528df","type":"debug","z":"7b21a369cedefa85","name":"merged","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":854,"y":40,"wires":[]},{"id":"09a3af0f0dce6909","type":"debug","z":"7b21a369cedefa85","name":"split x array / y array","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":691,"y":199,"wires":[]},{"id":"05e9b1460206b41b","type":"change","z":"7b21a369cedefa85","name":"set query","rules":[{"t":"set","p":"payload","pt":"msg","to":"{     \"query\": \"{ viewer { homes { currentSubscription{ priceInfo{ today { total startsAt } tomorrow { total startsAt } } } } } }\" }","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":291,"y":86,"wires":[["55a48a0776be8d1f"]]},{"id":"815231582d01f1bb","type":"ha-entity-config","server":"32e490af.a728b","deviceConfig":"12b46ce419b8d466","name":"tibber_price_series","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"Tibber Price Series"},{"property":"icon","value":""},{"property":"entity_category","value":""},{"property":"entity_picture","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":"measurement"}],"resend":false,"debugEnabled":false},{"id":"32e490af.a728b","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30},{"id":"12b46ce419b8d466","type":"ha-device-config","name":"Tibber Prices","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""}]
1 Like

Thanks for the inspiration!
I have modified and simplified your solution a bit, mainly pertaining to the data_generator part.

With the REST sensor otherwise the same, modify the payload to the following:

payload: '{ "query": "{ viewer { homes { currentSubscription { priceInfo { current { total } today { total startsAt } tomorrow { total startsAt } } } } } }" }'

I have removed the status part as I didn’t care for that, and added startsAt to both today and tomorrow so that you get a UTC-offset date-time that we’ll use for the data_generator. An entry would look like this then:

- total: 0.2585
  startsAt: '2023-08-13T00:00:00.000+02:00'

The data_generator part can then be simplified to the following, removing the calculation based on the current date, and also using a slightly more descriptive map lambda instead of the for loop:

data_generator: >
  return [...entity.attributes.today,
  ...entity.attributes.tomorrow].map((price) => {
    return [new Date(price.startsAt), price.total * 100];
  });

This first creates a new array with the values of entity.attributes.today and entity.attributes.tomorrow. It then maps each entry of that new array to a new entry based on the startsAt attribute of the price entry, and the total multiplied by 100 to get Cents instead of Euros per kilowatt hour.

You could also use moment(price.startsAt) instead of new Date(price.startsAt) as Moment.js is automatically included by ApexCharts, but since “plain” JavaScript seems to yield the same result, I went for new Date(price.startsAt)

Honestly, I do not know how this chart behaves tomorrow when future prices are not (yet) available. I hope it’s somehow robust to paste those two arrays and loop over the length.

It is! I have used both your code and mine for a bit now and it works splendidly. If there’s no data for tomorrow, it will simply stop at the current day mark and add no info for the next day.

EDIT: Ah, now that I’ve tinkered with this myself I saw that further up, jonas21 already had a similar solution with only slightly different code. :sweat_smile:

1 Like