[GH-ISSUE #559] Dayahead prices broken since ~March 9, 2026: ENTSO-E security token revoked + Google Apps Script quota exceeded #2567

Open
opened 2026-03-20 21:07:39 +01:00 by sascha_hemi · 2 comments
Owner

Originally created by @g0llem on GitHub (Mar 10, 2026).
Original GitHub issue: https://github.com/OpenEPaperLink/OpenEPaperLink/issues/559

Originally assigned to: @nlimper on GitHub.

Since approximately March 9, 2026, Dayahead prices (contentMode 27) no longer update on any Access Point. The AP log shows:

getDayAhead http error -11
get dayahead prices

Two independent investigations have confirmed two related root causes.

Root Cause 1: ENTSO-E security token revoked
The Google Apps Script (miscellaneous/dayahead content type/get_dayahead.js, line 51) contains a hardcoded ENTSO-E security token:

securityToken=57ba8658-37a5-4e23-9bee-e60fc3f954db

This token has been revoked. Querying the ENTSO-E API directly returns:

<Acknowledgement_MarketDocument>

999
Authentication failed.

</Acknowledgement_MarketDocument>

Root Cause 2: Google Apps Script UrlFetch quota exceeded
Because every API call fails, the script never caches a valid response. All APs worldwide keep retrying, exhausting the daily UrlFetch quota:

Exception: Service invoked too many times for one day: urlfetch. (line 60, file "Code")

The failure chain
Token revoked
→ ENTSO-E returns "Authentication failed" (code 999)
→ No error handling on UrlFetchApp.fetch() (line 60)
→ Failed response not cached → every AP retries
→ Daily UrlFetch quota exceeded
→ ESP32: "getDayAhead http error -11"

Affected code
Google Apps Script (miscellaneous/dayahead content type/get_dayahead.js):

Line 51: Hardcoded ENTSO-E URL with revoked security token
Line 60: UrlFetchApp.fetch(xmlUrl) — no try/catch
ESP32 firmware (ESP32_AP-Flasher/src/contentmanager.cpp):

Line 1959-1961: Hardcoded Google Apps Script URL
Line 1966-1974: HTTP call with no caching, fallback, or backoff
Proposed fixes
Short term:

Request a new ENTSO-E security token and redeploy the Google Apps Script
Add try/catch around UrlFetchApp.fetch() on line 60
Long term:

Add a user-configurable ENTSO-E API token field to the web interface (tokens are free: https://transparency.entsoe.eu/)
AP-side caching of last-known-good prices in LittleFS
Exponential backoff after repeated failures
Better error handling in firmware (distinguish timeout vs auth vs quota errors)
Environment
Firmware: 33025 (v2.85)
Hardware: ESP32-S3, hwType 179
Country: NL
Weather (contentMode 4) works fine on the same AP
Related issues
#517, #514, #525, #452

Originally created by @g0llem on GitHub (Mar 10, 2026). Original GitHub issue: https://github.com/OpenEPaperLink/OpenEPaperLink/issues/559 Originally assigned to: @nlimper on GitHub. Since approximately March 9, 2026, Dayahead prices (contentMode 27) no longer update on any Access Point. The AP log shows: getDayAhead http error -11 get dayahead prices Two independent investigations have confirmed two related root causes. Root Cause 1: ENTSO-E security token revoked The Google Apps Script (miscellaneous/dayahead content type/get_dayahead.js, line 51) contains a hardcoded ENTSO-E security token: securityToken=57ba8658-37a5-4e23-9bee-e60fc3f954db This token has been revoked. Querying the ENTSO-E API directly returns: <Acknowledgement_MarketDocument> <Reason> <code>999</code> <text>Authentication failed.</text> </Reason> </Acknowledgement_MarketDocument> Root Cause 2: Google Apps Script UrlFetch quota exceeded Because every API call fails, the script never caches a valid response. All APs worldwide keep retrying, exhausting the daily UrlFetch quota: Exception: Service invoked too many times for one day: urlfetch. (line 60, file "Code") The failure chain Token revoked → ENTSO-E returns "Authentication failed" (code 999) → No error handling on UrlFetchApp.fetch() (line 60) → Failed response not cached → every AP retries → Daily UrlFetch quota exceeded → ESP32: "getDayAhead http error -11" Affected code Google Apps Script (miscellaneous/dayahead content type/get_dayahead.js): Line 51: Hardcoded ENTSO-E URL with revoked security token Line 60: UrlFetchApp.fetch(xmlUrl) — no try/catch ESP32 firmware (ESP32_AP-Flasher/src/contentmanager.cpp): Line 1959-1961: Hardcoded Google Apps Script URL Line 1966-1974: HTTP call with no caching, fallback, or backoff Proposed fixes Short term: Request a new ENTSO-E security token and redeploy the Google Apps Script Add try/catch around UrlFetchApp.fetch() on line 60 Long term: Add a user-configurable ENTSO-E API token field to the web interface (tokens are free: https://transparency.entsoe.eu/) AP-side caching of last-known-good prices in LittleFS Exponential backoff after repeated failures Better error handling in firmware (distinguish timeout vs auth vs quota errors) Environment Firmware: 33025 (v2.85) Hardware: ESP32-S3, hwType 179 Country: NL Weather (contentMode 4) works fine on the same AP Related issues #517, #514, #525, #452
sascha_hemi added the bug label 2026-03-20 21:07:39 +01:00
Author
Owner

@g0llem commented on GitHub (Mar 10, 2026):

Proposed fix: Direct ENTSO-E API access (bypass Google Apps Script)

The root cause is that the Google Apps Script proxy uses a hardcoded ENTSO-E security token (57ba8...54db in get_dayahead.js:51) which appears to have been revoked/rate-limited. All users share this single token.

Proposed solution: Let the ESP32 call the ENTSO-E API directly with a user-provided token. Changes in 2 files:

1. content_cards.json — Add token field to UI

Add a new parameter to content type 27:

{
"key": "entsoe_token",
"name": "ENTSO-E API token",
"desc": "Your personal ENTSO-E security token (free). Register at transparency.entsoe.eu, then email transparency@entsoe.eu to request API access.",
"type": "text"
}

2. contentmanager.cpp — Direct API call + XML parsing

  • Add country→domain mapping table (AT→10YAT-APG------L, NL→10YNL----------L, etc.)
  • If entsoe_token is set: build ENTSO-E API URL directly, parse XML response on ESP32
  • If no token: fall back to existing Google Apps Script (backward compatible)
  • Add exponential backoff on failures (5→10→20→30 min) instead of fixed 5-min retry
  • Better error messages (auth failure vs connection error)

How to get a token (free)

  1. Register at https://transparency.entsoe.eu
  2. Email transparency@entsoe.eu with subject "RESTful API access"
  3. After approval (1-3 days), generate token in account settings

I have a full patch with the implementation details available. Happy to submit a PR if there's interest.

<!-- gh-comment-id:4030703510 --> @g0llem commented on GitHub (Mar 10, 2026): ### Proposed fix: Direct ENTSO-E API access (bypass Google Apps Script) The root cause is that the Google Apps Script proxy uses a hardcoded ENTSO-E security token (`57ba8...54db` in `get_dayahead.js:51`) which appears to have been revoked/rate-limited. All users share this single token. **Proposed solution:** Let the ESP32 call the ENTSO-E API directly with a user-provided token. Changes in 2 files: #### 1. `content_cards.json` — Add token field to UI Add a new parameter to content type 27: { "key": "entsoe_token", "name": "ENTSO-E API token", "desc": "Your personal ENTSO-E security token (free). Register at transparency.entsoe.eu, then email transparency@entsoe.eu to request API access.", "type": "text" } #### 2. `contentmanager.cpp` — Direct API call + XML parsing - Add country→domain mapping table (AT→10YAT-APG------L, NL→10YNL----------L, etc.) - If entsoe_token is set: build ENTSO-E API URL directly, parse XML response on ESP32 - If no token: fall back to existing Google Apps Script (backward compatible) - Add exponential backoff on failures (5→10→20→30 min) instead of fixed 5-min retry - Better error messages (auth failure vs connection error) #### How to get a token (free) 1. Register at https://transparency.entsoe.eu 2. Email transparency@entsoe.eu with subject "RESTful API access" 3. After approval (1-3 days), generate token in account settings I have a full patch with the implementation details available. Happy to submit a PR if there's interest.
Author
Owner

@nlimper commented on GitHub (Mar 18, 2026):

I used that single token to prevent people having to apply for their own token. The script is heavily cached, so the API call only happens maximum once per hour per region. But probably somebody started reusing the token (I think I should have masked it...).
At some point I can apply for a new token, but currently I don't have to time to quickly fix it.

<!-- gh-comment-id:4081729281 --> @nlimper commented on GitHub (Mar 18, 2026): I used that single token to prevent people having to apply for their own token. The script is heavily cached, so the API call only happens maximum once per hour per region. But probably somebody started reusing the token (I think I should have masked it...). At some point I can apply for a new token, but currently I don't have to time to quickly fix it.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/OpenEPaperLink#2567