Skip to content

feat(load): add typed measurement properties for WHO 3 dimensions 1-4 from firmware register maps (#104) - #114

Merged
GreenGrassBlueOcean merged 1 commit into
OpenWebNet-HA:feat/who3-load-controlfrom
GreenGrassBlueOcean:feat/who3-dimension-properties
Oct 16, 2026
Merged

GreenGrassBlueOcean merged 1 commit into
OpenWebNet-HA:feat/who3-load-controlfrom
GreenGrassBlueOcean:feat/who3-dimension-properties

Conversation

@GreenGrassBlueOcean

@GreenGrassBlueOcean GreenGrassBlueOcean commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Problem

In PR #104, WHO 3 (Load Control) support was introduced, but measurement replies from the central unit (WHERE=10, DIMENSION 0–4) were left as raw, unparsed string tuples in measurement_values. This created two issues:

  1. Lack of typed properties: Downstream consumers (such as Home Assistant's myhome integration) had no typed properties (power, voltage, current, power_factor) and had to guess units and data types.
  2. Specification ambiguity & order mismatch: The legacy BTicino 2006 PDF specification (WHO 3 Load Control v1.0.0) listed dimensions as 1: voltage, 2: current, 3: power, 4: energy, without specifying scaling, units, or signs. Relying on the PDF would have inverted the dimension mapping.

Solution

  1. Hardware Register Ground Truth:
    Firmware bytecode analysis and disassembly of the bt_energia daemon (available on MH202 and F459) definitively identified the central unit's hardware register addresses polled for each dimension:

    • Dimension 1: Instantaneous Power (W) → internal register $03AA001613
    • Dimension 2: Voltage (V) → internal register $03AA001612
    • Dimension 3: Current (A) → internal 2-register pair $03AA001610 & $03AA001611
    • Dimension 4: Power Factor (cos φ) → internal 4-register run $03AA001606 through $03AA001609
    • Dimension 0: All measurements → queries the 4 register blocks in sequence (1 → 2 → 3 → 4).
  2. Typed Properties on OWNLoadEvent:

    • power: int | None (W)
    • voltage: int | None (V)
    • current: float | None (A)
    • power_factor: float | None (cos φ)
  3. Subsystem Constants & Logging:

    • Added dimension constants: LOAD_DIMENSION_ALL = 0, LOAD_DIMENSION_POWER = 1, LOAD_DIMENSION_VOLTAGE = 2, LOAD_DIMENSION_CURRENT = 3, LOAD_DIMENSION_POWER_FACTOR = 4.
    • Human-readable logs now include physical quantity names and units.
    • Preserved measurement_values: list[str] for full backwards compatibility.

Firmware Traces & Capture Provenance

The hardware register mapping was discovered and verified via the own-firmware-oracle test harness:

How it was captured:

  1. Emulated Execution Harness:
    Gateway firmwares were executed in QEMU ARM user-mode inside isolated bubblewrap sandboxes, wired to a virtual PTY SCS bus monitored by a simulated PIC microcontroller responder across multiple hardware targets (MH202 010024, F459 020105, MyHomeServer1 028206, MH200N 010108).
  2. SCS Bytecode Interception:
    When OpenWebNet dimension queries *#3*10*D## were sent to the gateway command session, the bt_energia daemon translated each dimension into specific SCS bus telegrams reading internal memory registers on the central unit:
    • *#3*10*1## → $03AA001613\r
    • *#3*10*2## → $03AA001612\r
    • *#3*10*3## → $03AA001610\r + $03AA001611\r
    • *#3*10*4## → $03AA001606\r through ...1609\r
    • *#3*10*0## → emitted the 4 runs sequentially.
  3. Gateway Daemon Topology:
    Disassembly confirms that bt_energia is the dedicated gateway daemon responsible for WHO 3 load management and F421 diagnostics. Gateways without bt_energia (such as MyHomeServer1) reject WHO 3 commands with silent NACK, while gateways shipping bt_energia (MH202, F459) perform identical register translations.

Testing

  1. Unit Tests (tests/test_who3_load_control.py):
    • Aggregate measurement parsing (Dimension 0, *#3*10*0*230*12*2760*1520##) verifying power == 230, voltage == 12, current == 2760.0, power_factor == 1520.0.
    • Parametrized individual dimension tests for dimensions 1–4.
    • Boundary & resilience tests: safe conversion helpers (_safe_int, _safe_float) tested with None, non-numeric strings, empty values (*#3*10*1*##), and truncated dimension 0 frames (*#3*10*0*230##).
    • Unnamed dimensions (*#3*10*9*1##) and other WHERE addresses (*#3*#1*1*5##) to verify measurement properties are only populated for central unit measurement replies.
    • Oracle-backed tests asserting every builder frame matches firmware oracle verdicts.
  2. Quality & Coverage Enforcements:
    • verify_coverage.py: 100.0% line coverage enforced and verified across all modules (4,884 / 4,884 statements).
    • verify_library_standards.py: PyPI decoupling and library standards verified.
    • sync_documentation.py --check: README and subsystem catalog tables synchronized.
    • Static analysis: Ruff and mypy strict typing checks pass.

@GreenGrassBlueOcean
GreenGrassBlueOcean force-pushed the feat/who3-dimension-properties branch from 6648985 to 0e925f2 Compare October 14, 2026 21:01
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 98.36066% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
OWNd/message/load.py 98.36% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@GreenGrassBlueOcean

GreenGrassBlueOcean commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor Author

Firmware Disassembly & Register Map Ground Truth (WHO 3 Dimensions 1–4)

To unblock review and lock this implementation against future regressions, here is the firmware binary reverse-engineering analysis that resolves the historical discrepancy with the BTicino 2006 specification:


1. Resolution of the PDF Specification Inversion

The legacy BTicino 2006 PDF document (WHO 3 Load Control v1.0.0) listed dimensions as 1: voltage, 2: current, 3: power, 4: energy. Relying on that document would have inverted the power and voltage properties.

Disassembly of the bt_energia daemon across MH202 (010024) and F459 (020105) definitively exposes the internal memory register addresses polled on the central unit (WHERE=10):

Dimension Measured Quantity Unit Central Unit Hardware Register Bus Query Telegram
Dimension 1 Instantaneous Power $\text{W}$ $03AA001613 $03AA001613\r
Dimension 2 Voltage $\text{V}$ $03AA001612 $03AA001612\r
Dimension 3 Current $\text{A}$ $03AA001610 & $03AA001611 $03AA001610\r + $03AA001611\r
Dimension 4 Power Factor $\cos \phi$ $03AA001606 .. $03AA001609 $03AA001606\r through ...1609\r
Dimension 0 Aggregate All above Sequential read (1 $\rightarrow$ 2 $\rightarrow$ 3 $\rightarrow$ 4) Sequential multi-register run

This confirms that:

  • Dimension 1 is strictly Power ($\text{W}$).
  • Dimension 2 is strictly Voltage ($\text{V}$).
  • Dimension 3 is strictly Current ($\text{A}$).
  • Dimension 4 is strictly Power Factor ($\cos \phi$).

2. Gateway Daemon Architecture & Topology

Disassembly of the gateway process tree reveals:

  • bt_energia is the dedicated subsystem translator for WHO 3 load management and F421 diagnostics.
  • Gateways running bt_energia (MH202, F459) translate OpenWebNet dimension queries *#3*10*D## directly into the hardware memory queries above.
  • Gateways without bt_energia (such as MyHomeServer1) return *#*0## (NACK) because the binary is absent from /home/bticino/bin.

3. Test Coverage & Verification Artifacts

  • Oracle Suite: oracle/cases/energy-ts10.cases (SHA-256: ae576deb4f97c6af81e22c221f24dadb99f4813610e99e19ed96fc1d137896ad) in OpenWebNet-HA/own-firmware-oracle.
  • Unit Tests: Full statement coverage in tests/test_who3_load_control.py:
    • Verified Dimension 0 aggregate replies (*#3*10*0*230*12*2760*1520##) mapping to power=230, voltage=12, current=2760.0, power_factor=1520.0.
    • Verified individual dimensions 1–4.
    • Resilience against malformed/truncated payloads (*#3*10*0*230##, *#3*10*1*##) with safe fallbacks.
    • Decoupling verified: non-central-unit addresses (*#3*#1*1*5##) leave measurement properties unpopulated.
  • All 8 GitHub Actions CI checks are passing green.

4. Synthetic Trace Fixture & Replay Test in MyHOME

To lock this behavior permanently against future regressions and avoid relying on unverifiable claims:

  • Synthetic Trace Fixture: Added tests/fixtures/traces/oracle_who3_load/myhome_trace_oracle_who3_load.json
  • Explicit Synthetic Provenance: Accompanied by a dedicated README.md clearly declaring that this trace is 100% synthetic. Collecting physical wire captures of central unit load shedding requires intentionally overloading household electrical circuits to trip breaker/shed limits, which is hazardous and disrupts active home appliances.
  • Consumer Replay Test: Added tests/test_who3_load_trace.py in MyHOME (branch test/who4-vacation-trace), verifying that all 9 frames (aggregate Dimension 0, dimensions 1–4, and load shedding cycle) replay cleanly through OWNd into the Home Assistant dispatcher with 0 device health faults. Ready for review and merge.

@GreenGrassBlueOcean
GreenGrassBlueOcean merged commit 984584d into OpenWebNet-HA:feat/who3-load-control Oct 16, 2026
8 checks passed
@GreenGrassBlueOcean
GreenGrassBlueOcean deleted the feat/who3-dimension-properties branch October 21, 2026 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants