# Current State Assessment date: 2026-07-13 Branch assessed: `lora-refactor` Commit assessed: `def0916 refactor lora payload timing` ## Architecture Verification | Assumption | Status | Evidence | |---|---:|---| | `src/main.cpp` is the thin top-level coordinator. | Verified | Initializes shared services, creates role configs, delegates `loop()` to role objects. | | Sender runtime is owned by `SenderStateMachine`. | Verified | `src/sender_state_machine.h/.cpp` own sender state, queueing, sync, ACK, retry, and sleep loop. | | Receiver runtime is owned by `ReceiverPipeline`. | Verified | `src/receiver_pipeline.h/.cpp` own receive, reassembly, ACK, duplicate, MQTT, SD, and web update flow. | | One firmware image supports both roles. | Verified | `detect_role()` selects role at boot; `loop()` dispatches sender or receiver in one image. | | PlatformIO is the canonical build system. | Verified | `platformio.ini` defines all firmware environments. | | Arduino remains the framework. | Verified | `[env] framework = arduino`. | | pioarduino Espressif platform remains pinned. | Verified | Platform URL is `https://github.com/pioarduino/platform-espressif32/releases/download/51.03.07/platform-espressif32.zip`. | | Existing environments include `production`, `debug`, and `test`. | Verified | `platformio.ini` has exactly those project environments. | | Payload schema v4 is current. | Verified | `lib/dd3_legacy_core/src/payload_codec.cpp` uses `kSchema = 4`; payload tests use schema v4 vectors. | | Existing golden vectors remain relevant. | Verified by inspection | `test/test_payload_codec` contains schema v4 golden vectors. | | Power behavior was changed by this task. | Not changed | This harness task did not edit firmware source. | ## Current Build Configuration - PlatformIO Core observed locally: `6.1.18`. - Expected PlatformIO Core for CI and reproducible verification: `6.1.18`. - PlatformIO emits a local warning that multiple/obsolete cores may be installed: `Obsolete PIO Core v6.1.18 is used (previous was 6.1.19)`. - Board: `ttgo-lora32-v1`. - Framework: Arduino. - Environments: - `production`: serial debug off, light sleep on. - `debug`: serial diagnostics on, real meter and real LoRa. - `test`: `ENABLE_TEST_MODE` and `PAYLOAD_CODEC_TEST`. ## Verification Snapshot - `pio run -e production`: passed; RAM `95588` bytes, flash `1182653` bytes. - `pio run -e debug`: passed; RAM `95628` bytes, flash `1189501` bytes. - `pio run -e test`: passed; RAM `95060` bytes, flash `1182177` bytes. - `pio test -e test --without-uploading --without-testing`: passed compile-only for all seven embedded Unity suites. - `python tools/check_size.py`: passed with current artifact baselines in `docs/engineering/size-baseline.json`. - `python tools/verify.py`: failed only at static analysis; `pio check -e production --fail-on-defect=high` exits 1 because cppcheck fails on the Xtensa C++ toolchain package header. - `pio check -e production --fail-on-defect=high --skip-packages`: also failed because cppcheck reports high defects in third-party ArduinoJson headers under `.pio/libdeps`. - The strict static-analysis failure is intentionally preserved until analyzer scope and third-party dependency policy are reviewed. ## Resolved Dependency Baseline Observed with `pio pkg list` after forcing UTF-8 console output: | Dependency | Configured requirement | Resolved version | |---|---|---:| | pioarduino `platform-espressif32` | release URL `51.03.07` | `51.3.6` | | Arduino ESP32 framework | platform-provided | `3.0.7` | | ESP32 Arduino libs | platform-provided | `5.1.0+sha.632e0c2a9f` | | `sandeepmistry/LoRa` | `^0.8.0` | `0.8.0` | | `bblanchon/ArduinoJson` | `^6.21.5` | `6.21.6` | | `adafruit/Adafruit SSD1306` | `^2.5.9` | `2.5.17` | | `adafruit/Adafruit GFX Library` | `^1.11.9` | `1.12.6` | | `Adafruit BusIO` | transitive | `1.17.4` | | `knolleary/PubSubClient` | `^2.8` | `2.8.0` | | `throwtheswitch/Unity` | `^2.6.1` | `2.6.1` | Proposed exact direct pins for a separate dependency-only commit: ```ini sandeepmistry/LoRa@0.8.0 bblanchon/ArduinoJson@6.21.6 adafruit/Adafruit SSD1306@2.5.17 adafruit/Adafruit GFX Library@1.12.6 knolleary/PubSubClient@2.8.0 throwtheswitch/Unity@2.6.1 ``` ## Hardware and Persistence Contracts - Role pin: `GPIO14`; HIGH is sender, LOW is receiver. - OLED control pin: `GPIO13`. - LoRa defaults in `include/config.h`: 868 MHz, SF12, BW 125 kHz, coding rate 4/5, sync word `0x34`. - Configured sender short ID: `0x6540`; configured receiver short ID: `0x7EB4`. - Preferences namespace: `dd3cfg`. - Preferences keys: `ssid`, `pass`, `mqhost`, `mqport`, `mquser`, `mqpass`, `ntp1`, `ntp2`, `webuser`, `webpass`, `valid`. - CSV current header: `ts_utc,ts_hms_local,p_w,p1_w,p2_w,p3_w,e_kwh,bat_v,bat_pct,rssi,snr,err_m,err_d,err_tx,err_last`. ## Protocol Contracts - LoRa frame: `[msg_kind:1][device_short_id_be:2][payload...][crc16_ccitt_be:2]`. - `LoraMsgKind`: `BatchUp=0`, `AckDown=1`. - `BatchUp` chunk header: `[batch_id_le:2][chunk_index:1][chunk_count:1][total_len_le:2][chunk_payload...]`. - Payload codec: schema v4, magic `0xDDB3`, 30-bit `present_mask`, `n == 0` sync-request support. - `AckDown` payload length: 7 bytes, `[flags:1][batch_id_be:2][epoch_utc_be:4]`. - ACK time is accepted only when `flags bit0` is set and epoch is at least `MIN_ACCEPTED_EPOCH_UTC`. - MQTT state topic: `smartmeter//state`. - MQTT fault topic: `smartmeter//faults`. - Test MQTT topic: `smartmeter//test`. - Home Assistant discovery topic: `homeassistant/sensor///config`. ## Repository Shape - `lib/dd3_legacy_core`: shared legacy logic for data model, HTML utilities, JSON codec, and payload codec. - `lib/dd3_transport_logic`: pure-ish transport helpers for LoRa frame, HA discovery JSON, and batch reassembly. - `test/`: seven embedded Unity suites, compile-only runnable without a board. - `.vscode/`: generated PlatformIO files plus extension recommendations. `.vscode/extensions.json` had pre-existing local modifications before this task. - Existing Gitea configuration: none found before this task. ## Security Assessment Confirmed current behavior: - AP password default is `changeme123`. - Web UI defaults are `admin/admin`. - `WEB_AUTH_REQUIRE_AP` and `WEB_AUTH_REQUIRE_STA` are both `true`. - Wi-Fi, MQTT, NTP, and web-auth credentials are stored through ESP32 Preferences in namespace `dd3cfg`. - The source does not implement LoRa cryptographic authentication; it uses CRC, configured sender/receiver IDs, batch IDs, and ACK rate limiting. - The source contains no OTA implementation or firmware signing path. - No project configuration for secure boot or flash encryption was found. Recommendations are in `docs/engineering/risk-register.md`; authentication, encryption, secure boot, flash encryption, OTA signing, and eFuse changes need a separate approved task.