3.3 KiB
3.3 KiB
DD3-LoRa-Bridge-MultiSender
Unified firmware for LilyGO T3 v1.6.1 (ESP32 + SX1276 + SSD1306) running as either:
Sender: reads energy-only values from multiple IEC 62056-21 meters and sends binary batches over LoRa.Receiver: accepts batches, ACKs with optional time, publishes to MQTT/web.
Protocol (minimal)
Frame format:
[msg_kind:1][dev_id_short:2][payload...][crc16:2]
msg_kind:
0:BATCH_UP(Sender -> Receiver)1:ACK_DOWN(Receiver -> Sender)
Removed from protocol:
- protocol version field
- payload type field
- MeterData JSON/compressed LoRa path
- standalone TimeSync packets
CRC16 validation is still required on every frame.
Payloads
1) BATCH_UP
- Uses existing binary batch/chunk transport.
sample_count == 0is valid and meansSYNC_REQUEST.- Payload starts with
schema_id:0: legacy schema (kept for compatibility)1:EnergyMultischema (ts + integer kWh for up to 3 meters)
2) ACK_DOWN (7 bytes)
flags(u8): bit0 =time_validbatch_id(u16, big-endian)epoch_utc(u32, big-endian)
Receiver sets:
time_valid=1only when receiver time is authoritative and sane.- Otherwise
time_valid=0andepoch_utc=0.
Time bootstrap safety
Sender starts with:
g_time_acquired=false- no real sampling/batching
- periodic
SYNC_REQUESTeverySYNC_REQUEST_INTERVAL_MS(default15000ms)
Sender only accepts time from ACK_DOWN if:
time_valid == 1epoch_utc >= 2026-02-01 00:00:00 UTC(MIN_ACCEPTED_EPOCH_UTC = 1769904000)
Only then:
- system time is set
g_time_acquired=true- normal 1 Hz sampling + batch transmit starts
This guarantees no pre-2026-02-01 epoch reaches MQTT or SD/DB paths.
Multi-meter sender mode
- Meter protocol: IEC 62056-21 ASCII Mode D
- UART framing:
9600 7E1 - Extracted OBIS: only total energy
1-0:1.8.0 - Conversion: kWh is sent as integer using
floor(12345.67 -> 12345)
Meter count by build mode
- Debug builds (
SERIAL_DEBUG_MODE=1):METER_COUNT=2- keeps USB serial logs on UART0
- uses UART1 + UART2 for meters
- Prod builds (
SERIAL_DEBUG_MODE=0):METER_COUNT=3- no serial logging
- reclaims UART0 for meter 3 RX
Meter RX pins (TTGO T3 v1.6.1 defaults)
PIN_METER1_RX = GPIO34(UART2 RX)PIN_METER2_RX = GPIO25(UART1 RX)PIN_METER3_RX = GPIO3(UART0 RX, prod only)
All pins are configurable in include/config.h.
Receiver MQTT output (EnergyMulti)
For schema_id=1, MQTT payload includes integer fields:
energy1_kwhenergy2_kwhenergy3_kwh(when meter count is 3)
Receiver behavior
On BATCH_UP:
- Decode batch/chunks.
- Send
ACK_DOWNimmediately. - If
sample_count == 0: treat asSYNC_REQUEST, do not publish MQTT/update stats. - Else decode and publish samples as normal.
Sender/Receiver debug logs (SERIAL_DEBUG_MODE)
Sender:
sync: request tx batch_id=%uack: rx ok batch_id=%u time_valid=%u epoch=%lu set=%uack: timeout batch_id=%u retry=%u
Receiver:
ack: tx batch_id=%u time_valid=%u epoch=%lu samples=%u
Removed hardware dependency
DS3231 RTC support was removed:
- no RTC files
- no RTC init/load/set logic
- no
ENABLE_DS3231flow
Build
pio run -e lilygo-t3-v1-6-1
pio run -e lilygo-t3-v1-6-1-test
pio run -e lilygo-t3-v1-6-1-prod