Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions OWNd/message/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,35 +430,44 @@ def __init__(self, data: str) -> None: # pylint: disable=super-init-not-called
self._match: re.Match[str] | None = None
self._type = "UNKNOWN"
self._human_readable_log = data
self._who: int | None = None
self._where: str | None = None
self._is_valid_message = False

if match := self._ACK.match(self._raw):
self._is_valid_message = True
self._match = match
self._family = "SIGNALING"
self._type = "ACK"
self._human_readable_log = "ACK."
elif match := self._NACK.match(self._raw):
self._is_valid_message = True
self._match = match
self._family = "SIGNALING"
self._type = "NACK"
self._human_readable_log = "NACK."
elif match := self._NONCE.match(self._raw):
self._is_valid_message = True
self._match = match
self._family = "SIGNALING"
self._type = "NONCE"
self._human_readable_log = (
f"Nonce challenge received: {self._match.group(1)}."
)
elif match := self._SHA.match(self._raw):
self._is_valid_message = True
self._match = match
self._family = "SIGNALING"
self._type = f"SHA{'-1' if self._match.group(1) == '1' else '-256'}"
self._human_readable_log = f"SHA{'-1' if self._match.group(1) == '1' else '-256'} challenge received." # pylint: disable=line-too-long
elif match := self._COMMAND_SESSION.match(self._raw):
self._is_valid_message = True
self._match = match
self._family = "SIGNALING"
self._type = "COMMAND_SESSION"
self._human_readable_log = "Command session requested."
elif match := self._EVENT_SESSION.match(self._raw):
self._is_valid_message = True
self._match = match
self._family = "SIGNALING"
self._type = "EVENT_SESSION"
Expand Down
36 changes: 31 additions & 5 deletions tests/golden/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ A declarative conformance suite of OpenWebNet frames providing cross-framework v
|---|---|---|
| **Judge** | Official Legrand PDFs via `openwebnet-mcp` | Validates whether a frame is syntactically legal (its semantics are not authoritative; see Provenance below) |
| **Oracle** | `openwebnet4j` & openHAB binding (by Massimo Valla) | Provides mature reference factory outputs and empirical test vectors |
| **Firmware Translation Oracle** | `own-firmware-oracle` (`tests/golden/firmware_oracle.json`) | Provides hash-pinned empirical verdicts, gateway reply codes, and bus frames from real emulated BTicino/Legrand gateway binaries |
| **SUT** | `OWNd` / `custom_components/myhome` | System Under Test: verified against judge and oracle |

## Provenance: which fixtures may change
Expand Down Expand Up @@ -61,20 +62,45 @@ tools/golden/
MASSI_OUTREACH.md # Community proposal draft for Massi Valla
tests/golden/
corpus.json # Zero-dependency standard library runtime cache
firmware_oracle.json # Hash-pinned empirical verdict index from own-firmware-oracle
tests/
test_golden_conformance.py # Pytest suite running conformance tests
test_firmware_oracle_conformance.py # Pytest suite testing parser resilience against real firmware
docs/
protocol_conformance_matrix.md # Verifiable truth matrix across all 11 subsystems
```

## Firmware Oracle Dataset (`tests/golden/firmware_oracle.json`)

The firmware oracle fixture captures empirical OpenWebNet protocol execution across the BTicino/Legrand gateway fleet generated by `own-firmware-oracle`.

- **Schema Version**: `1.1.0` (Format `1.0.0`)
- **Digest Pin**: `verdicts_sha256`: `438c1c3074042929c01e4b8a22c94bc43391eaef89cdb2b692355e01e8df9072`
- **Total Unique Input Frames**: 303 frames across 17 test suites
- **Total Verdict Rows**: 3,015 empirical verdicts across 9 emulated gateways (335 rows each)
- **Fleet Emulation Status**:
- **9 Emulated**: `F450` (020010), `F453AV` (030014), `F454` (020051), `F459` (020105), `F460` (020012), `F461` (020011), `MH200N` (010108), `MH202` (010024), `MyHomeServer1` (028206).
- **1 Catalogued**: `F455` (010102) verified and catalogued, pending emulation (bare-metal ARM Cortex-M architecture).

### Key Architectural Behaviors & Empirical Insights

1. **State-Dependent Suite Divergence**: 49 (product, frame) pairs produce divergent replies across suites due to prior session state or pre-configured operational modes. For example, MyHomeServer1 accepts central-unit heating (`*4*1*#0##`) with ACK in `ownd-pr82-heating` where heating state was established, but returns NACK in `thermo-central-mode`.
2. **Harness Limitations vs Protocol Dialect**:
- 69 crashes on `F450` occur exclusively in thermo suites because F450 is a BACnet gateway (OPEN-BACnet interface) whose emulated daemon crashes on unsupported WHO 4 commands under QEMU.
- 2 crashes on `MH202` occur on edge frames (`*4*311*1##`, `*4*3201*#0##`).
- 7 timeouts occur in `energy-ts10` where totalizer commands wait for responses from physical energy meters that do not respond on an unsimulated virtual bus.
- These 78 cases represent test-harness limitations and are flagged in the test suite to ensure they are not conflated with genuine gateway protocol dialect.
3. **NACK with SCS Bus Forwarding**: 797 rows return NACK at the command session while echoing the telegram onto the SCS bus (predominantly `F460` with 239 rows and `F461` with 238 rows).
4. **PIC Bus Dispatch vs Actuator Replies**: In energy management, requests like `*#18*51*51##` are accepted (`ack`, `out`) and dispatched to the PIC serial bus (`$06D1A1023350150000\r`). On physical plants with active energy meters, an actuator responds with the dimension value (`*#18*51*51*23791364##`); in the emulator, the forward is verified while no actuator is attached.

## Running Conformance Verification

To validate all YAML fixtures against `schema.json` and synchronize `corpus.json`:
```powershell
& "C:\Users\laurensvdb\Documents\GitHub\MyHOME\.venv\Scripts\python.exe" tools/golden/validate_corpus.py
```bash
python tools/golden/validate_corpus.py
```

To run the automated pytest conformance suite (zero external dependencies required):
```powershell
& "C:\Users\laurensvdb\Documents\GitHub\MyHOME\.venv\Scripts\python.exe" -m pytest tests/test_golden_conformance.py -v
To run the automated pytest conformance suite:
```bash
python -m pytest tests/test_golden_conformance.py tests/test_firmware_oracle_conformance.py -v
```
Loading
Loading