npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

node-red-contrib-norbico

v0.4.0

Published

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.

Readme

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