@alteriom/painlessmesh 1.8.14 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BRIDGE_TO_INTERNET.md +229 -0
- package/CHANGELOG.md +89 -1
- package/CONTRIBUTING.md +79 -0
- package/README.md +70 -143
- package/docs/README.md +1 -0
- package/docs/api/shared-gateway.md +1207 -0
- package/docs/troubleshooting/common-issues.md +28 -0
- package/docs/troubleshooting/faq.md +113 -12
- package/examples/basic/test/simulator/CMakeLists.txt +40 -0
- package/examples/basic/test/simulator/README.md +149 -0
- package/examples/basic/test/simulator/firmware/basic_firmware.hpp +117 -0
- package/examples/basic/test/simulator/scenarios/basic_mesh_test.yaml +81 -0
- package/examples/bridge/bridge.ino +17 -4
- package/examples/bridge_failover/README.md +81 -0
- package/examples/bridge_failover/bridge_failover.ino +51 -6
- package/examples/sharedGateway/README.md +235 -0
- package/examples/{meshCommandNode → sharedGateway}/platformio.ini +3 -2
- package/examples/sharedGateway/sharedGateway.ino +303 -0
- package/library.json +3 -22
- package/library.properties +1 -1
- package/package.json +3 -3
- package/src/arduino/wifi.hpp +380 -13
- package/src/painlessmesh/gateway.hpp +2120 -0
- package/src/painlessmesh/mesh.hpp +1034 -6
- package/src/painlessmesh/message_tracker.hpp +311 -0
- package/src/painlessmesh/protocol.hpp +6 -0
- package/DOCUMENTATION_INDEX.md +0 -146
- package/docs/API_DESIGN_GUIDELINES.md +0 -414
- package/docs/ARDUINO_LIBRARY_MANAGER_SUBMISSION.md +0 -331
- package/docs/BOOLEAN_NAMING_CONVENTION.md +0 -235
- package/docs/BRIDGE_FAILOVER.md +0 -512
- package/docs/BRIDGE_HEALTH_MONITORING.md +0 -293
- package/docs/CHANNEL_SYNCHRONIZATION.md +0 -209
- package/docs/CREATE_MISSING_RELEASES.md +0 -321
- package/docs/DOCUMENTATION_MIGRATION_PLAN.md +0 -176
- package/docs/FAQ_VERSION_NUMBERS.md +0 -152
- package/docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md +0 -1062
- package/docs/MESH_TOPOLOGY_GUIDE.md +0 -992
- package/docs/MESH_TOPOLOGY_PROGRESS.md +0 -422
- package/docs/MQTT_BRIDGE_COMMANDS.md +0 -894
- package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +0 -324
- package/docs/MQTT_COMMAND_SCHEMA_PROPOSAL.md +0 -576
- package/docs/MQTT_SCHEMA_COMPLIANCE.md +0 -340
- package/docs/MQTT_SCHEMA_PROPOSALS.md +0 -446
- package/docs/MQTT_SCHEMA_REVIEW.md +0 -690
- package/docs/OTA_COMMANDS_REFERENCE.md +0 -554
- package/docs/PHASE1_GUIDE.md +0 -349
- package/docs/PHASE2_GUIDE.md +0 -543
- package/docs/QUICK_REFERENCE_VERSIONING.md +0 -127
- package/docs/RELEASE_AGENT_SUMMARY.md +0 -386
- package/docs/SCHEMA_VALIDATION_CHECKLIST.md +0 -222
- package/docs/VERSION_MANAGEMENT.md +0 -213
- package/docs/archive/DOCUSAURUS_DEPLOYMENT.md +0 -166
- package/docs/archive/FEATURE_PROPOSALS.md +0 -337
- package/docs/archive/LIBRARY_JSON_FIX.md +0 -98
- package/docs/archive/LIBRARY_STRUCTURE_FIX.md +0 -215
- package/docs/archive/PHASE1_IMPLEMENTATION.md +0 -325
- package/docs/archive/PHASE2_IMPLEMENTATION.md +0 -567
- package/docs/archive/RELEASE_SUMMARY.md +0 -173
- package/docs/archive/SCONS_BUILD_FIX.md +0 -313
- package/docs/archive/TRIGGER_RELEASE.md +0 -280
- package/docs/archive/VECTOR_INCLUDE_FIX.md +0 -129
- package/docs/archive/ota-and-status-enhancements.md +0 -911
- package/docs/archive/ota-status-architecture-diagrams.md +0 -658
- package/docs/archive/ota-status-quick-reference.md +0 -284
- package/docs/design/.gitkeep +0 -1
- package/docs/design/STATION_CREDENTIALS_DESIGN.md +0 -182
- package/docs/development/ARDUINO_COMPLIANCE_SUMMARY.md +0 -71
- package/docs/development/CODE_REFACTORING_RECOMMENDATIONS.md +0 -1011
- package/docs/development/DOCKER_TESTING.md +0 -196
- package/docs/development/PLATFORMIO_USAGE.md +0 -180
- package/docs/development/TESTING_SUMMARY.md +0 -126
- package/docs/development/contributing.md +0 -301
- package/docs/development/documentation.md +0 -583
- package/docs/features/DIAGNOSTICS_API.md +0 -534
- package/docs/implementation/BRIDGE_ARCHITECTURE_IMPLEMENTATION.md +0 -340
- package/docs/implementation/BRIDGE_HEALTH_MONITORING_IMPLEMENTATION.md +0 -213
- package/docs/implementation/BRIDGE_STATUS_FEATURE.md +0 -635
- package/docs/implementation/DIAGNOSTICS_API_IMPLEMENTATION.md +0 -232
- package/docs/implementation/IMPLEMENTATION_COMPLETE.md +0 -228
- package/docs/implementation/IMPLEMENTATION_NTP_TIME_SYNC.md +0 -325
- package/docs/implementation/IMPLEMENTATION_SUMMARY.md +0 -316
- package/docs/implementation/MESSAGE_QUEUE_IMPLEMENTATION.md +0 -405
- package/docs/implementation/MULTI_BRIDGE_IMPLEMENTATION.md +0 -520
- package/docs/implementation/NTP_TIME_SYNC_FEATURE.md +0 -392
- package/docs/improvements/FUTURE_PROPOSALS.md +0 -1016
- package/docs/improvements/IMPLEMENTATION_HISTORY.md +0 -1091
- package/docs/improvements/OTA_STATUS_ENHANCEMENTS.md +0 -709
- package/docs/improvements/README.md +0 -212
- package/docs/internal/CUSTOM_AGENT_ANALYSIS.md +0 -391
- package/docs/internal/ISSUE_65_VERIFICATION.md +0 -947
- package/docs/internal/ISSUE_66_CLOSURE.md +0 -249
- package/docs/internal/ISSUE_66_STATUS.md +0 -316
- package/docs/internal/PR_SUMMARY.md +0 -315
- package/docs/internal/REVIEW_SUMMARY.md +0 -332
- package/docs/multi-bridge-setup.md +0 -1025
- package/docs/platformio-publishing.md +0 -255
- package/docs/platformio-setup-summary.md +0 -121
- package/docs/releases/ANNOUNCEMENT_v1.8.6.md +0 -63
- package/docs/releases/ANNOUNCEMENT_v1.8.7.md +0 -113
- package/docs/releases/BRIDGE_STATUS_SELF_REGISTRATION_FIX.md +0 -221
- package/docs/releases/FEATURE_HISTORY.md +0 -543
- package/docs/releases/GITHUB_RELEASE_v1.8.6.md +0 -71
- package/docs/releases/GITHUB_RELEASE_v1.8.7.md +0 -90
- package/docs/releases/PATCH_v1.7.2.md +0 -262
- package/docs/releases/PATCH_v1.7.3.md +0 -262
- package/docs/releases/PATCH_v1.7.4.md +0 -219
- package/docs/releases/PHASE1_SUMMARY.md +0 -246
- package/docs/releases/PHASE2_SUMMARY.md +0 -499
- package/docs/releases/PUBLISH_v1.8.0_INSTRUCTIONS.md +0 -163
- package/docs/releases/QUICK_START_RELEASES.md +0 -113
- package/docs/releases/RELEASE_CHECKLIST_1.8.10.md +0 -331
- package/docs/releases/RELEASE_CHECKLIST_1.8.9.md +0 -207
- package/docs/releases/RELEASE_CHECKLIST_v1.7.4.md +0 -253
- package/docs/releases/RELEASE_CHECKLIST_v1.7.5.md +0 -315
- package/docs/releases/RELEASE_CHECKLIST_v1.7.6.md +0 -389
- package/docs/releases/RELEASE_CHECKLIST_v1.8.0.md +0 -331
- package/docs/releases/RELEASE_CHECKLIST_v1.8.2.md +0 -309
- package/docs/releases/RELEASE_NOTES_1.7.0.md +0 -539
- package/docs/releases/RELEASE_NOTES_1.8.10.md +0 -239
- package/docs/releases/RELEASE_NOTES_1.8.9.md +0 -213
- package/docs/releases/RELEASE_NOTES_v1.8.0.md +0 -685
- package/docs/releases/RELEASE_NOTES_v1.8.1.md +0 -221
- package/docs/releases/RELEASE_NOTES_v1.8.2.md +0 -421
- package/docs/releases/RELEASE_NOTES_v1.8.3.md +0 -292
- package/docs/releases/RELEASE_NOTES_v1.8.4.md +0 -277
- package/docs/releases/RELEASE_NOTES_v1.8.6.md +0 -205
- package/docs/releases/RELEASE_NOTES_v1.8.7.md +0 -184
- package/docs/releases/RELEASE_PLAN_v1.7.6.md +0 -816
- package/docs/releases/RELEASE_SUMMARY_1.8.10.md +0 -193
- package/docs/releases/RELEASE_SUMMARY_v1.7.4.md +0 -276
- package/docs/releases/RELEASE_SUMMARY_v1.7.5.md +0 -322
- package/docs/releases/RELEASE_SUMMARY_v1.7.6.md +0 -436
- package/docs/releases/RELEASE_SUMMARY_v1.7.7.md +0 -391
- package/docs/releases/RELEASE_SUMMARY_v1.7.8.md +0 -523
- package/docs/releases/RELEASE_SUMMARY_v1.7.9.md +0 -542
- package/docs/troubleshooting/ARDUINO_IDE_VERSION_FIX_SUMMARY.md +0 -229
- package/docs/troubleshooting/ARDUINO_LIBRARY_NAME_FIX.md +0 -197
- package/docs/troubleshooting/CRASH_QUICK_REF.md +0 -93
- package/docs/troubleshooting/ESP32_C6_COMPATIBILITY.md +0 -157
- package/docs/troubleshooting/FREERTOS_ASSERTION_FAILURE.md +0 -288
- package/docs/troubleshooting/FREERTOS_FIX_IMPLEMENTATION.md +0 -267
- package/docs/troubleshooting/NPM_PUBLISHING_ISSUE_SUMMARY.md +0 -110
- package/docs/troubleshooting/PAINLESSMESH_V1.7.4_COMPILATION_ISSUES.md +0 -547
- package/docs/troubleshooting/QUICK_FIX_FREERTOS.md +0 -164
- package/docs/troubleshooting/SENSOR_NODE_CONNECTION_CRASH.md +0 -264
- package/docs/troubleshooting/station-reconnection-issues.md +0 -172
- package/docs/v1.7.7_MQTT_IMPROVEMENTS.md +0 -794
- package/docs/wiki/API-Reference.md +0 -246
- package/docs/wiki/Complete-Documentation.md +0 -123
- package/examples/alteriomImproved/alteriom_sensor_package.hpp +0 -224
- package/examples/alteriomImproved/improved_sensor_node.ino +0 -248
- package/examples/alteriomImproved/platformio.ini +0 -32
- package/examples/alteriomMetricsHealth/alteriom_sensor_package.hpp +0 -796
- package/examples/alteriomMetricsHealth/metrics_health_node.ino +0 -429
- package/examples/alteriomMetricsHealth/platformio.ini +0 -26
- package/examples/alteriomPhase1/alteriom_sensor_package.hpp +0 -224
- package/examples/alteriomPhase1/phase1_features.ino +0 -242
- package/examples/alteriomPhase1/platformio.ini +0 -26
- package/examples/alteriomPhase2/alteriom_sensor_package.hpp +0 -224
- package/examples/alteriomPhase2/phase2_features.ino +0 -186
- package/examples/alteriomPhase2/platformio.ini +0 -26
- package/examples/alteriomSensorNode/alteriom_sensor_node.ino +0 -186
- package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +0 -1227
- package/examples/alteriomSensorNode/platformio.ini +0 -26
- package/examples/bridge/alteriom_sensor_package.hpp +0 -1170
- package/examples/bridge/bridge_health_monitoring_example.ino +0 -188
- package/examples/bridge/enhanced_mqtt_bridge.hpp +0 -610
- package/examples/bridge/enhanced_mqtt_bridge_example.ino +0 -226
- package/examples/bridge/mesh_event_publisher.hpp +0 -253
- package/examples/bridge/mesh_topology_reporter.hpp +0 -303
- package/examples/bridge/mqtt_command_bridge.hpp +0 -459
- package/examples/bridge/mqtt_status_bridge.hpp +0 -519
- package/examples/bridgeAwareSensorNode/alteriom_sensor_package.hpp +0 -1227
- package/examples/bridgeAwareSensorNode/bridgeAwareSensorNode.ino +0 -342
- package/examples/bridgeAwareSensorNode/platformio.ini +0 -26
- package/examples/diagnosticsExample/diagnosticsExample.ino +0 -171
- package/examples/diagnosticsExample/platformio.ini +0 -26
- package/examples/echoNode/echoNode.ino +0 -33
- package/examples/echoNode/platformio.ini +0 -26
- package/examples/meshCommandNode/alteriom_sensor_package.hpp +0 -235
- package/examples/meshCommandNode/meshCommandNode.ino +0 -265
- package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +0 -235
- package/examples/mqttCommandBridge/mesh_event_publisher.hpp +0 -253
- package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +0 -303
- package/examples/mqttCommandBridge/mqttCommandBridge.ino +0 -254
- package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +0 -462
- package/examples/mqttCommandBridge/platformio.ini +0 -27
- package/examples/mqttStatusBridge/mqttStatusBridge.ino +0 -218
- package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +0 -522
- package/examples/mqttStatusBridge/platformio.ini +0 -27
- package/examples/mqttTopologyTest/README.md +0 -467
- package/examples/mqttTopologyTest/mqttTopologyTest.ino +0 -754
- package/examples/mqttTopologyTest/platformio.ini +0 -27
- package/examples/multi_bridge/README.md +0 -346
- package/examples/multi_bridge/primary_bridge.ino +0 -96
- package/examples/multi_bridge/regular_node.ino +0 -141
- package/examples/multi_bridge/secondary_bridge.ino +0 -111
- package/examples/ntpTimeSyncBridge/alteriom_sensor_package.hpp +0 -1383
- package/examples/ntpTimeSyncBridge/ntpTimeSyncBridge.ino +0 -86
- package/examples/ntpTimeSyncNode/alteriom_sensor_package.hpp +0 -1383
- package/examples/ntpTimeSyncNode/ntpTimeSyncNode.ino +0 -109
- package/examples/queued_alarms/README.md +0 -390
- package/examples/queued_alarms/queued_alarms.ino +0 -265
- package/examples/routing_demo/README.md +0 -172
- package/examples/routing_demo/routing_demo.ino +0 -102
- package/examples/rtcIntegration/README.md +0 -294
- package/examples/rtcIntegration/rtcIntegration.ino +0 -210
|
@@ -1,462 +0,0 @@
|
|
|
1
|
-
#ifndef MQTT_COMMAND_BRIDGE_HPP
|
|
2
|
-
#define MQTT_COMMAND_BRIDGE_HPP
|
|
3
|
-
|
|
4
|
-
#include "painlessMesh.h"
|
|
5
|
-
#include <PubSubClient.h>
|
|
6
|
-
#include "alteriom_sensor_package.hpp"
|
|
7
|
-
#include "mesh_topology_reporter.hpp"
|
|
8
|
-
|
|
9
|
-
using namespace alteriom;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @brief Bidirectional MQTT-Mesh Command Bridge
|
|
13
|
-
*
|
|
14
|
-
* Enables MQTT control of mesh devices and mesh status reporting to MQTT.
|
|
15
|
-
* Supports command forwarding, configuration management, and response routing.
|
|
16
|
-
*/
|
|
17
|
-
class MqttCommandBridge {
|
|
18
|
-
private:
|
|
19
|
-
painlessMesh& mesh;
|
|
20
|
-
PubSubClient& mqtt;
|
|
21
|
-
String gatewayId;
|
|
22
|
-
MeshTopologyReporter* topologyReporter;
|
|
23
|
-
|
|
24
|
-
// Command definitions matching MQTT_BRIDGE_COMMANDS.md
|
|
25
|
-
enum Commands {
|
|
26
|
-
// Device Control (1-99)
|
|
27
|
-
RESET = 1,
|
|
28
|
-
SLEEP = 2,
|
|
29
|
-
WAKE = 3,
|
|
30
|
-
LED_CONTROL = 10,
|
|
31
|
-
RELAY_SWITCH = 11,
|
|
32
|
-
PWM_SET = 12,
|
|
33
|
-
SENSOR_ENABLE = 20,
|
|
34
|
-
SENSOR_CALIBRATE = 21,
|
|
35
|
-
|
|
36
|
-
// Configuration (100-199)
|
|
37
|
-
GET_CONFIG = 100,
|
|
38
|
-
SET_CONFIG = 101,
|
|
39
|
-
RESET_CONFIG = 102,
|
|
40
|
-
SAVE_CONFIG = 103,
|
|
41
|
-
SET_SAMPLE_RATE = 110,
|
|
42
|
-
SET_DEVICE_NAME = 111,
|
|
43
|
-
|
|
44
|
-
// Status (200-255)
|
|
45
|
-
GET_STATUS = 200,
|
|
46
|
-
GET_METRICS = 201,
|
|
47
|
-
GET_DIAGNOSTICS = 202,
|
|
48
|
-
START_MONITORING = 210,
|
|
49
|
-
STOP_MONITORING = 211,
|
|
50
|
-
|
|
51
|
-
// Topology (300-399)
|
|
52
|
-
GET_TOPOLOGY = 300
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
public:
|
|
56
|
-
MqttCommandBridge(painlessMesh& m, PubSubClient& mq, MeshTopologyReporter* reporter = nullptr)
|
|
57
|
-
: mesh(m), mqtt(mq), topologyReporter(reporter) {
|
|
58
|
-
gatewayId = String(mesh.getNodeId());
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* @brief Set topology reporter instance
|
|
63
|
-
*/
|
|
64
|
-
void setTopologyReporter(MeshTopologyReporter* reporter) {
|
|
65
|
-
topologyReporter = reporter;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* @brief Initialize the bridge with topic subscriptions and callbacks
|
|
70
|
-
*/
|
|
71
|
-
void begin() {
|
|
72
|
-
// Subscribe to command topics
|
|
73
|
-
String cmdTopic = "mesh/command/" + gatewayId;
|
|
74
|
-
mqtt.subscribe(cmdTopic.c_str());
|
|
75
|
-
mqtt.subscribe("mesh/command/broadcast");
|
|
76
|
-
|
|
77
|
-
String configGetTopic = "mesh/config/" + gatewayId + "/get";
|
|
78
|
-
mqtt.subscribe(configGetTopic.c_str());
|
|
79
|
-
|
|
80
|
-
String configSetTopic = "mesh/config/" + gatewayId + "/set";
|
|
81
|
-
mqtt.subscribe(configSetTopic.c_str());
|
|
82
|
-
|
|
83
|
-
Serial.printf("MQTT Command Bridge initialized - Gateway ID: %s\n", gatewayId.c_str());
|
|
84
|
-
Serial.println("Subscribed topics:");
|
|
85
|
-
Serial.printf(" - %s\n", cmdTopic.c_str());
|
|
86
|
-
Serial.println(" - mesh/command/broadcast");
|
|
87
|
-
Serial.printf(" - %s\n", configGetTopic.c_str());
|
|
88
|
-
Serial.printf(" - %s\n", configSetTopic.c_str());
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* @brief Set MQTT callback for incoming messages
|
|
93
|
-
*/
|
|
94
|
-
void setMqttCallback() {
|
|
95
|
-
mqtt.setCallback([this](char* topic, byte* payload, unsigned int length) {
|
|
96
|
-
this->onMqttMessage(topic, payload, length);
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* @brief Set mesh received callback for outgoing messages
|
|
102
|
-
*/
|
|
103
|
-
void setMeshCallback() {
|
|
104
|
-
mesh.onReceive([this](uint32_t from, String& msg) {
|
|
105
|
-
this->onMeshMessage(from, msg);
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* @brief Handle incoming MQTT messages
|
|
111
|
-
*/
|
|
112
|
-
void onMqttMessage(char* topic, byte* payload, unsigned int length) {
|
|
113
|
-
String topicStr = String(topic);
|
|
114
|
-
|
|
115
|
-
// Parse JSON payload
|
|
116
|
-
JsonDocument doc;
|
|
117
|
-
DeserializationError error = deserializeJson(doc, payload, length);
|
|
118
|
-
|
|
119
|
-
if (error) {
|
|
120
|
-
Serial.printf("JSON parse error: %s\n", error.c_str());
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
Serial.printf("MQTT message on %s\n", topic);
|
|
125
|
-
|
|
126
|
-
if (topicStr.indexOf("/command/") >= 0) {
|
|
127
|
-
forwardCommandToMesh(doc);
|
|
128
|
-
}
|
|
129
|
-
else if (topicStr.endsWith("/get")) {
|
|
130
|
-
handleConfigRequest(doc);
|
|
131
|
-
}
|
|
132
|
-
else if (topicStr.endsWith("/set")) {
|
|
133
|
-
handleConfigUpdate(doc);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* @brief Forward MQTT command to mesh network
|
|
139
|
-
*/
|
|
140
|
-
void forwardCommandToMesh(JsonDocument& doc) {
|
|
141
|
-
// Create CommandPackage
|
|
142
|
-
CommandPackage cmd;
|
|
143
|
-
cmd.command = doc["command"];
|
|
144
|
-
cmd.targetDevice = doc["targetDevice"];
|
|
145
|
-
cmd.commandId = doc["commandId"] | millis(); // Generate if missing
|
|
146
|
-
cmd.parameters = doc["parameters"].as<String>();
|
|
147
|
-
cmd.from = mesh.getNodeId();
|
|
148
|
-
cmd.dest = cmd.targetDevice;
|
|
149
|
-
|
|
150
|
-
Serial.printf("Command: cmd=%d, target=%u, id=%u\n",
|
|
151
|
-
cmd.command, cmd.targetDevice, cmd.commandId);
|
|
152
|
-
|
|
153
|
-
// Route based on target
|
|
154
|
-
if (cmd.targetDevice == 0 || cmd.targetDevice == mesh.getNodeId()) {
|
|
155
|
-
// Execute locally on gateway
|
|
156
|
-
executeCommand(cmd);
|
|
157
|
-
} else {
|
|
158
|
-
// Forward to mesh node
|
|
159
|
-
auto variant = painlessmesh::protocol::Variant(&cmd);
|
|
160
|
-
String message;
|
|
161
|
-
variant.printTo(message);
|
|
162
|
-
|
|
163
|
-
mesh.sendSingle(cmd.targetDevice, message);
|
|
164
|
-
Serial.printf("Command forwarded to node %u\n", cmd.targetDevice);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* @brief Execute command locally on gateway
|
|
170
|
-
*/
|
|
171
|
-
void executeCommand(const CommandPackage& cmd) {
|
|
172
|
-
Serial.printf("Executing command: %d\n", cmd.command);
|
|
173
|
-
|
|
174
|
-
StatusPackage response;
|
|
175
|
-
response.from = mesh.getNodeId();
|
|
176
|
-
response.responseToCommand = cmd.commandId;
|
|
177
|
-
response.deviceStatus = 0; // OK
|
|
178
|
-
|
|
179
|
-
switch(cmd.command) {
|
|
180
|
-
case RESET:
|
|
181
|
-
response.responseMessage = "Rebooting...";
|
|
182
|
-
sendResponse(response);
|
|
183
|
-
delay(1000);
|
|
184
|
-
ESP.restart();
|
|
185
|
-
break;
|
|
186
|
-
|
|
187
|
-
case SLEEP: {
|
|
188
|
-
JsonDocument params;
|
|
189
|
-
deserializeJson(params, cmd.parameters);
|
|
190
|
-
uint32_t duration = params["duration_ms"];
|
|
191
|
-
|
|
192
|
-
response.responseMessage = "Entering sleep for " + String(duration) + "ms";
|
|
193
|
-
sendResponse(response);
|
|
194
|
-
|
|
195
|
-
ESP.deepSleep(duration * 1000);
|
|
196
|
-
break;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
case LED_CONTROL: {
|
|
200
|
-
JsonDocument params;
|
|
201
|
-
deserializeJson(params, cmd.parameters);
|
|
202
|
-
|
|
203
|
-
bool state = params["state"];
|
|
204
|
-
uint8_t brightness = params["brightness"] | 255;
|
|
205
|
-
|
|
206
|
-
// Control LED (use GPIO2 if LED_BUILTIN not defined on ESP32)
|
|
207
|
-
#ifndef LED_BUILTIN
|
|
208
|
-
#define LED_BUILTIN 2
|
|
209
|
-
#endif
|
|
210
|
-
digitalWrite(LED_BUILTIN, state ? LOW : HIGH);
|
|
211
|
-
|
|
212
|
-
response.responseMessage = "LED " + String(state ? "ON" : "OFF");
|
|
213
|
-
sendResponse(response);
|
|
214
|
-
break;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
case GET_CONFIG:
|
|
218
|
-
sendConfiguration();
|
|
219
|
-
break;
|
|
220
|
-
|
|
221
|
-
case GET_STATUS:
|
|
222
|
-
sendStatus();
|
|
223
|
-
break;
|
|
224
|
-
|
|
225
|
-
case GET_METRICS:
|
|
226
|
-
sendMetrics();
|
|
227
|
-
break;
|
|
228
|
-
|
|
229
|
-
case GET_TOPOLOGY:
|
|
230
|
-
sendTopology(cmd.commandId);
|
|
231
|
-
break;
|
|
232
|
-
|
|
233
|
-
default:
|
|
234
|
-
response.deviceStatus = 2; // Error
|
|
235
|
-
response.responseMessage = "Unknown command: " + String(cmd.command);
|
|
236
|
-
sendResponse(response);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* @brief Handle incoming mesh messages and forward to MQTT
|
|
242
|
-
*/
|
|
243
|
-
void onMeshMessage(uint32_t from, String& msg) {
|
|
244
|
-
// Parse message
|
|
245
|
-
JsonDocument doc;
|
|
246
|
-
DeserializationError error = deserializeJson(doc, msg);
|
|
247
|
-
|
|
248
|
-
if (error) return;
|
|
249
|
-
|
|
250
|
-
uint8_t msgType = doc["type"];
|
|
251
|
-
|
|
252
|
-
// Forward mesh messages to MQTT based on type
|
|
253
|
-
switch(msgType) {
|
|
254
|
-
case 200: // SensorPackage
|
|
255
|
-
publishToMqtt("mesh/sensor/" + String(from), msg);
|
|
256
|
-
break;
|
|
257
|
-
|
|
258
|
-
case 202: // StatusPackage
|
|
259
|
-
// Check if it's a command response (ArduinoJson v7 compatible)
|
|
260
|
-
if (doc["respTo"].is<uint32_t>() && doc["respTo"].as<uint32_t>() > 0) {
|
|
261
|
-
publishToMqtt("mesh/response/" + String(from), msg);
|
|
262
|
-
} else {
|
|
263
|
-
publishToMqtt("mesh/status/" + String(from), msg);
|
|
264
|
-
}
|
|
265
|
-
break;
|
|
266
|
-
|
|
267
|
-
case 203: // EnhancedStatusPackage
|
|
268
|
-
publishToMqtt("mesh/health/" + String(from), msg);
|
|
269
|
-
break;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* @brief Send status response via MQTT
|
|
275
|
-
*/
|
|
276
|
-
void sendResponse(const StatusPackage& response) {
|
|
277
|
-
auto variant = painlessmesh::protocol::Variant(&response);
|
|
278
|
-
String message;
|
|
279
|
-
variant.printTo(message);
|
|
280
|
-
|
|
281
|
-
String topic = "mesh/response/" + String(response.from);
|
|
282
|
-
publishToMqtt(topic, message);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* @brief Send configuration via MQTT
|
|
287
|
-
*/
|
|
288
|
-
void sendConfiguration() {
|
|
289
|
-
JsonDocument config;
|
|
290
|
-
config["schema_version"] = 1;
|
|
291
|
-
config["device_id"] = gatewayId;
|
|
292
|
-
config["timestamp"] = getCurrentISO8601Timestamp();
|
|
293
|
-
|
|
294
|
-
JsonObject cfg = config["config"].to<JsonObject>();
|
|
295
|
-
cfg["deviceName"] = "Gateway-" + gatewayId;
|
|
296
|
-
cfg["firmwareVersion"] = "1.7.0-alteriom";
|
|
297
|
-
cfg["role"] = "gateway";
|
|
298
|
-
cfg["meshPrefix"] = "AlteriomMesh";
|
|
299
|
-
cfg["nodeCount"] = mesh.getNodeList().size();
|
|
300
|
-
|
|
301
|
-
String payload;
|
|
302
|
-
serializeJson(config, payload);
|
|
303
|
-
|
|
304
|
-
String topic = "mesh/config/" + gatewayId;
|
|
305
|
-
publishToMqtt(topic, payload);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* @brief Send basic status via MQTT
|
|
310
|
-
*/
|
|
311
|
-
void sendStatus() {
|
|
312
|
-
StatusPackage status;
|
|
313
|
-
status.from = mesh.getNodeId();
|
|
314
|
-
status.deviceStatus = 0;
|
|
315
|
-
status.uptime = millis() / 1000;
|
|
316
|
-
status.freeMemory = ESP.getFreeHeap() / 1024;
|
|
317
|
-
status.wifiStrength = WiFi.RSSI();
|
|
318
|
-
status.firmwareVersion = "1.7.0-alteriom";
|
|
319
|
-
|
|
320
|
-
sendResponse(status);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* @brief Send enhanced metrics via MQTT
|
|
325
|
-
*/
|
|
326
|
-
void sendMetrics() {
|
|
327
|
-
EnhancedStatusPackage metrics;
|
|
328
|
-
metrics.from = mesh.getNodeId();
|
|
329
|
-
metrics.deviceStatus = 0;
|
|
330
|
-
metrics.uptime = millis() / 1000;
|
|
331
|
-
metrics.freeMemory = ESP.getFreeHeap() / 1024;
|
|
332
|
-
metrics.wifiStrength = WiFi.RSSI();
|
|
333
|
-
metrics.firmwareVersion = "1.7.0-alteriom";
|
|
334
|
-
|
|
335
|
-
// Mesh statistics
|
|
336
|
-
auto nodeList = mesh.getNodeList();
|
|
337
|
-
metrics.nodeCount = nodeList.size();
|
|
338
|
-
metrics.connectionCount = mesh.getNodeList().size();
|
|
339
|
-
|
|
340
|
-
auto variant = painlessmesh::protocol::Variant(&metrics);
|
|
341
|
-
String message;
|
|
342
|
-
variant.printTo(message);
|
|
343
|
-
|
|
344
|
-
String topic = "mesh/health/" + String(metrics.from);
|
|
345
|
-
publishToMqtt(topic, message);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* @brief Send mesh topology via MQTT (Command 300)
|
|
350
|
-
* @param commandId The command ID for correlation
|
|
351
|
-
*/
|
|
352
|
-
void sendTopology(uint32_t commandId) {
|
|
353
|
-
if (!topologyReporter) {
|
|
354
|
-
Serial.println("⚠️ Topology reporter not initialized");
|
|
355
|
-
|
|
356
|
-
StatusPackage response;
|
|
357
|
-
response.from = mesh.getNodeId();
|
|
358
|
-
response.responseToCommand = commandId;
|
|
359
|
-
response.deviceStatus = 2; // Error
|
|
360
|
-
response.responseMessage = "Topology reporter not available";
|
|
361
|
-
sendResponse(response);
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
Serial.printf("📊 Generating topology for command %u\n", commandId);
|
|
366
|
-
String topology = topologyReporter->generateFullTopology();
|
|
367
|
-
|
|
368
|
-
// Parse to add correlation_id
|
|
369
|
-
JsonDocument doc;
|
|
370
|
-
DeserializationError error = deserializeJson(doc, topology);
|
|
371
|
-
|
|
372
|
-
if (error) {
|
|
373
|
-
Serial.printf("❌ Failed to parse topology: %s\n", error.c_str());
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Add correlation_id at root level
|
|
378
|
-
doc["correlation_id"] = String(commandId);
|
|
379
|
-
|
|
380
|
-
String payload;
|
|
381
|
-
serializeJson(doc, payload);
|
|
382
|
-
|
|
383
|
-
// Publish to response topic
|
|
384
|
-
String topic = "alteriom/mesh/MESH-001/topology/response";
|
|
385
|
-
publishToMqtt(topic, payload);
|
|
386
|
-
|
|
387
|
-
Serial.printf("✅ Topology sent (cmd=%u, size=%d bytes)\n", commandId, payload.length());
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* @brief Handle configuration request
|
|
392
|
-
*/
|
|
393
|
-
void handleConfigRequest(JsonDocument& doc) {
|
|
394
|
-
sendConfiguration();
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* @brief Handle configuration update
|
|
399
|
-
*/
|
|
400
|
-
void handleConfigUpdate(JsonDocument& doc) {
|
|
401
|
-
JsonObject config = doc["config"];
|
|
402
|
-
|
|
403
|
-
// Apply configuration updates (ArduinoJson v7 compatible)
|
|
404
|
-
if (config["deviceName"].is<const char*>()) {
|
|
405
|
-
String newName = config["deviceName"];
|
|
406
|
-
Serial.printf("Config update: deviceName=%s\n", newName.c_str());
|
|
407
|
-
// Store to preferences/EEPROM in production
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
if (config["meshPrefix"].is<const char*>()) {
|
|
411
|
-
String newPrefix = config["meshPrefix"];
|
|
412
|
-
Serial.printf("Config update: meshPrefix=%s (requires restart)\n", newPrefix.c_str());
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// Send acknowledgment
|
|
416
|
-
JsonDocument ack;
|
|
417
|
-
ack["status"] = "success";
|
|
418
|
-
ack["device_id"] = gatewayId;
|
|
419
|
-
ack["message"] = "Configuration updated";
|
|
420
|
-
ack["timestamp"] = getCurrentISO8601Timestamp();
|
|
421
|
-
|
|
422
|
-
String payload;
|
|
423
|
-
serializeJson(ack, payload);
|
|
424
|
-
|
|
425
|
-
String topic = "mesh/response/" + gatewayId;
|
|
426
|
-
publishToMqtt(topic, payload);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* @brief Publish message to MQTT broker
|
|
431
|
-
*/
|
|
432
|
-
void publishToMqtt(const String& topic, const String& payload) {
|
|
433
|
-
if (mqtt.connected()) {
|
|
434
|
-
bool success = mqtt.publish(topic.c_str(), payload.c_str());
|
|
435
|
-
if (success) {
|
|
436
|
-
Serial.printf("MQTT published: %s\n", topic.c_str());
|
|
437
|
-
} else {
|
|
438
|
-
Serial.printf("MQTT publish failed: %s\n", topic.c_str());
|
|
439
|
-
}
|
|
440
|
-
} else {
|
|
441
|
-
Serial.println("MQTT not connected, cannot publish");
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
private:
|
|
446
|
-
/**
|
|
447
|
-
* @brief Get current ISO8601 timestamp
|
|
448
|
-
* Note: Simple implementation, enhance with NTP for production
|
|
449
|
-
*/
|
|
450
|
-
String getCurrentISO8601Timestamp() {
|
|
451
|
-
unsigned long seconds = millis() / 1000;
|
|
452
|
-
char timestamp[25];
|
|
453
|
-
snprintf(timestamp, sizeof(timestamp),
|
|
454
|
-
"1970-01-01T%02lu:%02lu:%02luZ",
|
|
455
|
-
(seconds / 3600) % 24,
|
|
456
|
-
(seconds / 60) % 60,
|
|
457
|
-
seconds % 60);
|
|
458
|
-
return String(timestamp);
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
|
-
|
|
462
|
-
#endif // MQTT_COMMAND_BRIDGE_HPP
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
[platformio]
|
|
2
|
-
src_dir = .
|
|
3
|
-
|
|
4
|
-
[env]
|
|
5
|
-
lib_deps =
|
|
6
|
-
bblanchon/ArduinoJson
|
|
7
|
-
arkhipenko/TaskScheduler
|
|
8
|
-
knolleary/PubSubClient
|
|
9
|
-
|
|
10
|
-
lib_ldf_mode = deep+
|
|
11
|
-
[env:esp8266]
|
|
12
|
-
platform = espressif8266
|
|
13
|
-
board = nodemcuv2
|
|
14
|
-
framework = arduino
|
|
15
|
-
lib_extra_dirs = ../../
|
|
16
|
-
lib_deps =
|
|
17
|
-
${env.lib_deps} ; Inherit common dependencies
|
|
18
|
-
esp32async/ESPAsyncTCP@^2.0.0 ; Only for ESP8266
|
|
19
|
-
|
|
20
|
-
[env:esp32]
|
|
21
|
-
platform = espressif32
|
|
22
|
-
board = esp32dev
|
|
23
|
-
framework = arduino
|
|
24
|
-
lib_extra_dirs = ../../
|
|
25
|
-
lib_deps =
|
|
26
|
-
${env.lib_deps} ; Inherit common dependencies
|
|
27
|
-
esp32async/AsyncTCP
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
//************************************************************
|
|
2
|
-
// Phase 2: MQTT Status Bridge Example
|
|
3
|
-
//
|
|
4
|
-
// This example demonstrates the MQTT Status Bridge feature,
|
|
5
|
-
// which publishes comprehensive mesh status to MQTT topics
|
|
6
|
-
// for professional monitoring with tools like:
|
|
7
|
-
// - Grafana
|
|
8
|
-
// - InfluxDB
|
|
9
|
-
// - Prometheus
|
|
10
|
-
// - Home Assistant
|
|
11
|
-
// - Node-RED
|
|
12
|
-
//
|
|
13
|
-
// MQTT Topics Published:
|
|
14
|
-
// - mesh/status/nodes - List of all nodes in mesh
|
|
15
|
-
// - mesh/status/topology - Complete mesh topology JSON
|
|
16
|
-
// - mesh/status/metrics - Performance metrics
|
|
17
|
-
// - mesh/status/alerts - Active alerts
|
|
18
|
-
// - mesh/status/node/{id} - Per-node detailed status (optional)
|
|
19
|
-
//
|
|
20
|
-
// Requirements:
|
|
21
|
-
// - ESP32 or ESP8266
|
|
22
|
-
// - WiFi connection to external network (for MQTT broker)
|
|
23
|
-
// - MQTT broker (e.g., Mosquitto, HiveMQ, AWS IoT)
|
|
24
|
-
//************************************************************
|
|
25
|
-
|
|
26
|
-
#include <Arduino.h>
|
|
27
|
-
#include "painlessTaskOptions.h" // Must be first to configure TaskScheduler
|
|
28
|
-
#include <TaskScheduler.h> // Required for LDF to find TaskScheduler dependency
|
|
29
|
-
#include <painlessMesh.h>
|
|
30
|
-
#include <PubSubClient.h>
|
|
31
|
-
#include <WiFiClient.h>
|
|
32
|
-
#include "mqtt_status_bridge.hpp"
|
|
33
|
-
|
|
34
|
-
// Mesh configuration
|
|
35
|
-
#define MESH_PREFIX "AlteriomMesh"
|
|
36
|
-
#define MESH_PASSWORD "somethingSneaky"
|
|
37
|
-
#define MESH_PORT 5555
|
|
38
|
-
|
|
39
|
-
// External WiFi configuration (for MQTT connection)
|
|
40
|
-
#define STATION_SSID "YourAP_SSID"
|
|
41
|
-
#define STATION_PASSWORD "YourAP_PWD"
|
|
42
|
-
|
|
43
|
-
// MQTT broker configuration
|
|
44
|
-
#define MQTT_BROKER_IP "192.168.1.100" // Change to your MQTT broker IP
|
|
45
|
-
#define MQTT_BROKER_PORT 1883
|
|
46
|
-
#define MQTT_CLIENT_ID "painlessMesh_StatusBridge"
|
|
47
|
-
|
|
48
|
-
#define HOSTNAME "MQTT_Status_Bridge"
|
|
49
|
-
|
|
50
|
-
// Prototypes
|
|
51
|
-
void receivedCallback(const uint32_t &from, const String &msg);
|
|
52
|
-
void mqttCallback(char* topic, byte* payload, unsigned int length);
|
|
53
|
-
IPAddress getlocalIP();
|
|
54
|
-
|
|
55
|
-
// Global objects
|
|
56
|
-
IPAddress myIP(0, 0, 0, 0);
|
|
57
|
-
IPAddress mqttBroker(192, 168, 1, 100); // Change to your MQTT broker IP
|
|
58
|
-
|
|
59
|
-
Scheduler userScheduler;
|
|
60
|
-
painlessMesh mesh;
|
|
61
|
-
WiFiClient wifiClient;
|
|
62
|
-
PubSubClient mqttClient(mqttBroker, MQTT_BROKER_PORT, mqttCallback, wifiClient);
|
|
63
|
-
|
|
64
|
-
// Phase 2: MQTT Status Bridge instance
|
|
65
|
-
MqttStatusBridge* statusBridge = nullptr;
|
|
66
|
-
|
|
67
|
-
void setup() {
|
|
68
|
-
Serial.begin(115200);
|
|
69
|
-
Serial.println("\n\n=== Phase 2: MQTT Status Bridge Example ===\n");
|
|
70
|
-
|
|
71
|
-
// Initialize mesh
|
|
72
|
-
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
73
|
-
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT, WIFI_AP_STA, 6);
|
|
74
|
-
mesh.onReceive(&receivedCallback);
|
|
75
|
-
|
|
76
|
-
// Connect to external WiFi for MQTT
|
|
77
|
-
mesh.stationManual(STATION_SSID, STATION_PASSWORD);
|
|
78
|
-
mesh.setHostname(HOSTNAME);
|
|
79
|
-
|
|
80
|
-
// Bridge node should be root
|
|
81
|
-
mesh.setRoot(true);
|
|
82
|
-
mesh.setContainsRoot(true);
|
|
83
|
-
|
|
84
|
-
Serial.println("Mesh initialized");
|
|
85
|
-
Serial.println("Waiting for WiFi and MQTT connection...");
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
void loop() {
|
|
89
|
-
mesh.update();
|
|
90
|
-
mqttClient.loop();
|
|
91
|
-
|
|
92
|
-
// Check for WiFi connection and connect to MQTT
|
|
93
|
-
if (myIP != getlocalIP()) {
|
|
94
|
-
myIP = getlocalIP();
|
|
95
|
-
Serial.println("WiFi connected!");
|
|
96
|
-
Serial.print("IP address: ");
|
|
97
|
-
Serial.println(myIP.toString());
|
|
98
|
-
|
|
99
|
-
// Connect to MQTT broker
|
|
100
|
-
if (mqttClient.connect(MQTT_CLIENT_ID)) {
|
|
101
|
-
Serial.println("MQTT connected!");
|
|
102
|
-
Serial.print("Broker: ");
|
|
103
|
-
Serial.print(mqttBroker.toString());
|
|
104
|
-
Serial.print(":");
|
|
105
|
-
Serial.println(MQTT_BROKER_PORT);
|
|
106
|
-
|
|
107
|
-
// Subscribe to mesh command topics (optional)
|
|
108
|
-
mqttClient.subscribe("mesh/command/#");
|
|
109
|
-
mqttClient.publish("mesh/status/bridge", "Bridge online!");
|
|
110
|
-
|
|
111
|
-
// Phase 2: Initialize and start MQTT Status Bridge
|
|
112
|
-
if (statusBridge == nullptr) {
|
|
113
|
-
statusBridge = new MqttStatusBridge(mesh, mqttClient, userScheduler);
|
|
114
|
-
|
|
115
|
-
// Configure the bridge
|
|
116
|
-
statusBridge->setPublishInterval(30000); // Publish every 30 seconds
|
|
117
|
-
statusBridge->setTopicPrefix("mesh/status/");
|
|
118
|
-
|
|
119
|
-
// Enable features (all enabled by default)
|
|
120
|
-
statusBridge->enableTopology(true); // Publish mesh topology
|
|
121
|
-
statusBridge->enableMetrics(true); // Publish performance metrics
|
|
122
|
-
statusBridge->enableAlerts(true); // Publish active alerts
|
|
123
|
-
statusBridge->enablePerNode(false); // Per-node status (can be expensive)
|
|
124
|
-
|
|
125
|
-
// Start publishing
|
|
126
|
-
statusBridge->begin();
|
|
127
|
-
|
|
128
|
-
Serial.println("\n=== MQTT Status Bridge Configured ===");
|
|
129
|
-
Serial.println("Publishing to topics:");
|
|
130
|
-
Serial.println(" - mesh/status/nodes");
|
|
131
|
-
Serial.println(" - mesh/status/topology");
|
|
132
|
-
Serial.println(" - mesh/status/metrics");
|
|
133
|
-
Serial.println(" - mesh/status/alerts");
|
|
134
|
-
Serial.println("Publish interval: 30 seconds\n");
|
|
135
|
-
}
|
|
136
|
-
} else {
|
|
137
|
-
Serial.print("MQTT connection failed, rc=");
|
|
138
|
-
Serial.println(mqttClient.state());
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Reconnect to MQTT if connection is lost
|
|
143
|
-
static unsigned long lastReconnectAttempt = 0;
|
|
144
|
-
if (!mqttClient.connected() && myIP != IPAddress(0, 0, 0, 0)) {
|
|
145
|
-
unsigned long now = millis();
|
|
146
|
-
if (now - lastReconnectAttempt > 5000) {
|
|
147
|
-
lastReconnectAttempt = now;
|
|
148
|
-
Serial.println("Attempting MQTT reconnection...");
|
|
149
|
-
if (mqttClient.connect(MQTT_CLIENT_ID)) {
|
|
150
|
-
Serial.println("MQTT reconnected!");
|
|
151
|
-
mqttClient.subscribe("mesh/command/#");
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
void receivedCallback(const uint32_t &from, const String &msg) {
|
|
158
|
-
Serial.printf("Received from %u: %s\n", from, msg.c_str());
|
|
159
|
-
|
|
160
|
-
// Forward mesh messages to MQTT
|
|
161
|
-
String topic = "mesh/from/" + String(from);
|
|
162
|
-
if (mqttClient.connected()) {
|
|
163
|
-
mqttClient.publish(topic.c_str(), msg.c_str());
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
void mqttCallback(char* topic, uint8_t* payload, unsigned int length) {
|
|
168
|
-
// Parse payload
|
|
169
|
-
char* cleanPayload = (char*)malloc(length + 1);
|
|
170
|
-
memcpy(cleanPayload, payload, length);
|
|
171
|
-
cleanPayload[length] = '\0';
|
|
172
|
-
String msg = String(cleanPayload);
|
|
173
|
-
free(cleanPayload);
|
|
174
|
-
|
|
175
|
-
Serial.printf("MQTT received on %s: %s\n", topic, msg.c_str());
|
|
176
|
-
|
|
177
|
-
String topicStr = String(topic);
|
|
178
|
-
|
|
179
|
-
// Handle mesh commands
|
|
180
|
-
if (topicStr.startsWith("mesh/command/")) {
|
|
181
|
-
String command = topicStr.substring(13); // Remove "mesh/command/"
|
|
182
|
-
|
|
183
|
-
if (command == "getNodes") {
|
|
184
|
-
// Get node list
|
|
185
|
-
auto nodes = mesh.getNodeList(true);
|
|
186
|
-
String nodeList = "{\"nodes\":[";
|
|
187
|
-
bool firstNode = true;
|
|
188
|
-
for (auto nodeId : nodes) {
|
|
189
|
-
if (!firstNode) nodeList += ",";
|
|
190
|
-
firstNode = false;
|
|
191
|
-
nodeList += String(nodeId);
|
|
192
|
-
}
|
|
193
|
-
nodeList += "]}";
|
|
194
|
-
mqttClient.publish("mesh/response/nodes", nodeList.c_str());
|
|
195
|
-
}
|
|
196
|
-
else if (command == "getTopology") {
|
|
197
|
-
// Get mesh topology
|
|
198
|
-
String topology = mesh.subConnectionJson(false);
|
|
199
|
-
mqttClient.publish("mesh/response/topology", topology.c_str());
|
|
200
|
-
}
|
|
201
|
-
else if (command == "publishNow") {
|
|
202
|
-
// Trigger immediate status publish
|
|
203
|
-
if (statusBridge != nullptr) {
|
|
204
|
-
statusBridge->publishNow();
|
|
205
|
-
mqttClient.publish("mesh/response/command", "Status published");
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
else if (command == "broadcast") {
|
|
209
|
-
// Broadcast message to all mesh nodes
|
|
210
|
-
mesh.sendBroadcast(msg);
|
|
211
|
-
mqttClient.publish("mesh/response/command", "Message broadcasted");
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
IPAddress getlocalIP() {
|
|
217
|
-
return IPAddress(mesh.getStationIP());
|
|
218
|
-
}
|