Remove auto-reboot and make timezone configurable
This commit is contained in:
10
README.md
10
README.md
@@ -9,7 +9,9 @@ Firmware for LilyGO T3 v1.6.1 (`ESP32 + SX1276 + SSD1306`) that runs as either:
|
|||||||
- Single codebase, role selected at boot via `detect_role()` (`include/config.h`, `src/config.cpp`).
|
- Single codebase, role selected at boot via `detect_role()` (`include/config.h`, `src/config.cpp`).
|
||||||
- LoRa link uses explicit CRC16 frame protection in firmware (`src/lora_transport.cpp`).
|
- 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 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`).
|
||||||
- Receiver uses STA mode when config is valid, otherwise AP fallback with web config.
|
- 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.
|
||||||
|
|
||||||
## LoRa Frame Protocol (Current)
|
## LoRa Frame Protocol (Current)
|
||||||
|
|
||||||
@@ -54,12 +56,18 @@ Only after valid ACK time is received:
|
|||||||
|
|
||||||
This blocks pre-threshold timestamps from MQTT/SD paths.
|
This blocks pre-threshold timestamps from MQTT/SD paths.
|
||||||
|
|
||||||
|
Timezone handling:
|
||||||
|
- Local time rendering uses `TIMEZONE_TZ` from `include/config.h`.
|
||||||
|
- Default value is `CET-1CEST,M3.5.0/2,M10.5.0/3` and can be changed at compile time.
|
||||||
|
|
||||||
## Sender Meter Path
|
## Sender Meter Path
|
||||||
|
|
||||||
Implemented in `src/meter_driver.cpp` + sender loop in `src/main.cpp`:
|
Implemented in `src/meter_driver.cpp` + sender loop in `src/main.cpp`:
|
||||||
|
|
||||||
- UART: `Serial2`, RX pin `GPIO34` (`PIN_METER_RX`), `9600 7E1`
|
- UART: `Serial2`, RX pin `GPIO34` (`PIN_METER_RX`), `9600 7E1`
|
||||||
- Frame detection: starts at `'/'`, ends at `'!'`, timeout protection included
|
- 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`).
|
||||||
|
- Parsing runs in a dedicated sender task and is handed to the main sender loop via queue.
|
||||||
- Parsed OBIS values:
|
- Parsed OBIS values:
|
||||||
- `1-0:1.8.0` (total energy)
|
- `1-0:1.8.0` (total energy)
|
||||||
- `1-0:16.7.0` (total power)
|
- `1-0:16.7.0` (total power)
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ constexpr uint16_t SD_HISTORY_MAX_DAYS = 30;
|
|||||||
constexpr uint16_t SD_HISTORY_MIN_RES_MIN = 1;
|
constexpr uint16_t SD_HISTORY_MIN_RES_MIN = 1;
|
||||||
constexpr uint16_t SD_HISTORY_MAX_BINS = 4000;
|
constexpr uint16_t SD_HISTORY_MAX_BINS = 4000;
|
||||||
constexpr uint16_t SD_HISTORY_TIME_BUDGET_MS = 10;
|
constexpr uint16_t SD_HISTORY_TIME_BUDGET_MS = 10;
|
||||||
|
constexpr const char *TIMEZONE_TZ = "CET-1CEST,M3.5.0/2,M10.5.0/3";
|
||||||
constexpr const char *AP_SSID_PREFIX = "DD3-Bridge-";
|
constexpr const char *AP_SSID_PREFIX = "DD3-Bridge-";
|
||||||
constexpr const char *AP_PASSWORD = "changeme123";
|
constexpr const char *AP_PASSWORD = "changeme123";
|
||||||
constexpr bool WEB_AUTH_REQUIRE_STA = true;
|
constexpr bool WEB_AUTH_REQUIRE_STA = true;
|
||||||
|
|||||||
14
src/main.cpp
14
src/main.cpp
@@ -29,8 +29,6 @@ static char g_device_id[16] = "";
|
|||||||
static SenderStatus g_sender_statuses[NUM_SENDERS];
|
static SenderStatus g_sender_statuses[NUM_SENDERS];
|
||||||
static bool g_ap_mode = false;
|
static bool g_ap_mode = false;
|
||||||
static WifiMqttConfig g_cfg;
|
static WifiMqttConfig g_cfg;
|
||||||
static uint32_t g_boot_ms = 0;
|
|
||||||
static bool g_debug_forced_reboot_done = false;
|
|
||||||
static FaultCounters g_sender_faults = {};
|
static FaultCounters g_sender_faults = {};
|
||||||
static FaultCounters g_receiver_faults = {};
|
static FaultCounters g_receiver_faults = {};
|
||||||
static FaultCounters g_receiver_faults_published = {};
|
static FaultCounters g_receiver_faults_published = {};
|
||||||
@@ -121,7 +119,6 @@ static constexpr uint32_t METER_READER_TASK_STACK_WORDS = 4096;
|
|||||||
static constexpr UBaseType_t METER_READER_TASK_PRIORITY = 2;
|
static constexpr UBaseType_t METER_READER_TASK_PRIORITY = 2;
|
||||||
static constexpr BaseType_t METER_READER_TASK_CORE = 0;
|
static constexpr BaseType_t METER_READER_TASK_CORE = 0;
|
||||||
#endif
|
#endif
|
||||||
static constexpr uint32_t DEBUG_FORCED_REBOOT_INTERVAL_MS = 3UL * 60UL * 60UL * 1000UL;
|
|
||||||
|
|
||||||
enum class TxBuildError : uint8_t {
|
enum class TxBuildError : uint8_t {
|
||||||
None = 0,
|
None = 0,
|
||||||
@@ -937,7 +934,6 @@ void setup() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
watchdog_init();
|
watchdog_init();
|
||||||
g_boot_ms = millis();
|
|
||||||
g_role = detect_role();
|
g_role = detect_role();
|
||||||
init_device_ids(g_short_id, g_device_id, sizeof(g_device_id));
|
init_device_ids(g_short_id, g_device_id, sizeof(g_device_id));
|
||||||
display_set_role(g_role);
|
display_set_role(g_role);
|
||||||
@@ -1364,16 +1360,6 @@ receiver_loop_done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (SERIAL_DEBUG_MODE && !g_debug_forced_reboot_done &&
|
|
||||||
(millis() - g_boot_ms >= DEBUG_FORCED_REBOOT_INTERVAL_MS)) {
|
|
||||||
g_debug_forced_reboot_done = true;
|
|
||||||
serial_debug_printf("debug: force reboot after %lu ms uptime",
|
|
||||||
static_cast<unsigned long>(millis() - g_boot_ms));
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
|
||||||
delay(50);
|
|
||||||
esp_restart();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#ifdef ENABLE_TEST_MODE
|
#ifdef ENABLE_TEST_MODE
|
||||||
if (g_role == DeviceRole::Sender) {
|
if (g_role == DeviceRole::Sender) {
|
||||||
test_sender_loop(g_short_id, g_device_id);
|
test_sender_loop(g_short_id, g_device_id);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "time_manager.h"
|
#include "time_manager.h"
|
||||||
|
#include "config.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
static bool g_time_synced = false;
|
static bool g_time_synced = false;
|
||||||
@@ -12,15 +13,20 @@ static void note_last_sync(uint32_t epoch) {
|
|||||||
g_last_sync_utc = epoch;
|
g_last_sync_utc = epoch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ensure_timezone_set() {
|
||||||
|
if (g_tz_set) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setenv("TZ", TIMEZONE_TZ, 1);
|
||||||
|
tzset();
|
||||||
|
g_tz_set = true;
|
||||||
|
}
|
||||||
|
|
||||||
void time_receiver_init(const char *ntp_server_1, const char *ntp_server_2) {
|
void time_receiver_init(const char *ntp_server_1, const char *ntp_server_2) {
|
||||||
const char *server1 = (ntp_server_1 && ntp_server_1[0] != '\0') ? ntp_server_1 : "pool.ntp.org";
|
const char *server1 = (ntp_server_1 && ntp_server_1[0] != '\0') ? ntp_server_1 : "pool.ntp.org";
|
||||||
const char *server2 = (ntp_server_2 && ntp_server_2[0] != '\0') ? ntp_server_2 : "time.nist.gov";
|
const char *server2 = (ntp_server_2 && ntp_server_2[0] != '\0') ? ntp_server_2 : "time.nist.gov";
|
||||||
configTime(0, 0, server1, server2);
|
configTime(0, 0, server1, server2);
|
||||||
if (!g_tz_set) {
|
ensure_timezone_set();
|
||||||
setenv("TZ", "CET-1CEST,M3.5.0/2,M10.5.0/3", 1);
|
|
||||||
tzset();
|
|
||||||
g_tz_set = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t time_get_utc() {
|
uint32_t time_get_utc() {
|
||||||
@@ -40,11 +46,7 @@ bool time_is_synced() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void time_set_utc(uint32_t epoch) {
|
void time_set_utc(uint32_t epoch) {
|
||||||
if (!g_tz_set) {
|
ensure_timezone_set();
|
||||||
setenv("TZ", "CET-1CEST,M3.5.0/2,M10.5.0/3", 1);
|
|
||||||
tzset();
|
|
||||||
g_tz_set = true;
|
|
||||||
}
|
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
tv.tv_sec = epoch;
|
tv.tv_sec = epoch;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user