node-red-contrib-norbico 0.3.2

Node-RED nodes for Danish utility APIs: Eloverblik (electricity) and Aalborg Forsyning (district heating). Per-meter outputs, encrypted credentials, MQTT runtime control, automatic retry, and CSV payloads ready for downstream systems like Niagara.

npm install node-red-contrib-norbico

node-red-contrib-norbico

Node-RED nodes for Danish utility APIs. Both nodes fetch consumption data on a schedule, publish one MQTT message per meter, and emit CSV payloads designed to be split directly in Niagara or any other downstream system.

Node API Data
Eloverblik api.eloverblik.dk Electricity consumption
Aalborg Forsyning services.aalborgforsyning.dk District heating & water

Both appear under the Norbico category in the palette.

Install

cd ~/.node-red
npm install node-red-contrib-norbico

Or use the palette manager: Install tab → search norbico.

Requirements: Node-RED 2.0+, Node.js 14+, and credentials for whichever API you're using.


Quick start

  1. Drag an Eloverblik node onto the canvas.
  2. Set Topic prefix to identify the site, e.g. <prefix>/Eloverblik. Everything the node publishes and listens to is built from this — see Topic prefix below.
  3. Paste your refresh token from eloverblik.dkDatadelingDatatilgangs-token.
  4. Add your metering point IDs under Meters. One output appears per meter.
  5. Pick a Resolution and Range, set a Schedule if you want it to run daily, and wire each output to an MQTT out node.
  6. Deploy, then right-click the node → Force update (or send any message to its input) to test.

Topic prefix

The prefix is the single most important field. Both nodes derive every topic from it, with no automatic naming:

<prefix>/Consumption/<meterID>            ← data out
<prefix>/Configuration/Token              ← config in
<prefix>/Configuration/MeterIDs
<prefix>/Configuration/ForceUpdate
<prefix>/Configuration/ClearMeterCache

The default values are Eloverblik and AalborgForsyning, but these are just placeholder text — the node does not append its own name. If you type <prefix>, your topics become <prefix>/Consumption/..., not <prefix>/Eloverblik/Consumption/....

When running one Node-RED for several sites, include both the site and the utility so the two nodes don't collide:

<prefix>/Eloverblik
<prefix>/AalborgForsyning
<prefix>/Eloverblik
<prefix>/AalborgForsyning

If the node shows "no token" while your Configuration MQTT-in nodes show connected, the prefix doesn't match what those nodes are subscribed to. That mismatch is the most common setup problem.


⚠️ Metering point IDs and MQTT-in nodes

Danish metering point IDs are 18-digit GSRN numbers. They exceed JavaScript's exact-integer limit (2^53), so any numeric conversion silently corrupts them:

Number("571313105200435440").toString()   // "571313105200435460"

MQTT carries payloads as bytes, so the broker holds the ID correctly. The damage happens in Node-RED if the MQTT-in node parses it as JSON — a bare 18-digit number is valid JSON.

Set the Output of any MQTT-in node feeding MeterIDs to "a String".

Not auto-detect, not a parsed JSON object. Note that a comma-separated list of several IDs isn't valid JSON and survives auto-detect intact, so this bug only shows up with a single meter — which makes it easy to miss.

Since 0.2.2 the Eloverblik node defends itself: it rejects numeric payloads outright, validates the GS1 check digit, keeps the previous meter list rather than caching a corrupted one, and tells you which setting to change. The Aalborg node has no such validation, so set its MQTT-in nodes to string too.


Eloverblik

Fetches electricity consumption time series from Energinet's customer API.

Configuration:

Field Notes
Refresh token Encrypted at rest, roughly 1 year validity
Resolution Actual / Quarter / Hour / Day / Month / Year
Range Presets (yesterday, last 7 days, last full month, …) or custom dates
Meters One output per meter, in dialog order
Output topic Stable (default) or Timestamped — see below
Schedule Optional HH:MM daily run
Retry Attempts, initial delay, backoff multiplier

Output topic

Stable (default, since 0.3.0) publishes one message per meter per fetch to a fixed topic:

SiteNameHere/Eloverblik/Consumption/571313105200435440

The topic never changes — not between fetches, and not when you change Resolution or Range. That's what a fixed-topic subscriber like Niagara needs. The resolution travels in field 6 of the payload instead.

A single fetch can return many periods (three months for last full month, ~720 for Hour over 30 days). The node sorts them chronologically — the API does not return them in order — publishes the most recent one, and summarises the rest in the appended fields.

Timestamped is the pre-0.3.0 behaviour: one message per period, with the period start appended to the topic. Use it if you want the broker to hold the history as separate retained records. Note the topic moves on every fetch, so subscribers need a wildcard.

Payload (CSV, 16 fields)

571313105200435440,2026-08-01T00:00:00,2372.660,2026-07-01T00:00:00,2026-08-01T00:00:00,Month,1,A04,KWH,Input,1,2372.660,2026-07-01,2026-08-01,,0
# Field Notes
1 Metering point ID 18-digit GSRN
2 Timestamp Representative time = period end, local
3 Value Latest period, 3 decimals
4 Period start Local
5 Period end Local — same as field 2 by definition
6 Resolution Month, Hour, …
7 Position Point index within the period
8 Quality See codes below
9 Unit Usually KWH
10 Trigger Input, Schedule, Retry, …
11 Period count Periods returned for this meter
12 Range total Sum of all periods in the range
13 Date from Query start, YYYY-MM-DD
14 Date to Query end, YYYY-MM-DD
15 Previous value Period before the latest — empty if only one period
16 Non-measured count Periods where quality ≠ A04

Timestamps in fields 2, 4 and 5 are Europe/Copenhagen local time.

Fields 1–10 are unchanged from earlier versions, so existing parsers keep working after upgrading. Fields 11–16 were appended, not inserted.

When parsing fields 11–16, note that field 15 is empty whenever field 11 is 1 — there's no previous period to report. Handle the empty string rather than assuming it parses as a number.

Quality codes (ENTSO-E / Energinet)

Code Meaning
A04 Measured — a real reading
A03 Estimated — the reading didn't arrive in time
Other Adjusted, substituted, or unavailable

Treat A04 as authoritative. Field 16 counts everything else, so you can judge how much of the range total is estimated without parsing each period.

MQTT runtime control

Topic suffix Effect
/Configuration/Token Update refresh token (persists encrypted)
/Configuration/MeterIDs Override meter list — comma-separated, or empty for all meters on the account
/Configuration/ForceUpdate Trigger a fetch (truthy payload)
/Configuration/ClearMeterCache Drop the MQTT override and revert to the config dialog list

Publish these retained so they survive a Node-RED restart. Note that Mosquitto needs persistence true in its config for retained messages to survive a broker restart.

ClearMeterCache exists because publishing an empty string to MeterIDs means "all meters on the account", which is a different thing — it's not a way back to the configured list.

Output count and MQTT-set meters

A node's output count is a deploy-time property. Setting meters over MQTT updates the meter list but cannot add outputs, so data for meters beyond the last wired output is discarded. The node warns when this happens.

To resync: open the node's config dialog (it repopulates from the MQTT-cached list), click Done, then Deploy.

On a central multi-site server it's usually simpler to enter meters in the dialog and skip the MQTT override entirely — you're editing the flow anyway, and the output count then stays correct automatically.


Aalborg Forsyning

Fetches district heating and water meter data. Meter type is detected from the API response; each profile has its own CSV format and topic segment.

Configuration:

Field Notes
Username + password Encrypted at rest
Meters One output per meter; heating and water can be mixed in one node
Schedule Optional HH:MM daily run

API limits enforced by the node

  • 3 calls per 24 hours (the official limit)
  • 5-hour minimum between scheduled calls — ForceUpdate bypasses this
  • Budget persisted to disk, so it survives Node-RED restarts

Because calls are scarce, the node keeps daily counter snapshots per meter (62-day retention) and computes daily, current-month and previous-month consumption from them between API calls. Confidence labels (complete / partial / unavailable) tell you whether snapshot coverage was sufficient.

Heating

Topic: <prefix>/Consumption/Heating/<meterID>

Payload (CSV, 16 fields):

meterID, timestamp, energy_MWh, volume_m3, temp_supply, temp_return, flow,
operating_hours, readings_count, daily_MWh, currentMonth_MWh,
previousMonth_MWh, currentMonth_daysMissing, currentMonth_confidence,
previousMonth_confidence, trigger

Fields 1–13 match the legacy EnergyMeter_xxx function-node format.

Water

Topic: <prefix>/Consumption/Water/<meterID>

Payload (CSV, 11 fields):

meterID, timestamp, volume_m3, readings_count, daily_m3, currentMonth_m3,
previousMonth_m3, currentMonth_daysMissing, currentMonth_confidence,
previousMonth_confidence, trigger

The Heating / Water topic segment exists here because the two payload layouts genuinely differ — downstream systems can route on the topic without inspecting the payload. The Eloverblik node has no equivalent segment because every resolution produces the same layout.

MQTT runtime control

Topic suffix Effect
/Configuration/Username Update username (persists encrypted)
/Configuration/Password Update password (persists encrypted)
/Configuration/MeterIDs Override meter list
/Configuration/ForceUpdate Trigger a fetch

State files

In the Node-RED user directory:

  • norbico-aalborg-<nodeId>.json — call history + heating snapshots
  • norbico-aalborg-<nodeId>-water.json — water snapshots

Writes are atomic (temp file + rename), so a crash mid-write can't corrupt them.


Common behaviour

  • Encrypted credentials in Node-RED's credential store. Credentials set over MQTT are persisted encrypted too.
  • One output per meter, in dialog order.
  • msg.debug carries the same data as a structured object alongside the CSV in msg.payload — useful for inspection without parsing.
  • msg.retain is set on stable-topic messages, but the MQTT out node's own Retain setting takes priority. Set Retain to true there.
  • Automatic retry on transient failures (HTTP 5xx, 408, 429, network errors) with configurable exponential backoff. Permanent errors (4xx) don't retry.
  • Optional daily schedule as HH:MM. For anything more complex, drive the node from an inject node or your own scheduler.

Troubleshooting

Symptom Likely cause
Status shows "no token" but MQTT-in nodes are connected Topic prefix doesn't match the Configuration topics
Configured meters not found on account Meter ID corrupted — set the MQTT-in Output to "a String" (see above), or the metering point isn't authorised on the account
MeterIDs arrived as a number Same — the MQTT-in node is parsing JSON
Fixed a meter ID by hand but it reverts A corrupted ID is cached in flow context and repopulates the dialog. Publish to ClearMeterCache
Nothing arrives at the subscriber Retain not set on the MQTT out node, or a topic in the out node's Topic field overriding msg.topic (leave it empty)
Data for some meters missing More meters configured than wired outputs — reopen the dialog, click Done, redeploy
Aalborg node refuses to fetch Daily 3-call budget spent, or inside the 5-hour window. Use ForceUpdate to bypass the window

License

MIT — see LICENSE.

Issues & contributing

GitHub issues

Node Info

Version: 0.3.2
Updated 1 day ago
License: MIT
Rating: not yet rated

Categories

Actions

Rate:

Downloads

5 in the last week

Nodes

  • norbico-eloverblik
  • norbico-aalborg-forsyning

Keywords

  • node-red
  • norbico
  • eloverblik
  • energinet
  • aalborg
  • aalborg-forsyning
  • fjernvarme
  • energy
  • district-heating
  • denmark
  • utility
  • building-automation
  • niagara

Maintainers