After-Effects Cascade

Everything that runs automatically when a meter interaction reaches a final status — ordered sequence, conditional branches, follow-up interactions, and the abort cascade.

The blastoff Sequence

Eight steps run in code order after the interaction row is persisted. Steps 5–7 are fired asynchronously (not awaited). Step 8 is always last.

100%
Load interaction + meter Single DB query with nested meter tree Build meter update Type-specific fields + LoRaWAN device info Auto-close open issue If issue type matches closing criteria Write meter to database UPDATE meters SET ... Telegram notification if order_id · terminal status only Recalculate batch progress if batch_execution_id · throttled 5s Commissioning flow advance active or resume paused Emit WebSocket UPDATE meter-interaction event · grid room 1 2 3 4 5 6 7 8 async / no await Loads: type, status, result_value, order_id, batch_execution_id, meter_commissioning, full meter + dcu + grid + last_commissioning updateMeterByInteraction (SUCCESSFUL only): TURN_ON/OFF → is_on · SET/READ_POWER_LIMIT → power_limit READ_CREDIT → credit + is_on · READ_REPORT → same + analytics POST (prod only) · READ_VERSION → version updateMeterByDeviceInfo (LoRaWAN only): RSSI/SNR → connection_metrics, possible dcu_id reassignment Follow-up interactions (async, not awaited) TOP_UP success → creates READ_CREDIT (skipped if part of commissioning) CLEAR_CREDIT success → creates READ_CREDIT (skipped if part of commissioning) SET_POWER_LIMIT fail (CALIN_V1 only) → creates READ_POWER_LIMIT ↺ each new interaction re-enters at step 1 NO_COMMUNICATION → closes when any interaction succeeds (last_seen_at is set) NO_CREDIT → closes when resulting credit balance > 0 UNEXPECTED_POWER_LIMIT → closes when power_limit equals power_limit_should_be POST to FlowXO webhook · only for SUCCESSFUL or FAILED status recalculates pending / processing / successful / failed counts on the batch_execution row interaction has meter_commissioning_id → advanceActiveCommissioningFlow (update status, trigger next, fail siblings on error) no commissioning + last_commissioning = PENDING + this SUCCESSFUL → resumeInactiveCommissioningFlow socket.io room: gridId · event: 'meter-interaction' · operation: 'UPDATE' · skipped if skipWebsocketEmission flag set

Follow-up Interactions & Abort Cascade

Two patterns that extend beyond a single interaction lifecycle.

100%
FOLLOW-UP INTERACTIONS ABORT CASCADE TOP_UP or CLEAR_CREDIT status: SUCCESSFUL READ_CREDIT created _createOneForMeter() SET_POWER_LIMIT FAILED · CALIN_V1 only READ_POWER_LIMIT created _createOneForMeter() enters full pipeline + blastoff at completion Interaction status → ABORTED from gatekeeper or reconciliation if meter_commissioning_id present: Pending siblings → ABORTED QUEUED · SUSPENDED · DEFERRED Commissioning → FAILED meter_commissionings row

Key Concepts

Meter fields by interaction type
  • TURN_ON / TURN_OFF → is_on, is_on_updated_at
  • SET / READ_POWER_LIMIT → power_limit, power_limit_updated_at
  • READ_CREDIT → kwh_credit_available, is_on, optionally balance_in_local_currency
  • READ_REPORT → same as READ_CREDIT + analytics POST to Yeti API (production only)
  • READ_VERSION → version
  • TOP_UP / CLEAR_CREDIT → no direct field update; triggers READ_CREDIT follow-up

All successful interactions also set last_seen_at on the meter.

Issue auto-closing

The meter's open issue (if any) is evaluated before the DB write and may be closed automatically based on the new meter state.

  • NO_COMMUNICATION — closed when any interaction succeeds and last_seen_at is set
  • NO_CREDIT — closed when resulting credit balance is > 0
  • UNEXPECTED_POWER_LIMIT — closed when power_limit now equals power_limit_should_be

UNEXPECTED_METER_STATUS is never auto-closed by this service.

Commissioning: advance vs resume

Two distinct code paths, selected based on whether the interaction itself belongs to a commissioning flow.

  • advanceActive — interaction has a meter_commissioning_id. Updates commissioning status (PENDING → PROCESSING → SUCCESSFUL), triggers the next deferred command, or marks FAILED and aborts siblings on error.
  • resumeInactive — a normal command succeeds while the meter's last_commissioning is still PENDING. Unpauses deferred commissioning commands.