Initial commit
This commit is contained in:
182
src/main.cpp
Normal file
182
src/main.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
#include <Arduino.h>
|
||||
#include "config.h"
|
||||
#include "data_model.h"
|
||||
#include "json_codec.h"
|
||||
#include "compressor.h"
|
||||
#include "lora_transport.h"
|
||||
#include "meter_driver.h"
|
||||
#include "power_manager.h"
|
||||
#include "time_manager.h"
|
||||
#include "wifi_manager.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "web_server.h"
|
||||
#include "display_ui.h"
|
||||
#include "test_mode.h"
|
||||
|
||||
static DeviceRole g_role = DeviceRole::Sender;
|
||||
static uint16_t g_short_id = 0;
|
||||
static char g_device_id[16] = "";
|
||||
|
||||
static SenderStatus g_sender_statuses[NUM_SENDERS];
|
||||
static bool g_ap_mode = false;
|
||||
static WifiMqttConfig g_cfg;
|
||||
static uint32_t g_last_timesync_ms = 0;
|
||||
|
||||
static void init_sender_statuses() {
|
||||
for (uint8_t i = 0; i < NUM_SENDERS; ++i) {
|
||||
g_sender_statuses[i] = {};
|
||||
g_sender_statuses[i].has_data = false;
|
||||
g_sender_statuses[i].last_update_ts_utc = 0;
|
||||
g_sender_statuses[i].last_data.short_id = EXPECTED_SENDER_IDS[i];
|
||||
snprintf(g_sender_statuses[i].last_data.device_id, sizeof(g_sender_statuses[i].last_data.device_id), "dd3-%04X", EXPECTED_SENDER_IDS[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(200);
|
||||
|
||||
g_role = detect_role();
|
||||
init_device_ids(g_short_id, g_device_id, sizeof(g_device_id));
|
||||
|
||||
lora_init();
|
||||
display_init();
|
||||
display_set_role(g_role);
|
||||
display_set_self_ids(g_short_id, g_device_id);
|
||||
|
||||
if (g_role == DeviceRole::Sender) {
|
||||
power_sender_init();
|
||||
meter_init();
|
||||
} else {
|
||||
power_receiver_init();
|
||||
wifi_manager_init();
|
||||
init_sender_statuses();
|
||||
display_set_sender_statuses(g_sender_statuses, NUM_SENDERS);
|
||||
|
||||
bool has_cfg = wifi_load_config(g_cfg);
|
||||
if (has_cfg && wifi_connect_sta(g_cfg)) {
|
||||
g_ap_mode = false;
|
||||
time_receiver_init(g_cfg.ntp_server_1.c_str(), g_cfg.ntp_server_2.c_str());
|
||||
mqtt_init(g_cfg, g_device_id);
|
||||
web_server_set_config(g_cfg);
|
||||
web_server_begin_sta(g_sender_statuses, NUM_SENDERS);
|
||||
} else {
|
||||
g_ap_mode = true;
|
||||
char ap_ssid[32];
|
||||
snprintf(ap_ssid, sizeof(ap_ssid), "DD3-Bridge-%04X", g_short_id);
|
||||
wifi_start_ap(ap_ssid, "changeme123");
|
||||
if (g_cfg.ntp_server_1.isEmpty()) {
|
||||
g_cfg.ntp_server_1 = "pool.ntp.org";
|
||||
}
|
||||
if (g_cfg.ntp_server_2.isEmpty()) {
|
||||
g_cfg.ntp_server_2 = "time.nist.gov";
|
||||
}
|
||||
web_server_set_config(g_cfg);
|
||||
web_server_begin_ap(g_sender_statuses, NUM_SENDERS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sender_cycle() {
|
||||
MeterData data = {};
|
||||
data.short_id = g_short_id;
|
||||
strncpy(data.device_id, g_device_id, sizeof(data.device_id));
|
||||
|
||||
bool meter_ok = meter_read(data);
|
||||
read_battery(data);
|
||||
|
||||
uint32_t now_utc = time_get_utc();
|
||||
data.ts_utc = now_utc > 0 ? now_utc : millis() / 1000;
|
||||
data.valid = meter_ok;
|
||||
|
||||
display_set_last_meter(data);
|
||||
display_set_last_read(meter_ok, data.ts_utc);
|
||||
|
||||
String json;
|
||||
bool json_ok = meterDataToJson(data, json);
|
||||
|
||||
bool tx_ok = false;
|
||||
if (json_ok) {
|
||||
uint8_t compressed[LORA_MAX_PAYLOAD];
|
||||
size_t compressed_len = 0;
|
||||
if (compressBuffer(reinterpret_cast<const uint8_t *>(json.c_str()), json.length(), compressed, sizeof(compressed), compressed_len)) {
|
||||
LoraPacket pkt = {};
|
||||
pkt.protocol_version = PROTOCOL_VERSION;
|
||||
pkt.role = DeviceRole::Sender;
|
||||
pkt.device_id_short = g_short_id;
|
||||
pkt.payload_type = PayloadType::MeterData;
|
||||
pkt.payload_len = compressed_len;
|
||||
memcpy(pkt.payload, compressed, compressed_len);
|
||||
tx_ok = lora_send(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
display_set_last_tx(tx_ok, data.ts_utc);
|
||||
display_tick();
|
||||
|
||||
LoraPacket rx = {};
|
||||
if (lora_receive(rx, 200) && rx.protocol_version == PROTOCOL_VERSION && rx.payload_type == PayloadType::TimeSync) {
|
||||
time_handle_timesync_payload(rx.payload, rx.payload_len);
|
||||
}
|
||||
|
||||
delay(50);
|
||||
go_to_deep_sleep(SENDER_WAKE_INTERVAL_SEC);
|
||||
}
|
||||
|
||||
static void receiver_loop() {
|
||||
LoraPacket pkt = {};
|
||||
if (lora_receive(pkt, 0) && pkt.protocol_version == PROTOCOL_VERSION && pkt.payload_type == PayloadType::MeterData) {
|
||||
uint8_t decompressed[256];
|
||||
size_t decompressed_len = 0;
|
||||
if (decompressBuffer(pkt.payload, pkt.payload_len, decompressed, sizeof(decompressed), decompressed_len)) {
|
||||
decompressed[decompressed_len] = '\0';
|
||||
MeterData data = {};
|
||||
if (jsonToMeterData(String(reinterpret_cast<const char *>(decompressed)), data)) {
|
||||
for (uint8_t i = 0; i < NUM_SENDERS; ++i) {
|
||||
if (pkt.device_id_short == EXPECTED_SENDER_IDS[i]) {
|
||||
data.short_id = pkt.device_id_short;
|
||||
g_sender_statuses[i].last_data = data;
|
||||
g_sender_statuses[i].last_update_ts_utc = data.ts_utc;
|
||||
g_sender_statuses[i].has_data = true;
|
||||
mqtt_publish_state(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_ap_mode && millis() - g_last_timesync_ms > TIME_SYNC_INTERVAL_SEC * 1000UL) {
|
||||
g_last_timesync_ms = millis();
|
||||
time_send_timesync(g_short_id);
|
||||
}
|
||||
|
||||
mqtt_loop();
|
||||
web_server_loop();
|
||||
display_set_receiver_status(g_ap_mode, wifi_is_connected() ? wifi_get_ssid().c_str() : "AP", mqtt_is_connected());
|
||||
display_tick();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
#ifdef ENABLE_TEST_MODE
|
||||
if (g_role == DeviceRole::Sender) {
|
||||
test_sender_loop(g_short_id, g_device_id);
|
||||
display_tick();
|
||||
delay(50);
|
||||
} else {
|
||||
test_receiver_loop(g_sender_statuses, NUM_SENDERS);
|
||||
mqtt_loop();
|
||||
web_server_loop();
|
||||
display_set_receiver_status(g_ap_mode, wifi_is_connected() ? wifi_get_ssid().c_str() : "AP", mqtt_is_connected());
|
||||
display_tick();
|
||||
delay(50);
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (g_role == DeviceRole::Sender) {
|
||||
sender_cycle();
|
||||
} else {
|
||||
receiver_loop();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user