Update batch schema and add ACK handling
This commit is contained in:
52
README.md
52
README.md
@@ -45,7 +45,6 @@ Variants:
|
||||
- Energy total: 1-0:1.8.0*255
|
||||
- Total power: 1-0:16.7.0*255
|
||||
- Phase power: 36.7 / 56.7 / 76.7
|
||||
- Phase voltage: 32.7 / 52.7 / 72.7
|
||||
- Reads battery voltage and estimates SoC.
|
||||
- Builds JSON payload, compresses, wraps in LoRa packet, transmits.
|
||||
- Light sleeps between meter reads; batches are sent every 30s.
|
||||
@@ -56,11 +55,11 @@ Variants:
|
||||
**Sender flow (pseudo-code)**:
|
||||
```cpp
|
||||
void sender_loop() {
|
||||
meter_read_every_second(); // SML/OBIS -> MeterData samples
|
||||
meter_read_every_second(); // OBIS -> MeterData samples
|
||||
read_battery(data); // VBAT + SoC
|
||||
|
||||
if (time_to_send_batch()) {
|
||||
json = meterBatchToJson(samples);
|
||||
json = meterBatchToJson(samples, batch_id);
|
||||
compressed = compressBuffer(json);
|
||||
lora_send(packet(MeterBatch, compressed));
|
||||
}
|
||||
@@ -77,7 +76,7 @@ void sender_loop() {
|
||||
|
||||
**Key sender functions**:
|
||||
```cpp
|
||||
bool meter_read(MeterData &data); // parse SML frame, set OBIS fields
|
||||
bool meter_read(MeterData &data); // parse OBIS fields
|
||||
void read_battery(MeterData &data); // ADC -> volts + percent
|
||||
bool meterDataToJson(const MeterData&, String&);
|
||||
bool compressBuffer(const uint8_t*, size_t, uint8_t*, size_t, size_t&);
|
||||
@@ -89,6 +88,7 @@ bool lora_send(const LoraPacket &pkt); // add header + CRC16 and transmit
|
||||
- NTP sync (UTC) and local display in Europe/Berlin.
|
||||
- Receives LoRa packets, verifies CRC16, decompresses, parses JSON.
|
||||
- Publishes meter JSON to MQTT.
|
||||
- Sends ACKs for MeterBatch packets and de-duplicates by batch_id.
|
||||
- Web UI:
|
||||
- AP mode: status + WiFi/MQTT config.
|
||||
- STA mode: status + per-sender pages.
|
||||
@@ -169,7 +169,7 @@ Packet layout:
|
||||
[0] protocol_version (1)
|
||||
[1] role (0=sender, 1=receiver)
|
||||
[2..3] device_id_short (uint16)
|
||||
[4] payload_type (0=meter, 1=test, 2=time_sync, 3=meter_batch)
|
||||
[4] payload_type (0=meter, 1=test, 2=time_sync, 3=meter_batch, 4=ack)
|
||||
[5..N-3] compressed payload
|
||||
[N-2..N-1] CRC16 (bytes 0..N-3)
|
||||
```
|
||||
@@ -190,14 +190,38 @@ JSON payload (sender + MQTT):
|
||||
"p1_w": 500.00,
|
||||
"p2_w": 450.00,
|
||||
"p3_w": 0.00,
|
||||
"v1_v": 230.10,
|
||||
"v2_v": 229.80,
|
||||
"v3_v": 231.00,
|
||||
"bat_v": 3.92,
|
||||
"bat_pct": 78
|
||||
}
|
||||
```
|
||||
|
||||
MeterBatch JSON (compressed over LoRa) uses per-field arrays with integer units for easier ingestion:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema": 1,
|
||||
"sender": "s01",
|
||||
"batch_id": 1842,
|
||||
"t0": 1738288000,
|
||||
"dt_s": 1,
|
||||
"n": 3,
|
||||
"energy_wh": [123456700, 123456701, 123456701],
|
||||
"p_w": [930, 940, 950],
|
||||
"p1_w": [480, 490, 500],
|
||||
"p2_w": [450, 450, 450],
|
||||
"p3_w": [0, 0, 0],
|
||||
"meta": {
|
||||
"rssi": -92,
|
||||
"snr": 7.5,
|
||||
"rx_ts": 1738288031
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
- `sender` maps to `EXPECTED_SENDER_IDS` order (`s01` = first sender).
|
||||
- `meta` is injected by the receiver after batch reassembly.
|
||||
|
||||
## Device IDs
|
||||
- Derived from WiFi STA MAC.
|
||||
- `short_id = (MAC[4] << 8) | MAC[5]`
|
||||
@@ -253,12 +277,20 @@ inline constexpr uint16_t EXPECTED_SENDER_IDS[NUM_SENDERS] = { 0xF19C };
|
||||
- `lilygo-t3-v1-6-1-868`: production build for 868 MHz modules
|
||||
- `lilygo-t3-v1-6-1-868-test`: test build for 868 MHz modules
|
||||
|
||||
## Config Knobs
|
||||
Key timing settings in `include/config.h`:
|
||||
- `METER_SAMPLE_INTERVAL_MS`
|
||||
- `METER_SEND_INTERVAL_MS`
|
||||
- `BATCH_ACK_TIMEOUT_MS`
|
||||
- `BATCH_MAX_RETRIES`
|
||||
|
||||
## Limits & Known Constraints
|
||||
- **Compression**: uses lightweight RLE (good for JSON but not optimal).
|
||||
- **OBIS parsing**: supports IEC 62056-21 ASCII (Mode D) and SML; may need tuning for some meters.
|
||||
- **OBIS parsing**: supports IEC 62056-21 ASCII (Mode D); may need tuning for some meters.
|
||||
- **Payload size**: single JSON frames < 256 bytes (ArduinoJson static doc); batch frames are chunked and reassembled.
|
||||
- **Battery ADC**: uses simple linear calibration constant in `power_manager.cpp`.
|
||||
- **OLED**: no hardware reset line is used (matches working reference).
|
||||
- **Batch ACKs**: sender waits for ACK after a batch and retries up to `BATCH_MAX_RETRIES` with `BATCH_ACK_TIMEOUT_MS` between attempts.
|
||||
|
||||
## Files & Modules
|
||||
- `include/config.h`, `src/config.cpp`: pins, radio settings, sender IDs
|
||||
@@ -266,7 +298,7 @@ inline constexpr uint16_t EXPECTED_SENDER_IDS[NUM_SENDERS] = { 0xF19C };
|
||||
- `include/json_codec.h`, `src/json_codec.cpp`: JSON encode/decode
|
||||
- `include/compressor.h`, `src/compressor.cpp`: RLE compression
|
||||
- `include/lora_transport.h`, `src/lora_transport.cpp`: LoRa packet + CRC
|
||||
- `include/meter_driver.h`, `src/meter_driver.cpp`: IEC 62056-21 ASCII + SML parse
|
||||
- `include/meter_driver.h`, `src/meter_driver.cpp`: IEC 62056-21 ASCII parse
|
||||
- `include/power_manager.h`, `src/power_manager.cpp`: ADC + sleep
|
||||
- `include/time_manager.h`, `src/time_manager.cpp`: NTP + time sync
|
||||
- `include/wifi_manager.h`, `src/wifi_manager.cpp`: NVS config + WiFi
|
||||
|
||||
Reference in New Issue
Block a user