Skip to content

Repository files navigation

luminus-price

Fetches and parses Luminus "Comfy" electricity price-list PDFs for a double-tariff (day/night) meter. Two ways to use it:

  • CLI script (luminus_price.py) — text/JSON output, or publish to MQTT with Home Assistant auto-discovery.
  • Native Home Assistant integration (custom_components/luminus_price/, installable via HACS) — a proper config-flow integration that polls Luminus directly and exposes the same 5 sensors per configured region, no MQTT broker required.

Luminus doesn't publish these prices as HTML/JSON — the price list page (https://www.luminus.be/nl/prive/energie/prijslijsten/) serves a per-plan, per-region PDF via api-next/get-pricelist. This script downloads that PDF and extracts the "Tweevoudige meter" (double tariff) table: peak/ off-peak consumption prices, peak/off-peak injection (solar feed-in) prices, and the annual fixed fee.

Install

pip install -r requirements.txt

paho-mqtt is only needed for --format mqtt.

Usage

# Human-readable, Flanders (default region)
python3 luminus_price.py

# Another region
python3 luminus_price.py --region wallonia

# JSON
python3 luminus_price.py --format json

# Publish to an MQTT broker with Home Assistant discovery
python3 luminus_price.py --format mqtt --mqtt-host 192.168.1.10 \
  --mqtt-username myuser --mqtt-password mypass

# Historical: the price a contract signed in January 2024 started at
python3 luminus_price.py --signing-month 2024-01

Only one region is fetched per run. To track more than one region in Home Assistant, run the script once per region — the default MQTT base topic already encodes the region (luminus/<region>), so separate runs don't collide:

python3 luminus_price.py --region flanders --format mqtt --mqtt-host 192.168.1.10
python3 luminus_price.py --region wallonia --format mqtt --mqtt-host 192.168.1.10

Regions

flanders, wallonia, brussels.

MQTT / Home Assistant discovery

Without --signing-month: 6 retained messages — 5 discovery configs (consumption_peak_ckwh, consumption_off_peak_ckwh, injection_peak_ckwh, injection_off_peak_ckwh, fixed_fee_eur_year) plus 1 JSON state topic.

With --signing-month: 10 retained messages — the same 5 (now sourced from the contract-vs-current comparison's "current" values) plus 4 more (contract_consumption_peak_ckwh, contract_consumption_off_peak_ckwh, contract_injection_peak_ckwh, contract_injection_off_peak_ckwh) — your contract's original signing-month prices, for comparison. All 9/5 share one state topic and one HA "device" entry.

Discovery configs live at <discovery-prefix>/sensor/luminus_comfy_<topic-slug>_<key>/config (default discovery prefix: homeassistant); state at <mqtt-base-topic>/state. Both are keyed off --mqtt-base-topic, not the region — the region only shows in the device's display name (e.g. "Luminus Comfy Electricity (Flanders)").

Relevant flags: --mqtt-host (default localhost), --mqtt-port (1883), --mqtt-username/--mqtt-password, --mqtt-tls, --mqtt-base-topic (default luminus/<region>), --mqtt-discovery-prefix (default homeassistant).

Historical prices & contract-vs-current comparison (--signing-month)

--signing-month YYYY-MM fetches Luminus's public price-list archive for the month a Comfy contract was signed, instead of the current price list. This uses the same public, unauthenticated endpoints that power https://www.luminus.be/nl/apps/prijslijsten-archief/ (look up the product ID for a region+month, then download that PDF); the archive covers roughly 2023-09 onward.

With --format text or --format json, this prints a full contract-vs-current comparison, not just the historical numbers, because consumption and injection behave differently:

  • Consumption is fixed by Luminus for a contract's first 12 months, then Luminus "may adjust" it per the general terms — with no public formula for what it becomes. So: if your contract is still within its first 12 months (checked from the signing month, printed in the output), current consumption == the contract price shown. Past that window, there's no public way to derive the current value — check a recent bill.
  • Injection (solar feed-in) is different: it's re-indexed monthly by a formula fixed at contract signing and printed on the contract's own signing-month PDF. That formula's coefficients are your contract's, not necessarily whatever Luminus currently quotes new signups — confirmed they can differ between contract vintages. So "current injection" here means your contract's own formula applied to this month's published Belpex index value (also pulled from Luminus's own current PDF, since it's market data that can't live in a static past contract — but only the index number is taken from there, not a pre-computed injection price). Expect the result to differ by ~0.01 c€/kWh from your actual bill, since Luminus prints the Belpex value rounded to 2 decimals.

Still not the same as your current bill for consumption past the first year, and there is no way to get your live, personal, currently-indexed price without logging into MyLuminus; that page is account-gated by design and out of scope for this tool. --format mqtt with --signing-month publishes the full comparison too (see the MQTT section above).

Home Assistant integration (HACS)

This repo is a HACS-installable "Integration" repository: it has a hacs.json at the root and the component lives at custom_components/luminus_price/.

Install via HACS

  1. HACS → the three-dot menu → Custom repositories.
  2. Add this repo's URL, category Integration.
  3. Install "Luminus Comfy Price", restart Home Assistant.
  4. Settings → Devices & services → Add integration → search "Luminus Comfy Price" → pick a region, and optionally your contract's signing month (YYYY-MM) for the contract-vs-current comparison.

Repeat step 4 once per region you want tracked — each region is its own config entry (and its own device), matching the CLI script's "run once per region" model. The signing month can be added, changed, or cleared later without removing the integration: open the integration's entry → Configure.

Exposed sensors

Per configured region, one device ("Luminus Comfy Electricity (<Region>)") with:

  • Always: Consumption Peak, Consumption Off-Peak, Injection Peak, Injection Off-Peak, Fixed Fee — the current price. If a signing month is configured, Consumption Peak/Off-Peak track the contract's fixed price while still within its first 12 months (unknown afterward — see --signing-month above for why), and Injection Peak/Off-Peak are computed from your contract's own formula, not just read off the current price list.
  • Only with a signing month configured (disabled by default in the entity registry — enable from the device's entity list if you want them): Contract Consumption Peak/Off-Peak, Contract Injection Peak/Off-Peak — your contract's original signing-month prices, for reference/comparison. Report unknown if no signing month is set.

Polling: every 4 hours normally. If a fetch fails (entity goes unavailable), it retries every 10 minutes until one succeeds, then falls back to the 4-hour interval.

Releases

Published to evenssolutions/luminus-pricing. HACS tracks versions via git tags — manifest.json's "version" is bumped and a matching tag (e.g. v0.0.1) is created for each release.

Testing

pip install -r requirements-dev.txt
pytest

tests/test_api.py parses frozen PDF snapshots (tests/fixtures/comfy_flanders_202608.pdf, a current-price PDF, and comfy_flanders_202401_signing.pdf, an archived signing-month PDF with a different table label for the injection row and different injection-formula coefficients) rather than hitting the network, so it catches regressions in both the price-table parser and the injection formula parser, independent of Luminus's current prices or endpoint availability. tests/test_signing_comparison.py covers the "is consumption still fixed?" date-window logic used by --signing-month.

Notes

  • Breaking change if you installed the integration before this version: DoubleTariffPrice's peak_ckwh/off_peak_ckwh fields (and matching CLI JSON keys / MQTT sensor keys) are now consumption_peak_ckwh/consumption_off_peak_ckwh, for consistency with the new contract_consumption_*/current_consumption_* fields. In Home Assistant this changes entity unique IDs, so you'll get new sensor.consumption_peak entities and should remove the old sensor.peak/sensor.off_peak ones manually (any history on the old entities won't carry over).
  • Prices are Luminus's currently published, monthly-indexed rates — re-fetch (script re-run, or the HA integration's next poll) for current figures.
  • The Brussels region requires an extra isBrussels=true query parameter alongside tabValue=Brussels, or the endpoint 404s; this is handled internally.
  • The CLI script and the HA integration share one fetch/parse implementation (custom_components/luminus_price/api.py) — the CLI imports it rather than duplicating it, so luminus_price.py only works when run from inside this repo checkout (it needs custom_components/luminus_price/ alongside it).

About

Fetch Luminus Contracts from the PDFs on the website

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages