mako-wim
WiM — Wechselprozesse im Messwesen, Strom und Gas
Process engine workflows for the German metering-point-operator change processes in both Sparten: BK6-24-174 Anlagen 2a/2b (WiM Strom Teil 1 and Teil 2) and the AWH WiM Gas 2.0 (gültig ab 01.10.2026), plus the EDI@Energy AHBs that carry them.
A Prüfidentifikator (PID) is the five-digit BDEW code every message in these processes carries. It names the exact Anwendungsfall, and with it the rules, the Frist and the answer tree that apply — so the PID, not the EDIFACT message type, is what routes.
One engine, two Sparten
AWH WiM Gas 2.0 restates WiM Strom Teil 1 use-case for use-case, Frist for Frist. Only the UTILMD PID namespace splits (55xxx / 44xxx); ORDERS, ORDRSP, REQOTE, QUOTES, IFTSTA and INSRPT are Sparte-neutral AHBs carrying both. The Sparte comes from the recipient MP-ID (BDEW Allgemeine Festlegungen §2.13) and decides four things:
| Strom | Gas | |
|---|---|---|
| Antwort-Codeliste | S_00xx |
G_00xx |
| Zuordnungszeitpunkt | 00:00 Uhr | 06:00 Uhr (Gastag) |
| APERAK | positiv und negativ, 45 min für UTILMD/ORDERS | nur negativ; nächster WT 12:00 (Folgeprozess) / 3 WT (Initialprozess) |
| Störungs-Fristen | nach Messtechnik | flach |
Fristen
Three clocks run on an inbound MSB-Wechsel order, and they are separate messages with separate commands:
| Clock | Window | Message | Source |
|---|---|---|---|
| APERAK — technical acknowledgement | Strom 45 Minuten (UTILMD/ORDERS am Werktag); Gas nächster WT 12:00 bzw. 3 WT auf einem Initialprozess | APERAK BGM+312/313 (Gas: nur 313) | APERAK AHB 1.1 §2.3.1/§2.4.1 |
| Antwort — business Bestätigung/Ablehnung | per PID, in beiden Sparten gleich: 55039·44039 → 3 WT, 55042·44042 → 5 WT, 55051·44051 → 7 WT, 55168·44168 → 1 WT | the Antwort-PID's UTILMD | WiM Teil 1 Kap. 2.2.2 / 2.3.2 / 2.4.2 · AWH WiM Gas 2.0 Kap. 3.3.2 / 3.5.2 / 3.6.2 |
| Vorlauffrist — was the requested date admissible? | 15 / 7 WT (Anmeldung), 20 WT (Abmeldung), ±9 WT Realisierungskorridor | the date inside the message | WiM Teil 1 Kap. 2.3.2 Nr. 1 / 2.4.2 Nr. 1 |
Only the second discharges the Antwortfrist. The business window comes from
antwort_frist_werktage(pid) and the Vorlauffristen from
mako_fristen::vorlauf — never a flat value. Saturday is not a Werktag
(GPKE Teil 1 Kap. 1.7, which WiM Teil 1 §1.7 defers to), and 24.12. and 31.12.
count as holidays.
Antwortcodes
Every answer carries SG4 STS+E01 (UTILMD) or SG2 AJT (ORDRSP) with a code
from the process's own Entscheidungsbaum. The catalogue and the executable
Prüfschritte are mako-pruefung (role-msb); this crate resolves against it
before anything reaches the outbox, so a code from the wrong tree is refused at
the command rather than sent.
DE 1131 / DE 1082 names the Codeliste, not the Entscheidungsbaum. The AHB
column reads „Codeliste Strom Nr. S_0090" for every WiM MSB-Wechsel answer,
and the cluster picks which of the pair. AntwortCode::wire_codeliste()
returns the wire value.
| Process | EBD Strom / Gas | Bestätigung / Ablehnung | Codeliste Strom | Gas |
|---|---|---|---|---|
| Kündigung MSB | E_0200 / E_2000 |
E15 Z01 Z44 / E11 Z12 Z29 Z34 (+ZC9 Strom) |
S_0090 / S_0054 |
G_0052 / G_0051 |
| Anmeldung MSB | E_0201 / E_2002 |
E15 Z01 Z44 / E11 E17 Z09 Z29 ZB6 (+ZC9 Strom) |
S_0055 / S_0056 |
G_0054 / G_0053 |
| Ende MSB | E_0202 / E_2005 |
E15 Z01 / E17 Z09 |
S_0059 / S_0060 |
G_0058 / G_0057 |
| Verpflichtungsanfrage | E_0240 / E_2006 |
E15 Z01 Z44 / E17 Z07 Z09 ZB6 |
S_0063 / S_0064 |
G_0070 / G_0071 |
| Gesamtvorgang | E_0232 / E_2003 |
— / Z66 |
S_0057 |
G_0055 |
| Weiterverpflichtung | E_0203 / E_2004 |
Z13 Z14 / Z22 |
S_0061 / S_0062 |
G_0072 / G_0073 |
| Gerätewechselabsicht | E_0204 / E_2007 |
ZB4 / ZB5; E17 Z07 in beiden |
S_0065 / S_0066 |
G_0059 / G_0060 |
| Bestellung Geräteübernahme | E_0247 / E_2011 |
Z13 / 5 Z32 |
S_0067 / S_0068 |
G_0061 / G_0074 |
| Messlokationsänderung, direkt beauftragt | E_0249 (NB) / E_0250 (LF) |
A02 / A01 (+ A03 A04) |
E_0249 / E_0250 |
— |
| Anfrage Änderung der Technik (35005) | E_0278 (NB) / E_0281 (LF) |
— / A01–A04 A99 resp. A01–A06 A99 |
E_0278 / E_0281 |
— |
| Bestellung Änderung der Technik nach Angebot | E_0279 (NB) / E_0283 (LF) |
A06 / A01–A05 A99 |
E_0279 / E_0283 |
— |
| Messlokationsänderung durchführen | E_0286 |
— / A01 A02 A03 A99 |
E_0286 |
— |
| Ersteinbau iMS (21029 → 21030/21031) | E_0233 |
A03 / A01 A02 A04 |
E_0233 |
— |
None of these alphabets is a GPKE one — A02 and A05 appear in no
MSB-Wechsel tree — and the Gas lists are not the Strom lists.
PID Inventory
Legend: ✅ Implemented — full state machine + AHB rule enforcement, production-safe. ⚠️ Registered — PID routes to the workflow;
handle()returnsWorkflowError::NotImplementedfor unhandled commands (no silent data loss). ✗ Not registered — PID is not in the router; inbound messages are dead-lettered.
MSB-Wechsel — UTILMD (WiM Strom Teil 1 Kap. 2)
| PID | Process name | EDIFACT | Module | Status |
|---|---|---|---|---|
| 55042 | Anmeldung MSB (MSBN → NB) | UTILMD S2.x | geraetewechsel |
✅ Implemented · Antwort 55043/55044, 5 WT (vorläufig) |
| 55039 | Kündigung MSB (MSBN → MSBA) | UTILMD S2.x | geraetewechsel |
✅ Implemented · Antwort 55040/55041, 3 WT |
| 55051 | Ende MSB / Abmeldung (MSBA → NB) | UTILMD S2.x | geraetewechsel |
✅ Implemented · Antwort 55052/55053, 7 WT |
| 55168 | Verpflichtungsanfrage / Aufforderung (NB → gMSB) | UTILMD S2.x | geraetewechsel |
✅ Implemented · Antwort 55169/55170, 1 WT |
| 44039 | Kündigung MSB Gas (MSBN → MSBA) | UTILMD G1.x | geraetewechsel |
✅ Implemented · Antwort 44040/44041, 3 WT |
| 44042 | Anmeldung MSB Gas (MSBN → NB) | UTILMD G1.x | geraetewechsel |
✅ Implemented · Antwort 44043/44044, 5 WT (vorläufig) |
| 44051 | Ende MSB Gas (MSBA → NB) | UTILMD G1.x | geraetewechsel |
✅ Implemented · Antwort 44052/44053, 7 WT |
| 44168 | Verpflichtungsanfrage Gas (NB → gMSB) | UTILMD G1.x | geraetewechsel |
✅ Implemented · Antwort 44169 only — no Ablehnungs-PID exists, 1 WT |
| 44183 | Ende MSB von NB (Stilllegung, NB → MSB) | UTILMD G1.x | geraetewechsel |
✅ Implemented · informational, no answer |
Mitteilung über Gesamtvorgang — IFTSTA
The Anmeldebestätigung 55043 is vorläufig. WiM Teil 1 Kap. 2.1.1: the NB assigns the MSBN „zu dem Tag des vom MSBN mitgeteilten Termins des erfolgreichen Abschlusses des Gesamtvorgangs … mit dem Zeitpunkt 00:00 Uhr", and the MSBA's assignment ends at the same instant. AWH WiM Gas 2.0 Kap. 3.1.1 says the same with 06:00 Uhr — the Gastag boundary. This leg is what makes the Wechsel constitutive.
| PID | Process name | Von → An | Frist |
|---|---|---|---|
| 21010 | Statusmeldung (erfolgreich), DTM+2380 |
MSBN → NB | 10 WT nach dem bestätigten Zuordnungsbeginn |
| 21009 | Statusmeldung (gescheitert) | MSBN → NB | — |
| 21012 | Statusmeldung (erfolgreich) — die Zuordnung | NB → MSBN | 1 WT |
| 21011 | Statusmeldung (MSB-Scheitermeldung, Z66) |
NB → MSBN/MSBA/LF | 1 WT |
| 21013 | Statusmeldung (gescheitert) — keine Meldung eingegangen | NB → MSBN/MSBA/LF | 11 WT |
The numeric order is the reverse of the reading order: 21009 is the failure and 21010 the success (IFTSTA AHB 2.1 § 6.2).
Every failure path leaves the MSBA assigned.
marktdderives the per-Messlokation MSB timeline from 21012 alone.
Geräteübernahme — ORDERS / ORDRSP
| PID(s) | Process name | EDIFACT | Module | Status |
|---|---|---|---|---|
| 17001 | Bestellung Geräteübernahmeangebot (MSBN → MSBA) | ORDERS 1.4b | geraeteubernahme |
✅ Implemented · Antwort 19001/19002, 2 WT |
| 17009 | Anzeige Gerätewechselabsicht (MSBN → MSBA) | ORDERS 1.4b | geraeteubernahme |
✅ Implemented · Antwort 19015/19016, 2 WT vor dem Wechseltermin; ein Termin näher als 4 WT wird mit E17 abgelehnt |
| 19001, 19002 | ORDRSP Bestellbestätigung / Ablehnung (MSBA → MSBN) | ORDRSP 1.4c | geraeteubernahme |
✅ Registered (nMSB role only) |
| 19015, 19016 | ORDRSP Eigenausbau ja/nein (MSBA → MSBN) | ORDRSP 1.4c | geraeteubernahme |
✅ Registered (nMSB role only) |
| 17002 → 19003/19004 | Weiterverpflichtung des MSB (NB → MSBA) | ORDERS 1.4b | weiterverpflichtung |
✅ Implemented · 1 WT, E_0203 |
The Anforderung eines Geräteübernahmeangebots is REQOTE 35001, answered by QUOTES 15001 within 4 WT —
preisanfrageowns that leg.19016 is named „Ablehnung Gerätewechselabsicht" but carries
ZB5„Kein Eigenausbau des MSBA": it settles who removes the old device, not whether the Gerätewechsel happens.
PIDs 19001/19002/19015/19016 are only registered when
DeploymentRolesincludesMarktrolle::Nmsb. On NB instances these PIDs belong tomako-gpke(GPKE Konfiguration). Never register both simultaneously.All six ORDERS/ORDRSP PIDs carry the Strom and the Gas Use-Case; the recipient MP-ID's Sparte picks
E_0247/E_0204againstE_2011/E_2007.
Stammdaten — ORDERS
| PID(s) | Process name | EDIFACT | Module | Status |
|---|---|---|---|---|
| 17132 | Stammdaten Anforderung Strom (NB → MSB) | ORDERS 1.4b | stammdaten |
✅ Implemented |
| 17102–17133 | Stammdatenübermittlung responses (MSB → NB) | ORDERS 1.4b | stammdaten |
✅ Implemented |
Weitere Prozesse
| PID(s) | Process name | EDIFACT | Module | Status |
|---|---|---|---|---|
| 39002 | ESA Stornierung der Bestellung von Werten (ORDCHG) | ORDCHG 1.1 | wertebestellung |
✅ Implemented |
| 31009 | MSB-Rechnung (MSB → NB/LF/ESA) | INVOIC 2.8e | invoic |
✅ Implemented (send + receive) · Antwort zum Zahlungsziel, an den NB 4. WT davor |
| 33001–33004 (REMADV) | Zahlungsavis / itemized Abweisung | REMADV 1.0a | invoic |
✅ Implemented (33003/34 = Strom Kopf+Summe / Position) |
| 29001 (COMDIS) | Ablehnung REMADV | COMDIS 1.0 | invoic |
✅ Implemented · 2. WT vor dem Zahlungsziel |
| 35001 → 15001 (REQOTE/QUOTES) | Anforderung Geräteübernahmeangebot (MSBN → MSBA) | REQOTE 1.3c | preisanfrage |
✅ Implemented · 4 WT |
| 35002 → 15002 | Anfrage Rechnungsabwicklung über den LF (LF → MSB) | REQOTE 1.3c | preisanfrage |
✅ Implemented · 5 WT |
| 35004 → 15004 | Anfrage einer Konfiguration (GPKE Teil 3, NB/LF → MSB) | REQOTE 1.3c | preisanfrage |
✅ Implemented · 2 WT |
| 35005 → 15005 | Anfrage Angebot Änderung Technik (NB/LF → MSB) | REQOTE 1.3c | preisanfrage |
✅ Implemented · 10 WT |
| 17005/17006 → 19009/19010 | Rechnungsabwicklung MSB über LF | ORDERS/ORDRSP | rechnungsabwicklung |
✅ Implemented · 8 WT |
| 27001–27003 | Preisliste (PRICAT) | PRICAT 2.1 | preisliste |
✅ Implemented · Preisblatt an LF 3 Monate vor Wirksamwerden, an NB initial 3 WT / bei Änderung 20 WT vor Inkrafttreten |
| 23001, 23003, 23004, 23008 | Störungsmeldung / Antwort / Ergebnisbericht | INSRPT 1.1a | insrpt |
✅ Implemented, beide Seiten · Antwort Strom 3 WT (kME ohne RLM, mME) / 1 WT (kME mit RLM, iMS), Gas flach 3 WT; Ergebnis Strom 7/4/2 WT nach Messtechnik und Spannungsebene, Gas flach 7 WT |
| 23005, 23009 | Informationsmeldungen an den NB (Gas) | INSRPT 1.1a | insrpt |
✅ Implemented |
| 23011, 23012 | Weiterleitung an betroffene Marktlokationen (Strom) | INSRPT 1.1a | insrpt |
✅ Implemented · 1 WT, und das Fenster überlebt den Ergebnisbericht — die 23012 ist danach fällig |
| 31003 → 33001/33002 | WiM-Rechnung (MSBA → NB / MSBN), beide Sparten | INVOIC 2.8e | invoic |
✅ Implemented · Rechnung 20. WT nach Leistungsende, Antwort zum Zahlungsziel |
| 31004 → 33001/33002 | Stornorechnung, Sparte-neutral | INVOIC 2.8e | invoic |
✅ Implemented |
| 11021–11023 | iMS Bestellung (Universalbestellprozess) | REST/JSON | steuerungsauftrag |
✅ Implemented (API-Webdienste channel) |
EDIFACT Format Versions
WiM rides eleven message types and they do not share a release cadence, so there is no single WiM format version. The profiles this crate validates against:
| Message | FV2025-10-01 |
FV2026-10-01 |
|---|---|---|
| UTILMD Strom | AHB 2.1 (MIG S2.1) | AHB 2.2 (MIG S2.2) |
| REQOTE | AHB 1.1 (MIG 1.3c) | AHB 1.2 (MIG 1.3c) |
| QUOTES | AHB 1.1 (MIG 1.3b) | AHB 1.1a (MIG 1.3c) |
| PRICAT | AHB 2.0f (MIG 2.0e) | AHB 2.1 (MIG 2.1) |
| IFTSTA | AHB 2.0h (MIG 2.0g) | AHB 2.1 (MIG 2.1) |
| ORDERS / ORDRSP | — (FV2026-04-01: AHB 1.1a, MIG 1.4b) |
AHB 1.1b (MIG 1.4c) |
INSRPT ships only at FV2026-01-01 (AHB 1.1g, MIG 1.1a), INVOIC and REMADV from
FV2026-04-01, ORDCHG at FV2025-04-01 and FV2026-10-01. The AHB and the
MIG carry different version numbers for every message type except UTILMD — the
tables above name the MIG release, which is what the „EDIFACT" column of the PID
inventories cites.
Modules
| Rust module | Contents |
|---|---|
geraetewechsel |
PIDs 55039/55042/55051/55168 and their Gas twins 44039/44042/44051/44168, plus 44183 and IFTSTA 21007/21009–21013/21015/21018/21036, of which 21009–21013 are the Gesamtvorgang leg (GESAMTVORGANG_PIDS) — MSB-Wechsel workflow + projection. Handles both directions: inbound UTILMD (ReceiveUtilmd → APERAK → DispatchAntwort → ReceiveGesamtvorgang → DispatchZuordnung) and ERP-initiated outbound orders (InitiateDeviceChange → ReceiveAntwort → MeldeGesamtvorgang → ReceiveZuordnungsantwort). Antwortfrist per process via antwort_frist_werktage(); the Realisierungskorridor is enforced on the Gesamtvorgang date. |
geraeteubernahme |
ORDERS 17001 → ORDRSP 19001/19002 (Bestellbestätigung/Ablehnung) and ORDERS 17009 → 19015/19016 (Eigenausbau ja/nein) — WiM Teil 1 Kap. 3.1/3.2. The 17009 Mindestvorlaufzeit is checked against mako_fristen::vorlauf before the answer window opens: a Gerätewechseltermin closer than the 4. Werktag is refused with E17 naming the earliest date still reachable, rather than accepted with a window that expired before the message arrived |
weiterverpflichtung |
ORDERS 17002 → ORDRSP 19003/19004 — the NB keeping the abgebender MSB on the Messlokation while the gMSB prepares to take over (Kap. 2.4.2 Nr. 5/6, E_0203) |
technik_aenderung |
REQOTE 35005 → QUOTES 15005 / IFTSTA 21033, ORDERS 17011/17118 → ORDRSP 19005/19006, IFTSTA 21025/21027 — Messlokationsänderung auf beiden Wegen; 10 WT Antwort, 20 WT Vorlauffrist nur auf der direkten Beauftragung (Kap. 3.3 / AWH Änd. Technik) |
ersteinbau |
IFTSTA 21029 → 21030/21031 — Ersteinbau eines iMS in eine bestehende Messlokation, 3 WT Antwort aus E_0233 (Kap. 3.5, Strom only) |
stammdaten |
PIDs 17102–17133, 17132 — Stammdaten Anforderung / Übermittlung |
wertebestellung |
PIDs 35003/15003/17007/17008, ORDCHG 39002 (Stornierung, answered by ORDRSP 19013/19014), ORDRSP 19011/19012, IFTSTA 21042 — ESA Wertebestellung (WiM Teil 2 Kap. 4): Anfrage → Angebot → Bestellung → Stornierung/Abbestellung, plus MSB-initiated termination. Fristen keyed on the positive AS4-Zustellquittung (ÜT); answers carry an E_0254/E_0256/E_0257 Antwortcode. |
invoic |
INVOIC 31009 (MSB-Rechnung, Strom) · 31003 (Dienstleistungen, beide Sparten) · 31004 (Stornorechnung, Sparte-neutral); inbound REMADV 33001–33004 and COMDIS 29001 — see below |
preisanfrage |
PIDs 35001/35002/35004/35005 (REQOTE), 15001/15002/15004/15005 (QUOTES) — Preisanfrage |
preisliste |
PIDs 27001–27003 — Preisliste PRICAT |
esa_wertebestellung |
The ESA side of the same relationship (esa-wertebestellung): it sends 35003/17007/17008/39002 and ingests the MSB's 15003/19011–19014/21042/13027. Disjoint commands from wertebestellung, so one deployment may hold both roles |
insrpt |
INSRPT 23001 → 23003/23004 (Entscheidungen), 23005/23009/23011/23012 (Informationsmeldungen), 23008 (Ergebnisbericht) — Störungsmeldung, both sides |
rechnungsabwicklung |
ORDERS 17005/17006 → ORDRSP 19009/19010 — Rechnungsabwicklung des MSB über den LF, 8 WT (E_0205–E_0209) |
steuerungsauftrag |
PIDs 11021–11023 — iMS Steuerungsauftrag (API-Webdienste REST channel) |
The invoic family
Both sides run here: the MSB sends with SendInvoic and awaits the REMADV;
the NB/LF/ESA ingests with ReceiveInvoic, then settles or disputes.
Replies correlate by conversation ID (RFF+Z13 → the 31009 reference), so they
resume this family even though the shared REMADV PID statically resolves to
GPKE. The state machine itself is mako-invoic's, shared with the GPKE, GaBi
Gas and GeLi Gas billing families; this module declares only the family and the
Gas Ablehnungs-Entscheidungsbaum.
Usage
use ;
use ;
// In tests (requires `testing` feature or `#[cfg(test)]`):
let ctx = new
.with_event_store
.build;
// In production, explicitly provide all stores:
// let ctx = EngineBuilder::with_stores(outbox, deadline, registry)
// .with_event_store(my_slatedb_store)
// .build();
let process = ctx.;
let events = process.execute.await?;
Geräteübernahme (WiM Teil 1, Kapitel 3.2)
| Step | Direction | Message | PID | Frist |
|---|---|---|---|---|
| 1 Anforderung Geräteübernahmeangebot | MSBN → MSBA | REQOTE | — | — |
| 2 Geräteübernahmeangebot | MSBA → MSBN | QUOTES | 15001 | 4 WT nach ÜT von Nr. 1 |
| 3 Bestellung | MSBN → MSBA | ORDERS | 17001 | 3 WT nach ÜT von Nr. 2 |
| 4 Bestellbestätigung | MSBA → MSBN | ORDRSP | 19001 / 19002 | 2 WT nach ÜT von Nr. 3 |
| 5 Zählerstand zur Geräteübernahme | MSBA → MSBN | MSCONS | — | 3 WT vor Ablauf des 28. T |
Adjacent processes sharing the workflow: ORDERS 17002 (Weiterverpflichtung MSBA) answered by ORDRSP 19003/19004, and ORDERS 17009 (Ankündigung Gerätewechselabsicht) answered by ORDRSP 19015/19016.
ESA Wertebestellung (WiM Teil 2, Kapitel 4)
§34 Abs. 2 S. 2 Nr. 10 MsbG makes serving an Energieserviceanbieter a mandatory,
non-discriminatory Zusatzleistung, so an MSB must be able to process the order
that authorises value delivery and the one that stops it. Both sides are
modelled: wertebestellung (MSB) and esa_wertebestellung (ESA), over disjoint
PID sets so one deployment may hold both roles.
| UC step | Direction | Message | PID | Frist | EBD |
|---|---|---|---|---|---|
| 4.1 Nr. 1 Anfrage | ESA → MSB | REQOTE | 35003 | — | E_0252 |
| 4.1 Nr. 2 Angebot / Ablehnung | MSB → ESA | QUOTES | 15003 | 5 WT nach ÜT der Anfrage | — |
| 4.1 Nr. 3 Bestellung | ESA → MSB | ORDERS | 17007 | bis Ablauf der Bindungsfrist | — |
| 4.1 Nr. 4 Antwort | MSB → ESA | ORDRSP | 19011 / 19012 | 2 WT nach ÜT der Bestellung | E_0256 |
| 4.1 Nr. 5 Stornierung | ESA → MSB | ORDCHG | 39002 | unverzüglich | — |
| 4.1 Nr. 6 Antwort | MSB → ESA | ORDRSP | 19013 / 19014 | 2 WT nach ÜT der Stornierung | E_0257 |
| 4.2 Werteübermittlung | MSB → ESA | MSCONS | 13027 | per Messprodukt | — |
| 4.3 Nr. 1 Abbestellung | ESA → MSB | ORDERS | 17008 | unverzüglich | — |
| 4.3 Nr. 2 Antwort | MSB → ESA | ORDRSP | 19011 / 19012 | 2 WT nach ÜT der Abbestellung | E_0254 |
| 4.4 Nr. 1 Beendigung durch MSB | MSB → ESA | IFTSTA | 21042 (STS+Z21 4405 = 105) |
unverzüglich | — |
What is ordered
The esa module holds the Codeliste der Konfigurationen 1.4
Kapitel 4.6 catalogue — the only Messprodukte the role may order — as data:
delivery path (4.6.1 EDIFACT back-end vs 4.6.2 SM-PKI from the iMS),
Lokationsebene, Werteart, Energieflussrichtung, cadence, and whether BNetzA
Mitteilung Nr. 3 makes the product mandatory. A Bestellgegenstand pairs a
Messprodukt-Code with the DTM+76 Wunschtermin and the IMD+7081 Abonnement
mode, and is carried through both aggregates: without it the process could not
say what a confirmed delivery is supposed to contain.
A subscription is the (Meldepunkt, Messprodukt) pair (esa::business_key) —
one Marktlokation can carry several products at once, so every follow-up message
and command has to say which one it means.
An order is validated against the catalogue before it leaves the system — a product outside Kapitel 4.6, one defined for a different Lokationsebene than the request addresses, or a 4.6.2 product without its SM-PKI target is refused.
The product decides the Lokationsebene (esa::ebene_fuer_messprodukt).
REQOTE AHB 1.2 §4.3 gives LOC+172 DE 3225 four permitted shapes and lets the
Marktlokations-ID format ([950]) serve both the Marktlokation (hint [502])
and the Tranche (hint [504]), so an identifier cannot resolve the level —
and the Tranche carries a Pflichtprodukt (9991 00000 306 4).
„Pflicht" and „nutzbar ab" are two different dates, and both are dates rather
than flags: 9991 00000 077 1 and 078 9 read „Optional ab 01.10.2023, Pflicht
ab 06.08.2024" while being usable from 01.10.2023. Verbindlichkeit::Pflicht { ab }
carries its start and Messprodukt::ist_pflicht_am is what E_0252 Prüfschritt 1
asks — a Vergangenheitswerte-Anfrage may reach back before the cut-over.
The Angebot is a priced offer
UC 4.1.1 has the ESA asking for „die Übermittlung von Werten und die damit
verbundenen Kosten". QUOTES AHB 1.1a §4.3 makes the substance Muss — SG4 CUX,
one to three SG27 PIA+Z02 Artikel-IDs, one SG31 PRI+CAL each (Z01
Einrichtungs- / Z02 Transaktions- / Z03 Betriebspreis) and one to 23
PIA+5 … :SRW OBIS-Kennzahlen — so esa::Angebot carries all of it and the
process keeps it past the Bestellung: it is what the INVOIC 31009 is checked
against and what a delivery-surveillance sweep expects to arrive.
It is also the discriminator. DTM+273 is Muss on the only published 15003
use case, so a refusal carries a Bindungsfrist too; the priced position is what
tells an Angebot from an Ablehnung.
The Prüfidentifikator is not in BGM
BGM DE 1004 is a Dokumentennummer throughout these handbooks; the PID
travels in SG1 RFF+Z13. DE 1001 carries a BDEW document code: Z57 on the
order handshake, Z83 on the MSCONS 13027 delivery, Z09 on the IFTSTA 21042.
Correlation
Only the opening REQOTE is keyed on a location. A conformant ORDERS, ORDCHG,
ORDRSP or IFTSTA of Kapitel 4 carries no LOC at all and correlates by a
Belegnummer, under the Zuordnungsschlüssel the BDEW Anwendungsübersicht der
Prüfidentifikatoren 4.0 publishes per PID:
| PID | Schlüssel | Segment | Points at |
|---|---|---|---|
| 35003 | ZO-T17 |
SG11 LOC+172 |
the Meldepunkt |
| 15003 | ZG-T16 |
SG1 RFF+AAV |
the REQOTE |
| 17007 | ZG-T24 |
SG1 RFF+AAG |
the QUOTES Angebot |
| 17008 | ZG-T41 |
SG1 RFF+ACW |
the ORDERS Bestellung |
| 39002 | ZG-T51 |
SG1 RFF+ON |
the ORDERS Bestellung |
| 19011 / 19012 | ZG-T14 |
SG1 RFF+ON |
the ORDERS answered |
| 19013 / 19014 | ZG-T50 |
SG1 RFF+ACW |
the ORDCHG |
| 21042 | ZG-T47 |
SG15 RFF+AGI |
the ORDERS Bestellung |
| 13027 | ZG-T42 (of EZ-03) |
SG1 RFF+AGI |
the ORDERS Bestellung |
esa::korrelation is that table; the renderer and the ingest dispatcher both
read it, so the qualifier they emit and the one they look for cannot drift. Note
that the same AGI qualifier sits in a different segment group per message —
SG15 on the IFTSTA, SG1 on the MSCONS — which is why the lookup searches by
qualifier rather than by position. EZ-03 continues past it to ZO-T20
(Gerätenummer) and ZO-T21 (OBIS-Kennzahl); those two assign the values to a
Zählwerk and belong to edmd.
Answers are Antwortcodes, not booleans
SG2 AJT is Muss on all four answer PIDs (ORDRSP AHB 1.1b §4.15) and carries the
Prüfschritt code in DE 4465 with its EBD in DE 1082. Conditions [17]/[18] require
the code to sit in that tree's Zustimmungs- resp. Ablehnungs-Cluster, so the
cluster selects the answer PID. The MSB commands therefore take an
antwort_code resolved against mako_pruefung::esa::wertebestellung, never an accept
flag alongside it.
And it is the whole content of a refusal on the receiving side too. Those
four use cases publish no free-text segment at all: the only FTX a
conformant 19011 may carry is SG27 FTX+Z27 — the MSB's IP address, Muss when
the confirmed order named a Kapitel-4.6.2 SMGW product (FTX+Z28 for a range),
and the source the ESA has to admit before the iMS can reach it.
The ESA side therefore records esa::Antwort, the typed (Antwortcode, EBD)
pair, rather than prose — that is what tells A08 (Einwilligung abgelaufen:
renew and re-order) from A10 (Lokationsbündel: split the request) from A09
(Gerätetechnik: nothing to retry). Antwort::widerspricht_pid flags a code whose
Cluster contradicts the PID that carried it; such an answer is recorded as a
conflict and resolved by the PID, since resolving it by the code would
silently turn a confirmation into a refusal.
Every inbound step notifies
The MSB-side workflow emits a ProcessInitiated outbox entry on each of
35003/17007/39002/17008. That notification is the entire input to processd's
ESA module — the four mako-pruefung walks, the operator queue and its Fristen —
and its payload is a contract: every field is a Prüfschritt input, so an omitted
one does not fail, it escalates a decision that could have been answered. In
particular abo_beginn (the confirmed DTM+203 of the Bestellung) is what
E_0254 Prüfschritt 2 compares a requested end against.
What a subscription remembers
Both aggregates keep lieferung_begonnen in their process data, not inside
the state variant that happens to be current. It is a fact about the
subscription: it has to survive a Storno or Abbestellung round trip, and a first
delivery landing while a 39002 is in flight is exactly the case E_0257 A02
exists for. The MSB side additionally remembers its own Bindungsfrist (E_0256
Prüfschritt 1 asks about it one state later), the Abo start, the reach of its
latest delivery and any date it already ended on — the three inputs E_0254
Prüfschritte 2–4 need.
An Angebot whose Bindungsfrist lapses is terminal on the ESA side: UC 4.1 Nr. 3 admits no Bestellung after it, so the process releases its (Meldepunkt, Messprodukt) business key rather than blocking every replacement order.
19011/19012 answer both the Bestellung and the Beendigung; the IMD+7081 on the
answer is what says which tree its code came from.
Stornierung and Abbestellung are not interchangeable
UC 4.1 Nr. 5 admits a Stornierung only while the einmalige Übermittlung has not
happened or the turnusmäßige has not begun; UC 4.3's Vorbedingung then states
"Eine Stornierung der Bestellung ist nicht mehr möglich".
MarkLieferungBegonnen flips the state that enforces this. On the MSB side the
two trees make the boundary explicit: E_0254 A01 refuses a Beendigung of a
one-shot order, and E_0257 refuses a Stornierung of a started delivery with
different codes per Abo mode (A02 Abo, A03 einmalig).
Regulatory references
- BDEW WiM Wechselprozesse im Messwesen
- MsbG — Messstellenbetriebsgesetz
- BNetzA BK6-24-174 Anlagen 2a/2b (WiM Strom Teil 1 und Teil 2)
- BDEW/VKU/GEODE/FNBGas AWH WiM Gas 2.0 (gültig ab 01.10.2026)
- EDI@Energy UTILMD Strom AHB 2.2 (MIG release S2.2,
FV2026-10-01) - EDI@Energy APERAK AHB 1.1 (
FV2026-10-01) — § 2.4.1 Strom, § 2.3.1 Gas. 2.2 is the APERAK MIG revision; AHB and MIG carry different version numbers for every message type except UTILMD
Related crates
The format layer and the domain packs meet in makod: a workflow crate knows the
Pruefidentifikator and its own domain types, never an EDIFACT message type.
| Crate | Role |
|---|---|
mako-wim ← this crate |
WiM workflows for both Sparten, PID routing, WimModule |
edi-energy |
EDI@Energy EDIFACT — parse · validate · build (UTILMD, MSCONS, ORDERS, INVOIC, APERAK, …); joined to these workflows in makod, not depended on |
mako-engine |
Event-sourced workflow runtime — Workflow, Process, EventStore, deadlines |
mako-fristen |
When an answer is due — Werktage, the MaKo holiday calendar, the per-PID Antwortfristen |
mako-pruefung |
What the answer must be — the BDEW Entscheidungsbäume, executable |
mako-invoic |
The INVOIC settle/dispute state machine every billing family shares |
energy-api |
The parallel API-Webdienste channel for iMS values |
makod |
Production daemon — routes, adapts and renders these workflows |
Part of mako, an open-source Rust platform for German energy market communication (Marktkommunikation). Full documentation: https://hupe1980.github.io/mako/