c62f07bf44f96f1548e8f3f720af1d72791d5309
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
Description
Unified Firmware for the LilyGO T3 v1.6.1 433MHz Version. Sender will read DD3 Smart Meter Data and send it to reciever as well as display on OLED. Reciever will publish to mqtt and show on a local website as well as OLED.
Languages
C++
94.2%
C
5.8%