Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Stroomprijs for all Dutch providers #17464

Open
enboer opened this issue Nov 27, 2024 · 13 comments
Open

Add Stroomprijs for all Dutch providers #17464

enboer opened this issue Nov 27, 2024 · 13 comments
Labels
tariffs Specific tariff support

Comments

@enboer
Copy link

enboer commented Nov 27, 2024

Add another tariff provider

Ideally I would like to have the enever as a tarif supplier as you do not need support for every single provider. Together with their token you get all Dutch providers. Need to filter them on the the used supplier. I have add their abbreviations.
So as a setting, provide the token and the abbreviation of the supplier. Then EVCC can findout the tariffs.

Price Today
https://enever.nl/api/stroomprijs_vandaag.php?token=YOUR_TOKEN
Price tomorrow
https://enever.nl/api/stroomprijs_morgen.php?token=YOUR_TOKEN

These are the abbr. of the suppliers:

AA = Atoom Alliantie
AIP = All in power
ANWB = ANWB Energie
BE = Budget Energie
EE = EasyEnergy
EN = Eneco
EVO = Energie van Ons
EZ = Energy Zero
FR = Frank Energie
GSL = Groenestroom Lokaal
MDE = Mijndomein Energie
NE = NextEnergy
TI = Tibber
VDB = Vandebron
VON = Vrij op naam
WE = Wout Energie
ZG = ZonderGas
ZP = Zonneplan

This is what you get, for every hour, and the supplier, prijsAA means Atoom Alliantie.

{"status":"true","data":[{"datum":"2024-11-28 00:00:00","prijs":"0.050100","prijsAA":"0.213471","prijsAIP":"0.222521","prijsANWB":"0.240671","prijsBE":"0.213261","prijsEE":"0.219121","prijsEN":"0.215661","prijsEVO":"0.240671","prijsEZ":"0.242271","prijsFR":"0.210471","prijsGSL":"0.240671","prijsMDE":"0.240671","prijsNE":"0.212171","prijsTI":"0.214051","prijsVDB":"0.214151","prijsVON":"0.212271","prijsWE":"0.217671","prijsZG":"0.240671","prijsZP":"0.212271"},{"datum":"2024-11-28 01:00:00","prijs":"0.041210","prijsAA":"0.202714","prijsAIP":"0.211764","prijsANWB":"0.229914","prijsBE":"0.202504","prijsEE":"0.208364","prijsEN":"0.204904","prijsEVO":"0.229914","prijsEZ":"0.231514","prijsFR":"0.199714","prijsGSL":"0.229914","prijsMDE":"0.229914","prijsNE":"0.201414","prijsTI":"0.203294","prijsVDB":"0.203394","prijsVON":"0.201514","prijsWE":"0.206914","prijsZG":"0.229914","prijsZP":"0.201514"},{"datum":"2024-11-28 02:00:00","prijs":"0.035130","prijsAA":"0.195357","prijsAIP":"0.204407","prijsANWB":"0.222557","prijsBE":"0.195147","prijsEE":"0.201007","prijsEN":"0.197547","prijsEVO":"0.222557","prijsEZ":"0.224157","prijsFR":"0.192357","prijsGSL":"0.222557","prijsMDE":"0.222557","prijsNE":"0.194057","prijsTI":"0.195937","prijsVDB":"0.196037","prijsVON":"0.194157","prijsWE":"0.199557","prijsZG":"0.222557","prijsZP":"0.194157"},{"datum":"2024-11-28 03:00:00","prijs":"0.038000","prijsAA":"0.198830","prijsAIP":"0.207880","prijsANWB":"0.226030","prijsBE":"0.198620","prijsEE":"0.204480","prijsEN":"0.201020","prijsEVO":"0.226030","prijsEZ":"0.227630","prijsFR":"0.195830","prijsGSL":"0.226030","prijsMDE":"0.226030","prijsNE":"0.197530","prijsTI":"0.199410","prijsVDB":"0.199510","prijsVON":"0.197630","prijsWE":"0.203030","prijsZG":"0.226030","prijsZP":"0.197630"},{"datum":"2024-11-28 04:00:00","prijs":"0.059900","prijsAA":"0.225329","prijsAIP":"0.234379","prijsANWB":"0.252529","prijsBE":"0.225119","prijsEE":"0.230979","prijsEN":"0.227519","prijsEVO":"0.252529","prijsEZ":"0.254129","prijsFR":"0.222329","prijsGSL":"0.252529","prijsMDE":"0.252529","prijsNE":"0.224029","prijsTI":"0.225909","prijsVDB":"0.226009","prijsVON":"0.224129","prijsWE":"0.229529","prijsZG":"0.252529","prijsZP":"0.224129"},{"datum":"2024-11-28 05:00:00","prijs":"0.092040","prijsAA":"0.264218","prijsAIP":"0.273268","prijsANWB":"0.291418","prijsBE":"0.264008","prijsEE":"0.269868","prijsEN":"0.266408","prijsEVO":"0.291418","prijsEZ":"0.293018","prijsFR":"0.261218","prijsGSL":"0.291418","prijsMDE":"0.291418","prijsNE":"0.262918","prijsTI":"0.264798","prijsVDB":"0.264898","prijsVON":"0.263018","prijsWE":"0.268418","prijsZG":"0.291418","prijsZP":"0.263018"},{"datum":"2024-11-28 06:00:00","prijs":"0.100100","prijsAA":"0.273971","prijsAIP":"0.283021","prijsANWB":"0.301171","prijsBE":"0.273761","prijsEE":"0.279621","prijsEN":"0.276161","prijsEVO":"0.301171","prijsEZ":"0.302771","prijsFR":"0.270971","prijsGSL":"0.301171","prijsMDE":"0.301171","prijsNE":"0.272671","prijsTI":"0.274551","prijsVDB":"0.274651","prijsVON":"0.272771","prijsWE":"0.278171","prijsZG":"0.301171","prijsZP":"0.272771"},{"datum":"2024-11-28 07:00:00","prijs":"0.132100","prijsAA":"0.312691","prijsAIP":"0.321741","prijsANWB":"0.339891","prijsBE":"0.312481","prijsEE":"0.318341","prijsEN":"0.314881","prijsEVO":"0.339891","prijsEZ":"0.341491","prijsFR":"0.309691","prijsGSL":"0.339891","prijsMDE":"0.339891","prijsNE":"0.311391","prijsTI":"0.313271","prijsVDB":"0.313371","prijsVON":"0.311491","prijsWE":"0.316891","prijsZG":"0.339891","prijsZP":"0.311491"},{"datum":"2024-11-28 08:00:00","prijs":"0.148290","prijsAA":"0.332281","prijsAIP":"0.341331","prijsANWB":"0.359481","prijsBE":"0.332071","prijsEE":"0.337931","prijsEN":"0.334471","prijsEVO":"0.359481","prijsEZ":"0.361081","prijsFR":"0.329281","prijsGSL":"0.359481","prijsMDE":"0.359481","prijsNE":"0.330981","prijsTI":"0.332861","prijsVDB":"0.332961","prijsVON":"0.331081","prijsWE":"0.336481","prijsZG":"0.359481","prijsZP":"0.331081"},{"datum":"2024-11-28 09:00:00","prijs":"0.140360","prijsAA":"0.322686","prijsAIP":"0.331736","prijsANWB":"0.349886","prijsBE":"0.322476","prijsEE":"0.328336","prijsEN":"0.324876","prijsEVO":"0.349886","prijsEZ":"0.351486","prijsFR":"0.319686","prijsGSL":"0.349886","prijsMDE":"0.349886","prijsNE":"0.321386","prijsTI":"0.323266","prijsVDB":"0.323366","prijsVON":"0.321486","prijsWE":"0.326886","prijsZG":"0.349886","prijsZP":"0.321486"},{"datum":"2024-11-28 10:00:00","prijs":"0.099010","prijsAA":"0.272652","prijsAIP":"0.281702","prijsANWB":"0.299852","prijsBE":"0.272442","prijsEE":"0.278302","prijsEN":"0.274842","prijsEVO":"0.299852","prijsEZ":"0.301452","prijsFR":"0.269652","prijsGSL":"0.299852","prijsMDE":"0.299852","prijsNE":"0.271352","prijsTI":"0.273232","prijsVDB":"0.273332","prijsVON":"0.271452","prijsWE":"0.276852","prijsZG":"0.299852","prijsZP":"0.271452"},{"datum":"2024-11-28 11:00:00","prijs":"0.098700","prijsAA":"0.272277","prijsAIP":"0.281327","prijsANWB":"0.299477","prijsBE":"0.272067","prijsEE":"0.277927","prijsEN":"0.274467","prijsEVO":"0.299477","prijsEZ":"0.301077","prijsFR":"0.269277","prijsGSL":"0.299477","prijsMDE":"0.299477","prijsNE":"0.270977","prijsTI":"0.272857","prijsVDB":"0.272957","prijsVON":"0.271077","prijsWE":"0.276477","prijsZG":"0.299477","prijsZP":"0.271077"},{"datum":"2024-11-28 12:00:00","prijs":"0.096160","prijsAA":"0.269204","prijsAIP":"0.278254","prijsANWB":"0.296404","prijsBE":"0.268994","prijsEE":"0.274854","prijsEN":"0.271394","prijsEVO":"0.296404","prijsEZ":"0.298004","prijsFR":"0.266204","prijsGSL":"0.296404","prijsMDE":"0.296404","prijsNE":"0.267904","prijsTI":"0.269784","prijsVDB":"0.269884","prijsVON":"0.268004","prijsWE":"0.273404","prijsZG":"0.296404","prijsZP":"0.268004"},{"datum":"2024-11-28 13:00:00","prijs":"0.098990","prijsAA":"0.272628","prijsAIP":"0.281678","prijsANWB":"0.299828","prijsBE":"0.272418","prijsEE":"0.278278","prijsEN":"0.274818","prijsEVO":"0.299828","prijsEZ":"0.301428","prijsFR":"0.269628","prijsGSL":"0.299828","prijsMDE":"0.299828","prijsNE":"0.271328","prijsTI":"0.273208","prijsVDB":"0.273308","prijsVON":"0.271428","prijsWE":"0.276828","prijsZG":"0.299828","prijsZP":"0.271428"},{"datum":"2024-11-28 14:00:00","prijs":"0.114400","prijsAA":"0.291274","prijsAIP":"0.300324","prijsANWB":"0.318474","prijsBE":"0.291064","prijsEE":"0.296924","prijsEN":"0.293464","prijsEVO":"0.318474","prijsEZ":"0.320074","prijsFR":"0.288274","prijsGSL":"0.318474","prijsMDE":"0.318474","prijsNE":"0.289974","prijsTI":"0.291854","prijsVDB":"0.291954","prijsVON":"0.290074","prijsWE":"0.295474","prijsZG":"0.318474","prijsZP":"0.290074"},{"datum":"2024-11-28 15:00:00","prijs":"0.118800","prijsAA":"0.296598","prijsAIP":"0.305648","prijsANWB":"0.323798","prijsBE":"0.296388","prijsEE":"0.302248","prijsEN":"0.298788","prijsEVO":"0.323798","prijsEZ":"0.325398","prijsFR":"0.293598","prijsGSL":"0.323798","prijsMDE":"0.323798","prijsNE":"0.295298","prijsTI":"0.297178","prijsVDB":"0.297278","prijsVON":"0.295398","prijsWE":"0.300798","prijsZG":"0.323798","prijsZP":"0.295398"},{"datum":"2024-11-28 16:00:00","prijs":"0.133930","prijsAA":"0.314905","prijsAIP":"0.323955","prijsANWB":"0.342105","prijsBE":"0.314695","prijsEE":"0.320555","prijsEN":"0.317095","prijsEVO":"0.342105","prijsEZ":"0.343705","prijsFR":"0.311905","prijsGSL":"0.342105","prijsMDE":"0.342105","prijsNE":"0.313605","prijsTI":"0.315485","prijsVDB":"0.315585","prijsVON":"0.313705","prijsWE":"0.319105","prijsZG":"0.342105","prijsZP":"0.313705"},{"datum":"2024-11-28 17:00:00","prijs":"0.151000","prijsAA":"0.335560","prijsAIP":"0.344610","prijsANWB":"0.362760","prijsBE":"0.335350","prijsEE":"0.341210","prijsEN":"0.337750","prijsEVO":"0.362760","prijsEZ":"0.364360","prijsFR":"0.332560","prijsGSL":"0.362760","prijsMDE":"0.362760","prijsNE":"0.334260","prijsTI":"0.336140","prijsVDB":"0.336240","prijsVON":"0.334360","prijsWE":"0.339760","prijsZG":"0.362760","prijsZP":"0.334360"},{"datum":"2024-11-28 18:00:00","prijs":"0.158240","prijsAA":"0.344320","prijsAIP":"0.353370","prijsANWB":"0.371520","prijsBE":"0.344110","prijsEE":"0.349970","prijsEN":"0.346510","prijsEVO":"0.371520","prijsEZ":"0.373120","prijsFR":"0.341320","prijsGSL":"0.371520","prijsMDE":"0.371520","prijsNE":"0.343020","prijsTI":"0.344900","prijsVDB":"0.345000","prijsVON":"0.343120","prijsWE":"0.348520","prijsZG":"0.371520","prijsZP":"0.343120"},{"datum":"2024-11-28 19:00:00","prijs":"0.154040","prijsAA":"0.339238","prijsAIP":"0.348288","prijsANWB":"0.366438","prijsBE":"0.339028","prijsEE":"0.344888","prijsEN":"0.341428","prijsEVO":"0.366438","prijsEZ":"0.368038","prijsFR":"0.336238","prijsGSL":"0.366438","prijsMDE":"0.366438","prijsNE":"0.337938","prijsTI":"0.339818","prijsVDB":"0.339918","prijsVON":"0.338038","prijsWE":"0.343438","prijsZG":"0.366438","prijsZP":"0.338038"},{"datum":"2024-11-28 20:00:00","prijs":"0.143390","prijsAA":"0.326352","prijsAIP":"0.335402","prijsANWB":"0.353552","prijsBE":"0.326142","prijsEE":"0.332002","prijsEN":"0.328542","prijsEVO":"0.353552","prijsEZ":"0.355152","prijsFR":"0.323352","prijsGSL":"0.353552","prijsMDE":"0.353552","prijsNE":"0.325052","prijsTI":"0.326932","prijsVDB":"0.327032","prijsVON":"0.325152","prijsWE":"0.330552","prijsZG":"0.353552","prijsZP":"0.325152"},{"datum":"2024-11-28 21:00:00","prijs":"0.131260","prijsAA":"0.311675","prijsAIP":"0.320725","prijsANWB":"0.338875","prijsBE":"0.311465","prijsEE":"0.317325","prijsEN":"0.313865","prijsEVO":"0.338875","prijsEZ":"0.340475","prijsFR":"0.308675","prijsGSL":"0.338875","prijsMDE":"0.338875","prijsNE":"0.310375","prijsTI":"0.312255","prijsVDB":"0.312355","prijsVON":"0.310475","prijsWE":"0.315875","prijsZG":"0.338875","prijsZP":"0.310475"},{"datum":"2024-11-28 22:00:00","prijs":"0.122160","prijsAA":"0.300664","prijsAIP":"0.309714","prijsANWB":"0.327864","prijsBE":"0.300454","prijsEE":"0.306314","prijsEN":"0.302854","prijsEVO":"0.327864","prijsEZ":"0.329464","prijsFR":"0.297664","prijsGSL":"0.327864","prijsMDE":"0.327864","prijsNE":"0.299364","prijsTI":"0.301244","prijsVDB":"0.301344","prijsVON":"0.299464","prijsWE":"0.304864","prijsZG":"0.327864","prijsZP":"0.299464"},{"datum":"2024-11-28 23:00:00","prijs":"0.112600","prijsAA":"0.289096","prijsAIP":"0.298146","prijsANWB":"0.316296","prijsBE":"0.288886","prijsEE":"0.294746","prijsEN":"0.291286","prijsEVO":"0.316296","prijsEZ":"0.317896","prijsFR":"0.286096","prijsGSL":"0.316296","prijsMDE":"0.316296","prijsNE":"0.287796","prijsTI":"0.289676","prijsVDB":"0.289776","prijsVON":"0.287896","prijsWE":"0.293296","prijsZG":"0.316296","prijsZP":"0.287896"}],"code":"5"}

@andig
Copy link
Member

andig commented Nov 27, 2024

Happy to take a pr

@andig andig added the tariffs Specific tariff support label Nov 27, 2024
@enboer

This comment was marked as resolved.

@andig andig changed the title tariffs add Add Stroomprijs for all Dutch providers Nov 29, 2024
@andig
Copy link
Member

andig commented Nov 29, 2024

How does one signup for the API? Is there a cost?

@tomjschwanke
Copy link
Contributor

seems to only require an email and is limited to private use: https://enever.nl/prijzenfeeds/

@andig
Copy link
Member

andig commented Nov 29, 2024

Sehr cool. Wer möchte es versuchen? Es wäre sinnig, das als N Templates je eins pro Provider zu machen.

@andig
Copy link
Member

andig commented Nov 29, 2024

I can‘t get data for tomorrow- code 5?

❯ curl https://enever.nl/api/stroomprijs_morgen.php\?token\=2a8e1f19aa60076ea75f00ad94ad569f
{"status":"true","data":[],"code":"5"}%    

@enboer
Copy link
Author

enboer commented Nov 29, 2024 via email

@andig
Copy link
Member

andig commented Nov 30, 2024

The jq part here looks straight forward. I think we'll need to find something that does two HTTP requests. I'll see if we can use #17481 for this purpose.

@andig

This comment was marked as resolved.

@andig
Copy link
Member

andig commented Dec 1, 2024

Timezone issue resolved thanks to https://stackoverflow.com/questions/79241351/use-jq-to-parse-local-time-into-golang-rfc-3339/79241515#79241515:

tariffs:
  grid:
    type: custom
    forecast:
      source: go
      init: |
        import (
          "fmt"
          "strings"
        )
      script: |
        // concat today and tomorrow
        "[" + strings.Trim(strings.Trim(today, "[]") + "," + strings.Trim(tomorrow, "[]"), ",") + "]"
      in:
        - name: today
          type: string
          config:
            source: http
            uri: https://enever.nl/api/stroomprijs_vandaag.php?token=<token>
            jq: |
              .data | 
              [
                .[] | 
                { 
                  "start": (.datum | strptime("%F %T") | strflocaltime("%FT%T%:z")),
                  "end":   (.datum | strptime("%F %T") | mktime + 3600 | strflocaltime("%FT%T%:z")),
                  "price": (.prijs | tonumber)
                }
              ] | tostring
        - name: tomorrow
          type: string
          config:
            source: http
            uri: https://enever.nl/api/stroomprijs_morgen.php?token=<token>
            jq: |
              .data |
              [
                .[] |
                {
                  "start": (.datum | strptime("%F %T") | strflocaltime("%FT%T%:z")),
                  "end":   (.datum | strptime("%F %T") | mktime + 3600 | strflocaltime("%FT%T%:z")),
                  "price": (.prijs | tonumber)
                }
              ] | tostring

@wgentine
Copy link

wgentine commented Dec 1, 2024

Timezone issue resolved thanks to https://stackoverflow.com/questions/79241351/use-jq-to-parse-local-time-into-golang-rfc-3339/79241515#79241515:

tariffs:
  grid:
    type: custom
    forecast:
      source: go
      script: |
        // concat today and tomorrow
        "[" + strings.Trim(strings.Trim(today, "[]") + "," + strings.Trim(tomorrow, "[]"), ",") + "]"
      in:
        - name: today
          type: string
          config:
            source: http
            uri: https://enever.nl/api/stroomprijs_vandaag.php?token=<token>
            jq: |
              .data | 
              [
                .[] | 
                { 
                  "start": (.datum | strptime("%F %T") | strflocaltime("%FT%T%:z")),
                  "end":   (.datum | strptime("%F %T") | mktime + 3600 | strflocaltime("%FT%T%:z")),
                  "price": (.prijs | tonumber)
                }
              ] | tostring
        - name: tomorrow
          type: string
          config:
            source: http
            uri: https://enever.nl/api/stroomprijs_morgen.php?token=<token>
            jq: |
              .data |
              [
                .[] |
                {
                  "start": (.datum | strptime("%F %T") | strflocaltime("%FT%T%:z")),
                  "end":   (.datum | strptime("%F %T") | mktime + 3600 | strflocaltime("%FT%T%:z")),
                  "price": (.prijs | tonumber)
                }
              ] | tostring

Looks awesome, but I get this issue with your config:
[main ] FATAL 2024/12/01 20:24:19 cannot create tariff type 'custom': forecast: decoding failed due to the following error(s):
'' has invalid keys: init

@andig
Copy link
Member

andig commented Dec 1, 2024

Yes, still waiting for another pointer from https://stackoverflow.com/questions/79242253/how-to-use-import-and-return-a-value-in-the-same-eval or traefik/yaegi#1670

@wgentine
Copy link

wgentine commented Dec 2, 2024

Yes, still waiting for another pointer from https://stackoverflow.com/questions/79242253/how-to-use-import-and-return-a-value-in-the-same-eval or traefik/yaegi#1670

Cool! I know nothing about go and have no idea how to integrate with evcc. However, I managed to create a python script with flask that query both APIs every 3 hours (to avoid limit rating) and cache the responses so evcc can call as many times as it wants. Then I created a container and run it there.

I query the python "server"this way, filtering by frankenergie prices only:

tariffs: grid: type: custom forecast: source: http uri: http://192.168.37.12:5000/prices jq: '[.data[] | { "start": ( .datum | strptime("%Y-%m-%d %H:%M:%S") | strftime("%Y-%m-%dT%H:%M:%SZ")), "end": ( .datum | strptime("%Y-%m-%d %H:%M:%S") | mktime + 3600 | strftime("%Y-%m-%dT%H:%M:%SZ")), "price": (.prijsFR | tonumber) }] | tostring'

and the python script here:

`
from flask import Flask, jsonify
import requests
import os
import time

app = Flask(name)

Cache structure

cache = {
'data': None, # To hold the combined data from today and tomorrow
'last_updated': 0, # Timestamp of the last API call
'cache_duration': 60 * 60 * 3 # Cache duration of 3 hours (in seconds)
}

def fetch_and_cache_prices():
"""
Fetches prices from the upstream APIs and caches them.
"""
token = os.getenv('ENERGY_API_TOKEN')
if not token:
return {"error": "API token not provided"}, 400

today_url = f"https://enever.nl/api/stroomprijs_vandaag.php?token={token}"
tomorrow_url = f"https://enever.nl/api/stroomprijs_morgen.php?token={token}"

try:
    # Fetch the data from the upstream URLs
    today_response = requests.get(today_url)
    today_data = today_response.json()

    # Check for error in the API response
    if not today_response.ok or today_data.get("status") != "true":
        return {"error": "Failed to fetch today's prices", "details": today_data}, 502

    tomorrow_response = requests.get(tomorrow_url)
    tomorrow_data = tomorrow_response.json()

    # Check for error in the API response
    if not tomorrow_response.ok or tomorrow_data.get("status") != "true":
        return {"error": "Failed to fetch tomorrow's prices", "details": tomorrow_data}, 502

    # Combine today's and tomorrow's prices
    combined_prices = today_data['data'] + tomorrow_data['data']
    
    # Cache the combined data and update the timestamp
    cache['data'] = combined_prices
    cache['last_updated'] = time.time()  # Update the last updated time to current time
    return combined_prices
except requests.exceptions.RequestException as e:
    return {"error": "An error occurred while fetching data", "details": str(e)}, 500

@app.route('/prices', methods=['GET'])
def get_prices():
"""
Endpoint to get the combined prices, using cached data if available.
"""
current_time = time.time()

# Check if cache is still valid (within the 3-hour window)
if cache['data'] is None or (current_time - cache['last_updated'] > cache['cache_duration']):
    # Cache expired or no data, so fetch new data
    new_data = fetch_and_cache_prices()
    if isinstance(new_data, tuple):  # Check if there's an error response
        return jsonify(new_data[0]), new_data[1]  # Return error response
    return jsonify({"status": "true", "data": new_data, "code": "5"})

# Return cached data if still valid
return jsonify({"status": "true", "data": cache['data'], "code": "5"})

if name == "main":
app.run(host='0.0.0.0', port=5000)`

Not a super elegant solution but it does work and solves the rate limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tariffs Specific tariff support
Projects
None yet
Development

No branches or pull requests

4 participants