initial commit to add MQTT observer support to Room Servers

This commit is contained in:
agessaman committed 2026-01-02 13:36:41 -08:00
1 parent bffbbb762b
commit 0cd0c36ab9
9 files changed
+290 -4

No files matched your search

+92 -1
View File
@@ -198,9 +198,23 @@ void MyMesh::logRxRaw(float snr, float rssi, const uint8_t raw[], int len) {
mesh::Utils::printHex(Serial, raw, len);
Serial.println();
#endif
#ifdef WITH_MQTT_BRIDGE
if (_prefs.bridge_enabled) {
// Store raw radio data for MQTT messages (same as repeater)
bridge.storeRawRadioData(raw, len, snr, rssi);
}
#endif
}
void MyMesh::logRx(mesh::Packet *pkt, int len, float score) {
#ifdef WITH_MQTT_BRIDGE
if (_prefs.bridge_enabled && _prefs.bridge_pkt_src == 1) {
// Log received packets to MQTT (same as repeater)
bridge.onPacketReceived(pkt);
}
#endif
if (_logging) {
File f = openAppend(PACKET_LOG_FILE);
if (f) {
@@ -220,6 +234,13 @@ void MyMesh::logRx(mesh::Packet *pkt, int len, float score) {
}
}
void MyMesh::logTx(mesh::Packet *pkt, int len) {
#ifdef WITH_MQTT_BRIDGE
if (_prefs.bridge_enabled && _prefs.bridge_pkt_src == 0) {
// Log transmitted packets to MQTT (same as repeater)
bridge.sendPacket(pkt);
}
#endif
if (_logging) {
File f = openAppend(PACKET_LOG_FILE);
if (f) {
@@ -587,7 +608,11 @@ void MyMesh::onAckRecv(mesh::Packet *packet, uint32_t ack_crc) {
MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondClock &ms, mesh::RNG &rng,
mesh::RTCClock &rtc, mesh::MeshTables &tables)
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables),
_cli(board, rtc, sensors, &_prefs, this), telemetry(MAX_PACKET_PAYLOAD - 4) {
_cli(board, rtc, sensors, &_prefs, this), telemetry(MAX_PACKET_PAYLOAD - 4)
#ifdef WITH_MQTT_BRIDGE
, bridge(&_prefs, _mgr, &rtc, &self_id)
#endif
{
last_millis = 0;
uptime_millis = 0;
next_local_advert = next_flood_advert = 0;
@@ -624,6 +649,34 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs.gps_interval = 0;
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
// bridge defaults (same as repeater)
_prefs.bridge_enabled = 1; // enabled
_prefs.bridge_delay = 500; // milliseconds
_prefs.bridge_pkt_src = 1; // logRx (RX packets)
_prefs.bridge_baud = 115200; // baud rate
_prefs.bridge_channel = 1; // channel 1
// MQTT defaults (same as repeater)
StrHelper::strncpy(_prefs.mqtt_origin, "MeshCore-RoomServer", sizeof(_prefs.mqtt_origin));
StrHelper::strncpy(_prefs.mqtt_iata, "SEA", sizeof(_prefs.mqtt_iata));
_prefs.mqtt_status_enabled = 1; // enabled
_prefs.mqtt_packets_enabled = 1; // enabled
_prefs.mqtt_raw_enabled = 0; // disabled
_prefs.mqtt_tx_enabled = 0; // disabled (RX only for now)
_prefs.mqtt_status_interval = 300000; // 5 minutes
// WiFi defaults (same as repeater)
StrHelper::strncpy(_prefs.wifi_ssid, "ssid_here", sizeof(_prefs.wifi_ssid));
StrHelper::strncpy(_prefs.wifi_password, "password_here", sizeof(_prefs.wifi_password));
// Timezone defaults (same as repeater - Pacific Time with DST support)
StrHelper::strncpy(_prefs.timezone_string, "America/Los_Angeles", sizeof(_prefs.timezone_string));
_prefs.timezone_offset = -8; // fallback
// Let's Mesh Analyzer defaults (same as repeater - both enabled by default)
_prefs.mqtt_analyzer_us_enabled = 1; // enabled
_prefs.mqtt_analyzer_eu_enabled = 1; // enabled
next_post_idx = 0;
next_client_idx = 0;
next_push = 0;
@@ -650,6 +703,41 @@ void MyMesh::begin(FILESYSTEM *fs) {
#if ENV_INCLUDE_GPS == 1
applyGpsPrefs();
#endif
#ifdef WITH_MQTT_BRIDGE
// Ensure analyzer servers are enabled by default (in case no prefs were loaded) - same as repeater
if (_prefs.mqtt_analyzer_us_enabled == 0 && _prefs.mqtt_analyzer_eu_enabled == 0) {
_prefs.mqtt_analyzer_us_enabled = 1; // enabled
_prefs.mqtt_analyzer_eu_enabled = 1; // enabled
MESH_DEBUG_PRINTLN("Setting analyzer servers to enabled by default");
}
// Set MQTT origin to actual device name (not build-time ADVERT_NAME) - same as repeater
StrHelper::strncpy(_prefs.mqtt_origin, _prefs.node_name, sizeof(_prefs.mqtt_origin));
MESH_DEBUG_PRINTLN("MQTT origin set to device name: %s", _prefs.mqtt_origin);
if (_prefs.bridge_enabled) {
// Set device public key for MQTT topics (same as repeater)
char device_id[65];
mesh::LocalIdentity self_id = getSelfId();
mesh::Utils::toHex(device_id, self_id.pub_key, PUB_KEY_SIZE);
MESH_DEBUG_PRINTLN("Setting device ID: %s", device_id);
bridge.setDeviceID(device_id);
// Set firmware version (same as repeater)
bridge.setFirmwareVersion(getFirmwareVer());
// Set board model (same as repeater)
bridge.setBoardModel(_cli.getBoard()->getManufacturerName());
// Set build date (same as repeater)
bridge.setBuildDate(getBuildDate());
// Set stats sources for automatic stats collection (same as repeater)
bridge.setStatsSources(this, _radio, _cli.getBoard(), _ms);
bridge.begin();
}
#endif
}
void MyMesh::applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr, int timeout_mins) {
@@ -807,6 +895,9 @@ bool MyMesh::saveFilter(ClientInfo* client) {
void MyMesh::loop() {
mesh::Mesh::loop();
#ifdef WITH_MQTT_BRIDGE
bridge.loop();
#endif
if (millisHasNowPassed(next_push) && acl.getNumClients() > 0) {
// check for ACK timeouts
+8
View File
@@ -23,6 +23,11 @@
#include <RTClib.h>
#include <target.h>
#ifdef WITH_MQTT_BRIDGE
#include "helpers/bridges/MQTTBridge.h"
#define WITH_BRIDGE
#endif
/* ------------------------------ Config -------------------------------- */
#ifndef FIRMWARE_BUILD_DATE
@@ -110,6 +115,9 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
uint8_t pending_sf;
uint8_t pending_cr;
int matching_peer_indexes[MAX_CLIENTS];
#ifdef WITH_MQTT_BRIDGE
MQTTBridge bridge;
#endif
void addPost(ClientInfo* client, const char* postData);
void pushPostToClient(ClientInfo* client, PostInfo& post);
+2 -3
View File
@@ -638,20 +638,19 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
sprintf(reply, "> %s", _prefs->mqtt_analyzer_us_enabled ? "on" : "off");
} else if (memcmp(config, "mqtt.analyzer.eu", 17) == 0) {
sprintf(reply, "> %s", _prefs->mqtt_analyzer_eu_enabled ? "on" : "off");
} else if (memcmp(config, "mqtt.owner", 10) == 0) {
} else if (sender_timestamp == 0 && memcmp(config, "mqtt.owner", 10) == 0) { // from serial command line only
if (_prefs->mqtt_owner_public_key[0] != '\0') {
sprintf(reply, "> %s", _prefs->mqtt_owner_public_key);
} else {
strcpy(reply, "> (not set)");
}
} else if (memcmp(config, "mqtt.email", 10) == 0) {
} else if (sender_timestamp == 0 && memcmp(config, "mqtt.email", 10) == 0) { // from serial command line only
if (_prefs->mqtt_email[0] != '\0') {
sprintf(reply, "> %s", _prefs->mqtt_email);
} else {
strcpy(reply, "> (not set)");
}
} else if (memcmp(config, "mqtt.config.valid", 17) == 0) {
// Check if MQTT configuration is valid using static method
bool valid = MQTTBridge::isConfigValid(_prefs);
sprintf(reply, "> %s", valid ? "valid" : "invalid");
#endif
+32
View File
@@ -163,6 +163,38 @@ lib_deps =
${Heltec_lora32_v3.lib_deps}
${esp32_ota.lib_deps}
[env:Heltec_v3_room_server_observer_mqtt]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"Heltec Room Observer"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
-D WITH_MQTT_BRIDGE=1
-D MAX_MQTT_BROKERS=3
-D MQTT_MAX_PACKET_SIZE=1024
; -D MQTT_DEBUG=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
-D CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<helpers/bridges/MQTTBridge.cpp>
+<helpers/MQTTMessageBuilder.cpp>
+<helpers/JWTHelper.cpp>
+<../examples/simple_room_server>
lib_deps =
${Heltec_lora32_v3.lib_deps}
${esp32_ota.lib_deps}
elims/PsychicMqttClient@^0.2.4
bblanchon/ArduinoJson
arduino-libraries/NTPClient
JChristensen/Timezone
paulstoffregen/Time
[env:Heltec_v3_terminal_chat]
extends = Heltec_lora32_v3
build_flags =
+32
View File
@@ -127,6 +127,38 @@ lib_deps =
JChristensen/Timezone
paulstoffregen/Time
[env:heltec_v4_room_server_observer_mqtt]
extends = Heltec_lora32_v4
build_flags =
${Heltec_lora32_v4.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"Heltec Room Observer"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
-D WITH_MQTT_BRIDGE=1
-D MAX_MQTT_BROKERS=3
-D MQTT_MAX_PACKET_SIZE=1024
; -D MQTT_DEBUG=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
-D CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
build_src_filter = ${Heltec_lora32_v4.build_src_filter}
+<helpers/bridges/MQTTBridge.cpp>
+<helpers/MQTTMessageBuilder.cpp>
+<helpers/JWTHelper.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../examples/simple_room_server>
lib_deps =
${Heltec_lora32_v4.lib_deps}
${esp32_ota.lib_deps}
elims/PsychicMqttClient@^0.2.4
bblanchon/ArduinoJson
arduino-libraries/NTPClient
JChristensen/Timezone
paulstoffregen/Time
[env:heltec_v4_room_server]
extends = Heltec_lora32_v4
build_flags =
+32
View File
@@ -136,6 +136,38 @@ lib_deps =
JChristensen/Timezone
paulstoffregen/Time
[env:LilyGo_T3S3_sx1262_room_server_observer_mqtt]
extends = LilyGo_T3S3_sx1262
build_flags =
${LilyGo_T3S3_sx1262.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"T3S3-1262 Room Observer"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
-D WITH_MQTT_BRIDGE=1
-D MAX_MQTT_BROKERS=3
-D MQTT_MAX_PACKET_SIZE=1024
; -D MQTT_DEBUG=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
-D CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter}
+<helpers/bridges/MQTTBridge.cpp>
+<helpers/MQTTMessageBuilder.cpp>
+<helpers/JWTHelper.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../examples/simple_room_server>
lib_deps =
${LilyGo_T3S3_sx1262.lib_deps}
${esp32_ota.lib_deps}
elims/PsychicMqttClient@^0.2.4
bblanchon/ArduinoJson
arduino-libraries/NTPClient
JChristensen/Timezone
paulstoffregen/Time
[env:LilyGo_T3S3_sx1262_terminal_chat]
extends = LilyGo_T3S3_sx1262
build_flags =
@@ -130,6 +130,36 @@ lib_deps =
JChristensen/Timezone
paulstoffregen/Time
[env:T_Beam_S3_Supreme_SX1262_room_server_observer_mqtt]
extends = T_Beam_S3_Supreme_SX1262
build_flags =
${T_Beam_S3_Supreme_SX1262.build_flags}
-D ADVERT_NAME='"T_Beam_S3_Supreme_SX1262 Room Observer"'
-D ADVERT_LAT=0
-D ADVERT_LON=0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
-D WITH_MQTT_BRIDGE=1
-D MAX_MQTT_BROKERS=3
-D MQTT_MAX_PACKET_SIZE=1024
; -D MQTT_DEBUG=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
-D CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
build_src_filter = ${T_Beam_S3_Supreme_SX1262.build_src_filter}
+<helpers/bridges/MQTTBridge.cpp>
+<helpers/MQTTMessageBuilder.cpp>
+<helpers/JWTHelper.cpp>
+<../examples/simple_room_server>
lib_deps =
${T_Beam_S3_Supreme_SX1262.lib_deps}
${esp32_ota.lib_deps}
elims/PsychicMqttClient@^0.2.4
bblanchon/ArduinoJson
arduino-libraries/NTPClient
JChristensen/Timezone
paulstoffregen/Time
[env:T_Beam_S3_Supreme_SX1262_room_server]
extends = T_Beam_S3_Supreme_SX1262
build_flags =
+32
View File
@@ -169,6 +169,38 @@ lib_deps =
${Station_G2.lib_deps}
${esp32_ota.lib_deps}
[env:Station_G2_room_server_observer_mqtt]
extends = Station_G2
board_build.partitions = default_16MB.csv ; standard 16MB partition table
build_flags =
${Station_G2.build_flags}
-D ADVERT_NAME='"Station G2 Room Observer"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
-D WITH_MQTT_BRIDGE=1
-D MAX_MQTT_BROKERS=3
-D MQTT_MAX_PACKET_SIZE=1024
; -D MQTT_DEBUG=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
-D CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
build_src_filter = ${Station_G2.build_src_filter}
+<helpers/bridges/MQTTBridge.cpp>
+<helpers/MQTTMessageBuilder.cpp>
+<helpers/JWTHelper.cpp>
+<helpers/ui/SH1106Display.cpp>
+<../examples/simple_room_server>
lib_deps =
${Station_G2.lib_deps}
${esp32_ota.lib_deps}
elims/PsychicMqttClient@^0.2.4
bblanchon/ArduinoJson
arduino-libraries/NTPClient
JChristensen/Timezone
paulstoffregen/Time
[env:Station_G2_room_server]
extends = Station_G2
build_src_filter = ${Station_G2.build_src_filter}
+30
View File
@@ -132,6 +132,36 @@ lib_deps =
JChristensen/Timezone
paulstoffregen/Time
[env:Xiao_S3_WIO_room_server_observer_mqtt]
extends = Xiao_S3_WIO
build_flags =
${Xiao_S3_WIO.build_flags}
-D ADVERT_NAME='"XiaoS3 Room Observer"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
-D WITH_MQTT_BRIDGE=1
-D MAX_MQTT_BROKERS=3
-D MQTT_MAX_PACKET_SIZE=1024
; -D MQTT_DEBUG=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
-D CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
build_src_filter = ${Xiao_S3_WIO.build_src_filter}
+<helpers/bridges/MQTTBridge.cpp>
+<helpers/MQTTMessageBuilder.cpp>
+<helpers/JWTHelper.cpp>
+<../examples/simple_room_server>
lib_deps =
${Xiao_S3_WIO.lib_deps}
${esp32_ota.lib_deps}
elims/PsychicMqttClient@^0.2.4
bblanchon/ArduinoJson
arduino-libraries/NTPClient
JChristensen/Timezone
paulstoffregen/Time
[env:Xiao_S3_WIO_room_server]
extends = Xiao_S3_WIO
build_src_filter = ${Xiao_S3_WIO.build_src_filter}