mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-09-10 19:45:42 +00:00
# Conflicts: # MQTT_INTERNALS.md # build.sh # docs/cli_commands.md # examples/simple_repeater/MyMesh.cpp # examples/simple_repeater/MyMesh.h # examples/simple_repeater/UITask.cpp # examples/simple_room_server/MyMesh.cpp # examples/simple_room_server/MyMesh.h # examples/simple_room_server/UITask.cpp # examples/simple_sensor/SensorMesh.cpp # platformio.ini # scripts/generate_webconfig_html.py # src/MeshCore.h # src/helpers/CommonCLI.cpp # src/helpers/CommonCLI.h # src/helpers/CommonCLI_Observer.cpp # src/helpers/ESP32Board.h # src/helpers/MQTTMessageBuilder.cpp # src/helpers/MQTTPresets.h # src/helpers/NRF52Board.cpp # src/helpers/NRF52Board.h # src/helpers/bridges/MQTTBridge.cpp # src/helpers/bridges/MQTTBridge.h # src/helpers/esp32/WebConfigServer.cpp # src/helpers/esp32/WebConfigServer.h # src/helpers/radiolib/RadioLibWrappers.cpp # src/helpers/radiolib/RadioLibWrappers.h # variants/lilygo_tbeam_SX1262/platformio.ini # variants/lilygo_tbeam_SX1276/platformio.ini # variants/lilygo_tlora_v2_1/platformio.ini # webui/index.html
300 lines
12 KiB
C
300 lines
12 KiB
C
#pragma once
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
// /mqtt_prefs is a raw binary persistence format. Keep the layout-only types
|
|
// independent from CommonCLI so the migration decoder can be tested on the host
|
|
// without pulling in Arduino, filesystem, or radio dependencies.
|
|
#ifdef WITH_MQTT_BRIDGE
|
|
|
|
// Must match MAX_MQTT_SLOTS in MQTTPresets.h. CommonCLI.h enforces that link on
|
|
// firmware builds; keeping this header standalone avoids importing preset data
|
|
// into host migration tests.
|
|
static const int MQTT_PREFS_SLOT_COUNT = 6;
|
|
|
|
// Old MQTT preferences layout (pre-slot firmware) -- used only for migration detection.
|
|
struct OldMQTTPrefs {
|
|
char mqtt_origin[32];
|
|
char mqtt_iata[8];
|
|
uint8_t mqtt_status_enabled;
|
|
uint8_t mqtt_packets_enabled;
|
|
uint8_t mqtt_raw_enabled;
|
|
uint8_t mqtt_tx_enabled;
|
|
uint32_t mqtt_status_interval;
|
|
char wifi_ssid[32];
|
|
char wifi_password[64];
|
|
uint8_t wifi_power_save;
|
|
char timezone_string[32];
|
|
int8_t timezone_offset;
|
|
char mqtt_server[64];
|
|
uint16_t mqtt_port;
|
|
char mqtt_username[32];
|
|
char mqtt_password[64];
|
|
uint8_t mqtt_analyzer_us_enabled;
|
|
uint8_t mqtt_analyzer_eu_enabled;
|
|
char mqtt_owner_public_key[65];
|
|
char mqtt_email[64];
|
|
};
|
|
|
|
// The pre-WiFi-power pre-slot layout has the same frozen size as
|
|
// OldMQTTPrefs, but timezone/server start one byte earlier. A conservative
|
|
// classifier distinguishes meaningful configurations before migration.
|
|
struct PreWifiPowerOldMQTTPrefs {
|
|
char mqtt_origin[32];
|
|
char mqtt_iata[8];
|
|
uint8_t mqtt_status_enabled;
|
|
uint8_t mqtt_packets_enabled;
|
|
uint8_t mqtt_raw_enabled;
|
|
uint8_t mqtt_tx_enabled;
|
|
uint32_t mqtt_status_interval;
|
|
char wifi_ssid[32];
|
|
char wifi_password[64];
|
|
char timezone_string[32];
|
|
int8_t timezone_offset;
|
|
char mqtt_server[64];
|
|
uint16_t mqtt_port;
|
|
char mqtt_username[32];
|
|
char mqtt_password[64];
|
|
uint8_t mqtt_analyzer_us_enabled;
|
|
uint8_t mqtt_analyzer_eu_enabled;
|
|
char mqtt_owner_public_key[65];
|
|
char mqtt_email[64];
|
|
};
|
|
|
|
// MQTT preferences stored separately from NodePrefs to avoid upstream layout
|
|
// conflicts. The full layout is the frozen v1 payload baseline. The prefix
|
|
// before observer settings is also an explicitly supported v1 payload: it was
|
|
// used before the observer fields were appended.
|
|
struct MQTTPrefs {
|
|
char mqtt_origin[32];
|
|
char mqtt_iata[8];
|
|
uint8_t mqtt_status_enabled;
|
|
uint8_t mqtt_packets_enabled;
|
|
uint8_t mqtt_raw_enabled;
|
|
uint8_t mqtt_tx_enabled;
|
|
uint32_t mqtt_status_interval;
|
|
|
|
char wifi_ssid[32];
|
|
char wifi_password[64];
|
|
uint8_t wifi_power_save;
|
|
|
|
char timezone_string[32];
|
|
int8_t timezone_offset;
|
|
|
|
char mqtt_slot_preset[MQTT_PREFS_SLOT_COUNT][24];
|
|
char mqtt_slot_host[MQTT_PREFS_SLOT_COUNT][64];
|
|
uint16_t mqtt_slot_port[MQTT_PREFS_SLOT_COUNT];
|
|
char mqtt_slot_username[MQTT_PREFS_SLOT_COUNT][32];
|
|
char mqtt_slot_password[MQTT_PREFS_SLOT_COUNT][64];
|
|
|
|
char mqtt_owner_public_key[65];
|
|
char mqtt_email[64];
|
|
|
|
char mqtt_slot_token[MQTT_PREFS_SLOT_COUNT][48];
|
|
char mqtt_slot_topic[MQTT_PREFS_SLOT_COUNT][96];
|
|
char mqtt_slot_audience[MQTT_PREFS_SLOT_COUNT][64];
|
|
|
|
uint8_t mqtt_rx_enabled;
|
|
char mqtt_ntp_server[64];
|
|
|
|
uint8_t snmp_enabled;
|
|
char snmp_community[24];
|
|
uint8_t radio_watchdog_minutes;
|
|
uint8_t alert_enabled;
|
|
char alert_psk_hex[33];
|
|
uint16_t alert_wifi_minutes;
|
|
uint16_t alert_mqtt_minutes;
|
|
uint16_t alert_min_interval_min;
|
|
char alert_hashtag[24];
|
|
char alert_region[31];
|
|
|
|
// Neighbors publishing (PSRAM boards only). Appended at the end of the
|
|
// observer tail so a shorter (pre-neighbors) /mqtt_prefs payload from earlier
|
|
// firmware still loads with these defaulting off/24h; keeps the format at
|
|
// VERSION 1. Field order and sizes are kept byte-identical to the flex
|
|
// neighbors build so a /mqtt_prefs written by either firmware is
|
|
// interchangeable (see the offsetof static_asserts below).
|
|
uint8_t mqtt_neighbors_enabled;
|
|
uint32_t mqtt_neighbors_interval;
|
|
};
|
|
|
|
// Neighbor discovery is scheduled with the wrap-safe millis() helpers, whose
|
|
// signed-delta comparison requires intervals below INT32_MAX ms. The 336h
|
|
// (two-week) cap stays comfortably inside that range.
|
|
static const uint32_t MQTT_NEIGHBORS_MIN_INTERVAL_HOURS = 12;
|
|
static const uint32_t MQTT_NEIGHBORS_MAX_INTERVAL_HOURS = 336;
|
|
static const uint32_t MQTT_NEIGHBORS_DEFAULT_INTERVAL_HOURS = 24;
|
|
static const uint32_t MQTT_NEIGHBORS_MIN_INTERVAL_MS = MQTT_NEIGHBORS_MIN_INTERVAL_HOURS * 3600000UL;
|
|
static const uint32_t MQTT_NEIGHBORS_MAX_INTERVAL_MS = MQTT_NEIGHBORS_MAX_INTERVAL_HOURS * 3600000UL;
|
|
static const uint32_t MQTT_NEIGHBORS_DEFAULT_INTERVAL_MS = MQTT_NEIGHBORS_DEFAULT_INTERVAL_HOURS * 3600000UL;
|
|
|
|
// Version-1 has three payload layouts this firmware can decode. Never infer a
|
|
// compatible payload from an arbitrary shorter size: raw prefs have no checksum.
|
|
// - PRE_OBSERVER (2736): stops before the observer tail (snmp_*/alert_*).
|
|
// - PRE_NEIGHBORS (2860): full observer tail, no neighbors fields yet.
|
|
// - FULL (2864): current baseline, with the neighbors tail.
|
|
static const size_t MQTT_PREFS_V1_PRE_OBSERVER_PAYLOAD_SIZE = 2736;
|
|
static const size_t MQTT_PREFS_V1_PRE_NEIGHBORS_PAYLOAD_SIZE = 2860;
|
|
static const size_t MQTT_PREFS_V1_FULL_PAYLOAD_SIZE = 2864;
|
|
|
|
// /mqtt_prefs starts with a self-describing 8-byte header. Headerless files
|
|
// are deployed legacy layouts and continue to be distinguished by size.
|
|
static const uint8_t MQTT_PREFS_MAGIC[4] = {0xF5, 'M', 'Q', 'P'};
|
|
static const uint16_t MQTT_PREFS_VERSION = 1;
|
|
|
|
struct MQTTPrefsHeader {
|
|
uint8_t magic[4];
|
|
uint16_t version;
|
|
uint16_t payload_len;
|
|
};
|
|
|
|
// 3-slot MQTTPrefs layout. Array dimensions changed in the current format, so
|
|
// it must be field-copied rather than read into MQTTPrefs directly.
|
|
struct ThreeSlotMQTTPrefs {
|
|
char mqtt_origin[32];
|
|
char mqtt_iata[8];
|
|
uint8_t mqtt_status_enabled;
|
|
uint8_t mqtt_packets_enabled;
|
|
uint8_t mqtt_raw_enabled;
|
|
uint8_t mqtt_tx_enabled;
|
|
uint32_t mqtt_status_interval;
|
|
char wifi_ssid[32];
|
|
char wifi_password[64];
|
|
uint8_t wifi_power_save;
|
|
char timezone_string[32];
|
|
int8_t timezone_offset;
|
|
char mqtt_slot_preset[3][24];
|
|
char mqtt_slot_host[3][64];
|
|
uint16_t mqtt_slot_port[3];
|
|
char mqtt_slot_username[3][32];
|
|
char mqtt_slot_password[3][64];
|
|
char mqtt_owner_public_key[65];
|
|
char mqtt_email[64];
|
|
uint8_t _legacy_analyzer_us_enabled;
|
|
uint8_t _legacy_analyzer_eu_enabled;
|
|
char _legacy_mqtt_server[64];
|
|
uint16_t _legacy_mqtt_port;
|
|
char _legacy_mqtt_username[32];
|
|
char _legacy_mqtt_password[64];
|
|
char mqtt_slot_token[3][48];
|
|
char mqtt_slot_topic[3][96];
|
|
};
|
|
|
|
// The earlier 3-slot format preceded token/topic fields.
|
|
struct ThreeSlotBaseMQTTPrefs {
|
|
char mqtt_origin[32];
|
|
char mqtt_iata[8];
|
|
uint8_t mqtt_status_enabled;
|
|
uint8_t mqtt_packets_enabled;
|
|
uint8_t mqtt_raw_enabled;
|
|
uint8_t mqtt_tx_enabled;
|
|
uint32_t mqtt_status_interval;
|
|
char wifi_ssid[32];
|
|
char wifi_password[64];
|
|
uint8_t wifi_power_save;
|
|
char timezone_string[32];
|
|
int8_t timezone_offset;
|
|
char mqtt_slot_preset[3][24];
|
|
char mqtt_slot_host[3][64];
|
|
uint16_t mqtt_slot_port[3];
|
|
char mqtt_slot_username[3][32];
|
|
char mqtt_slot_password[3][64];
|
|
char mqtt_owner_public_key[65];
|
|
char mqtt_email[64];
|
|
uint8_t _legacy_analyzer_us_enabled;
|
|
uint8_t _legacy_analyzer_eu_enabled;
|
|
char _legacy_mqtt_server[64];
|
|
uint16_t _legacy_mqtt_port;
|
|
char _legacy_mqtt_username[32];
|
|
char _legacy_mqtt_password[64];
|
|
};
|
|
|
|
// Headerless 6-slot layout shipped to the deployed flex fleet. It retains the
|
|
// removed `_legacy_*` block, so it too is field-copied into MQTTPrefs.
|
|
struct Legacy6SlotMQTTPrefs {
|
|
char mqtt_origin[32];
|
|
char mqtt_iata[8];
|
|
uint8_t mqtt_status_enabled;
|
|
uint8_t mqtt_packets_enabled;
|
|
uint8_t mqtt_raw_enabled;
|
|
uint8_t mqtt_tx_enabled;
|
|
uint32_t mqtt_status_interval;
|
|
char wifi_ssid[32];
|
|
char wifi_password[64];
|
|
uint8_t wifi_power_save;
|
|
char timezone_string[32];
|
|
int8_t timezone_offset;
|
|
char mqtt_slot_preset[MQTT_PREFS_SLOT_COUNT][24];
|
|
char mqtt_slot_host[MQTT_PREFS_SLOT_COUNT][64];
|
|
uint16_t mqtt_slot_port[MQTT_PREFS_SLOT_COUNT];
|
|
char mqtt_slot_username[MQTT_PREFS_SLOT_COUNT][32];
|
|
char mqtt_slot_password[MQTT_PREFS_SLOT_COUNT][64];
|
|
char mqtt_owner_public_key[65];
|
|
char mqtt_email[64];
|
|
uint8_t _legacy_analyzer_us_enabled;
|
|
uint8_t _legacy_analyzer_eu_enabled;
|
|
char _legacy_mqtt_server[64];
|
|
uint16_t _legacy_mqtt_port;
|
|
char _legacy_mqtt_username[32];
|
|
char _legacy_mqtt_password[64];
|
|
char mqtt_slot_token[MQTT_PREFS_SLOT_COUNT][48];
|
|
char mqtt_slot_topic[MQTT_PREFS_SLOT_COUNT][96];
|
|
char mqtt_slot_audience[MQTT_PREFS_SLOT_COUNT][64];
|
|
uint8_t mqtt_rx_enabled;
|
|
char mqtt_ntp_server[64];
|
|
};
|
|
|
|
// Historical headerless 6-slot variants. They share a common prefix but only
|
|
// later files contain the appended audience, RX, and NTP fields.
|
|
static const size_t LEGACY6_BASE_SIZE = 2452;
|
|
static const size_t LEGACY6_AUDIENCE_SIZE = 2836;
|
|
static const size_t LEGACY6_AUDIENCE_RX_SIZE = 2840;
|
|
|
|
// Frozen on-flash layouts; every firmware and native fixture build checks them.
|
|
static_assert(sizeof(MQTTPrefsHeader) == 8, "versioned /mqtt_prefs header must stay 8 bytes");
|
|
static_assert(offsetof(MQTTPrefs, snmp_enabled) == MQTT_PREFS_V1_PRE_OBSERVER_PAYLOAD_SIZE,
|
|
"v1 pre-observer /mqtt_prefs boundary changed");
|
|
static_assert(sizeof(MQTTPrefs) == MQTT_PREFS_V1_FULL_PAYLOAD_SIZE,
|
|
"v1 /mqtt_prefs payload layout changed");
|
|
// Lock the neighbors tail to the flex neighbors build's layout so a /mqtt_prefs
|
|
// written by either firmware is byte-for-byte interchangeable. The enable flag
|
|
// lands in the old struct's zeroed trailing padding (offset 2857), and the
|
|
// interval begins exactly at the pre-neighbors payload size (2860) so a
|
|
// pre-neighbors read stops right before it and the interval keeps its default.
|
|
static_assert(offsetof(MQTTPrefs, mqtt_neighbors_enabled) == 2857,
|
|
"neighbors enable flag must sit at the flex-compatible offset");
|
|
static_assert(offsetof(MQTTPrefs, mqtt_neighbors_interval) == MQTT_PREFS_V1_PRE_NEIGHBORS_PAYLOAD_SIZE,
|
|
"neighbors interval offset must equal the pre-neighbors payload size");
|
|
static_assert(sizeof(OldMQTTPrefs) == 472, "frozen pre-slot /mqtt_prefs layout changed");
|
|
static_assert(sizeof(PreWifiPowerOldMQTTPrefs) == 472, "frozen pre-WiFi-power /mqtt_prefs layout changed");
|
|
static_assert(offsetof(OldMQTTPrefs, wifi_power_save) == 144,
|
|
"frozen post-WiFi-power discriminator offset changed");
|
|
static_assert(offsetof(OldMQTTPrefs, timezone_string) == 145,
|
|
"frozen post-WiFi-power timezone offset changed");
|
|
static_assert(offsetof(OldMQTTPrefs, timezone_offset) == 177,
|
|
"frozen post-WiFi-power UTC offset changed");
|
|
static_assert(offsetof(OldMQTTPrefs, mqtt_server) == 178,
|
|
"frozen post-WiFi-power server offset changed");
|
|
static_assert(offsetof(PreWifiPowerOldMQTTPrefs, timezone_string) == 144,
|
|
"frozen pre-WiFi-power timezone offset changed");
|
|
static_assert(offsetof(PreWifiPowerOldMQTTPrefs, timezone_offset) == 176,
|
|
"frozen pre-WiFi-power UTC offset changed");
|
|
static_assert(offsetof(PreWifiPowerOldMQTTPrefs, mqtt_server) == 177,
|
|
"frozen pre-WiFi-power server offset changed");
|
|
static_assert(sizeof(ThreeSlotBaseMQTTPrefs) == 1032, "frozen early 3-slot /mqtt_prefs layout changed");
|
|
static_assert(sizeof(ThreeSlotMQTTPrefs) == 1464, "frozen 3-slot /mqtt_prefs layout changed");
|
|
static_assert(offsetof(ThreeSlotMQTTPrefs, mqtt_slot_token) == 1030,
|
|
"frozen 3-slot token offset changed");
|
|
static_assert(offsetof(ThreeSlotMQTTPrefs, mqtt_slot_topic) == 1174,
|
|
"frozen 3-slot topic offset changed");
|
|
static_assert(offsetof(Legacy6SlotMQTTPrefs, mqtt_slot_audience) == LEGACY6_BASE_SIZE,
|
|
"frozen early 6-slot /mqtt_prefs prefix changed");
|
|
static_assert(offsetof(Legacy6SlotMQTTPrefs, mqtt_rx_enabled) == LEGACY6_AUDIENCE_SIZE,
|
|
"frozen audience 6-slot /mqtt_prefs prefix changed");
|
|
static_assert(offsetof(Legacy6SlotMQTTPrefs, mqtt_ntp_server) == 2837,
|
|
"frozen RX 6-slot /mqtt_prefs prefix changed");
|
|
static_assert(sizeof(Legacy6SlotMQTTPrefs) == 2904, "frozen deployed-fleet /mqtt_prefs layout changed");
|
|
|
|
#endif // WITH_MQTT_BRIDGE
|