docs: update README to current lora-refactor state

This commit is contained in:
2026-02-13 23:54:03 +01:00
parent 5e27e2e7e8
commit 0a2e4e5a68

View File

@@ -10,6 +10,8 @@ Firmware for LilyGO T3 v1.6.1 (`ESP32 + SX1276 + SSD1306`) that runs as either:
- LoRa link uses explicit CRC16 frame protection in firmware (`src/lora_transport.cpp`).
- Sender batches up to `30` samples and retries on missing ACK (`BATCH_MAX_RETRIES=2`, retry policy `Keep`).
- Sender meter parsing is decoupled from LoRa ACK waits using a dedicated FreeRTOS reader task + queue (`src/main.cpp`).
- Batch payload codec is schema v3 and uses a sparse `present_mask` over a 30-second window (no schema v2 compatibility).
- Sender derives epoch timestamps from meter Sekundenindex (`0-0:96.8.0*255`) using an epoch anchor when time is synced.
- Receiver uses STA mode when config is valid, otherwise AP fallback with web config.
- No debug auto-reboot timer is active in normal firmware loops.
@@ -29,11 +31,14 @@ Transport is chunked (`batch_id`, `chunk_index`, `chunk_count`, `total_len`) and
Payload codec (`src/payload_codec.cpp`) currently uses:
- `kMagic=0xDDB3`
- `kSchema=2`
- metadata: sender, batch, timestamp, interval, battery, fault counters
- `kSchema=3`
- metadata: sender, batch, `t_last`, `present_mask`, battery, fault counters
- data arrays: `energy_wh[]`, `p1_w[]`, `p2_w[]`, `p3_w[]`
`n == 0` is valid and used for sync request packets.
`present_mask` is a 30-bit second map in the `[t_last-29, t_last]` window.
Only set bits carry samples, so missing seconds are explicitly represented.
`n == 0` is valid for sync request packets (`present_mask == 0`).
### `AckDown` (7 bytes)
@@ -66,14 +71,21 @@ Implemented in `src/meter_driver.cpp` + sender loop in `src/main.cpp`:
- UART: `Serial2`, RX pin `GPIO34` (`PIN_METER_RX`), `9600 7E1`
- ESP32 RX buffer is enlarged to `8192` bytes to survive long LoRa blocking sections.
- Frame detection: starts at `'/'`, ends at `'!'`, timeout protection included (`METER_FRAME_TIMEOUT_MS=20000`).
- Frame detection: starts at `'/'`, ends at `'!'`, timeout protection included (`METER_FRAME_TIMEOUT_MS=3000`).
- Parsing runs in a dedicated sender task and is handed to the main sender loop via queue.
- Parsed OBIS values:
- `0-0:96.8.0*255` (meter Sekundenindex, 4-byte hex)
- `1-0:1.8.0` (total energy)
- `1-0:16.7.0` (total power)
- `1-0:36.7.0`, `56.7.0`, `76.7.0` (phase powers)
- `1-0:1.8.0*Wh` is automatically scaled to kWh
Timestamping/validation on sender:
- Anchor when time is valid: `epoch_offset = epoch_now - meter_seconds`.
- Derived sample time: `ts_utc = meter_seconds + epoch_offset`.
- Meter-time checks: monotonicity and `delta_meter_seconds` vs elapsed wall time (with tolerance) plus anchor drift checks.
- On detected jump/drift, sender records meter fault and resulting timestamp discontinuities propagate through `present_mask` to receiver.
Sender samples every second and transmits batches every 30 seconds.
## Receiver Behavior
@@ -82,8 +94,9 @@ For valid `BatchUp` decode:
1. Reassemble chunks and decode payload.
2. Send `AckDown` immediately.
3. Drop duplicate batches per sender (`batch_id` tracking).
4. If `n==0`: treat as sync request only.
5. Else convert samples, log to SD, update web UI, publish MQTT.
4. Track duplicate stats per sender: absolute duplicates, total received, duplicate percentage, last duplicate timestamp.
5. If `n==0`: treat as sync request only.
6. Else reconstruct timestamps from `t_last` + `present_mask`, preserving skipped seconds, then log to SD, update web UI, publish MQTT.
## MQTT Topics and Payloads
@@ -109,6 +122,8 @@ Home Assistant discovery is enabled (`ENABLE_HA_DISCOVERY=true`) and publishes c
- AP fallback SSID prefix: `DD3-Bridge-`.
- Default web credentials: `admin/admin`.
- SD logging enabled (`ENABLE_SD_LOGGING=true`).
- Sender-specific web status includes duplicate-batch counters and the last duplicate time.
- Sender-specific OLED page shows duplicate rate as `pct (absolute)` and last duplicate as `HH:MM`.
## Build Environments