lumnik. / scenarios All scenarios · Français

Lyon draws 18.7 kW at night and only its owner is alerted

Goal Be alerted when a closed site draws more than its night threshold, without alerting the sites where that load is normal.

Three meters publish their power to Kafka at 23:15. A CSV registry says what each site is.

sites.csv
site_id,site_name,activity,night_baseline_kw,night_alert_kw,energy_owner,owner_email,tariff,context
SITE-LYON,Lyon Assembly Plant,Industrial assembly,4,10,Elodie Martin,elodie.martin@example.test,Peak and off-peak,Production must be stopped after 22:00
SITE-OFFICE,Paris Operations Office,Office,1,3,Karim Benali,karim.benali@example.test,Commercial standard,Only network and security systems stay powered
SITE-LAB,Grenoble Materials Laboratory,Research laboratory,28,40,Dr. Maya Laurent,maya.laurent@example.test,Research continuity,Climate chambers run continuously overnight
calibration.jsonl
{"reading_id":"CAL-LYON","meter_id":"MTR-042","site_id":"SITE-LYON","measured_at":"2026-10-15T17:00:00Z","power_kw":7.2,"period":"OPEN"}
{"reading_id":"CAL-OFFICE","meter_id":"MTR-101","site_id":"SITE-OFFICE","measured_at":"2026-10-15T17:00:00Z","power_kw":2.4,"period":"OPEN"}
{"reading_id":"CAL-LAB","meter_id":"MTR-207","site_id":"SITE-LAB","measured_at":"2026-10-15T17:00:00Z","power_kw":31.0,"period":"OPEN"}
manifests/30-enriched-reading.yaml
kind: Entityname: ScenarioEnergyReadingNdescription: "A live electricity reading enriched with the site's operating context."match: [reading_id]scopes: [energy]columns:  reading_id: { label: "Reading" }  meter_id: { label: "Meter" }  site_id: { label: "Site code" }  site_name: { label: "Site" }  power_kw: { label: "Power (kW)" }  period: { label: "Operating period" }  night_alert_kw: { label: "Night alert threshold (kW)" }  energy_owner: { label: "Energy owner" }  owner_email: { label: "Owner email" }  context: { label: "Operating context" }sources:  - table: t_scenario_energy_readings_n    map:      reading_id: reading_id      meter_id: meter_id      site_id: site_id      measured_at: measured_at      power_kw: power_kw      period: periodjoins:  - table: t_scenario_energy_sites_n    from: site_id    to: site_id    map:      site_name: site_name      activity: activity      night_baseline_kw: night_baseline_kw      night_alert_kw: night_alert_kw      energy_owner: energy_owner      owner_email: owner_email      tariff: tariff      context: context
manifests/40-factory-policy.yaml
apiVersion: apps.lumnik.io/v1kind: Processmetadata:  name: scenario-energy-factory-nspec:  scope: energy  on:    event: data.row.changed    table: connector.t_scenario_energy_readings_n  when:    - site_id=SITE-LYON    - period=CLOSED    - power_kw>10  emit:    type: decision.energy-after-hours-factory-n    message: "Meter {meter_id} at {site_id}: {power_kw} kW while the site is closed"
manifests/41-office-policy.yaml
apiVersion: apps.lumnik.io/v1kind: Processmetadata:  name: scenario-energy-office-nspec:  scope: energy  on:    event: data.row.changed    table: connector.t_scenario_energy_readings_n  when:    - site_id=SITE-OFFICE    - period=CLOSED    - power_kw>3  emit:    type: decision.energy-after-hours-office-n    message: "Meter {meter_id} at {site_id}: {power_kw} kW while the office is closed"
manifests/42-laboratory-policy.yaml
apiVersion: apps.lumnik.io/v1kind: Processmetadata:  name: scenario-energy-laboratory-nspec:  scope: energy  on:    event: data.row.changed    table: connector.t_scenario_energy_readings_n  when:    - site_id=SITE-LAB    - period=CLOSED    - power_kw>40  emit:    type: decision.energy-after-hours-laboratory-n    message: "Meter {meter_id} at {site_id}: {power_kw} kW above the laboratory night policy"
after-hours.jsonl
{"reading_id":"NIGHT-LYON-1","meter_id":"MTR-042","site_id":"SITE-LYON","measured_at":"2026-10-15T23:15:00Z","power_kw":18.7,"period":"CLOSED"}
{"reading_id":"NIGHT-OFFICE-1","meter_id":"MTR-101","site_id":"SITE-OFFICE","measured_at":"2026-10-15T23:15:00Z","power_kw":0.8,"period":"CLOSED"}
{"reading_id":"NIGHT-LAB-1","meter_id":"MTR-207","site_id":"SITE-LAB","measured_at":"2026-10-15T23:15:00Z","power_kw":28.4,"period":"CLOSED"}
$ lm entity get ScenarioEnergyReadingE --filter reading_id=NIGHT-LAB-1 -o json
[
  {
    "reading_id": "NIGHT-LAB-1",
    "meter_id": "MTR-207",
    "site_id": "SITE-LAB",
    "measured_at": "2026-10-15T23:15:00Z",
    "power_kw": "28.4",
    "period": "CLOSED",
    "site_name": "Grenoble Materials Laboratory",
    "activity": "Research laboratory",
    "night_baseline_kw": "28",
    "night_alert_kw": "40",
    "energy_owner": "Dr. Maya Laurent",
    "owner_email": "maya.laurent@example.test",
    "tariff": "Research continuity",
    "context": "Climate chambers run continuously overnight",
    "_conflicts": "{}"
  }
]
recovery.jsonl
{"reading_id":"NIGHT-LYON-2","meter_id":"MTR-042","site_id":"SITE-LYON","measured_at":"2026-10-15T23:30:00Z","power_kw":3.9,"period":"CLOSED"}

Limits

  • A policy sees only the Kafka reading's columns: the owner and context from the CSV cannot enter the decision message in v1.
  • The recipient is a static rule for this decision type; lumnik does not read the address from the entity.
  • lumnik compares a measurement with a declared threshold; it does not diagnose the cause. period=CLOSED comes from the source.
  • Grafana queries postgres every 5 seconds; this is not streaming.
  • Synthetic data.

Energy · three sites

At 23:15, a closed factory draws power.

Lyon draws 18.7 kW.

At the same moment, the Grenoble laboratory draws 28.4 kW.

Fictional sites · synthetic data

The problem

The same number does not mean the same thing everywhere.

  • The meter sends a site code and kW.
  • The CSV registry gives the site type and its night threshold.
  • Neither one knows a threshold is crossed.

Nothing is changed

The meters, Kafka and the file stay in place.

  • The Kafka producer does not change.
  • The CSV registry stays where it is.
  • No application to build.

What had to be written

when:
  - site_id=SITE-LYON
  - period=CLOSED
  - power_kw>10

One night threshold per site.

A 110-line scenario, six declaration files.

What the owner receives

One email, for Lyon only.

Email to Elodie Martin
Meter MTR-042 at SITE-LYON: 18.7 kW while the site is closed

Real message, replay of 3 November 2026.

Silence is an answer too

The laboratory runs all night.

  • 28.4 kW, against a 40 kW threshold.
  • Its climate chambers never stop.
  • No decision, no email.

The limit

lumnik compares a measurement with a declared threshold.

  • It does not say why Lyon draws power.
  • “Site closed” comes from the source, not a calendar.
  • The owner comes from the CSV, not the message.

Try it

The scenario replays end to end.

Kafka, CSV, entity, policies, email and Grafana: every step is published with its output.

This scenario needs lumnik Pro.

See the editions →