@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,303 +0,0 @@
|
|
|
1
|
-
#ifndef MESH_TOPOLOGY_REPORTER_HPP
|
|
2
|
-
#define MESH_TOPOLOGY_REPORTER_HPP
|
|
3
|
-
|
|
4
|
-
#include "painlessMesh.h"
|
|
5
|
-
#include <ArduinoJson.h>
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* MeshTopologyReporter - Generate schema-compliant topology messages
|
|
9
|
-
*
|
|
10
|
-
* Generates mesh topology messages conforming to @alteriom/mqtt-schema v0.5.0
|
|
11
|
-
* mesh_topology.schema.json specification.
|
|
12
|
-
*
|
|
13
|
-
* Features:
|
|
14
|
-
* - Full topology snapshots with nodes, connections, and metrics
|
|
15
|
-
* - Incremental updates for node join/leave events
|
|
16
|
-
* - Change detection to avoid redundant publishes
|
|
17
|
-
* - Network metrics aggregation
|
|
18
|
-
*
|
|
19
|
-
* @author Alteriom Development Team
|
|
20
|
-
* @date October 12, 2025
|
|
21
|
-
*/
|
|
22
|
-
class MeshTopologyReporter {
|
|
23
|
-
private:
|
|
24
|
-
painlessMesh& mesh;
|
|
25
|
-
String meshId;
|
|
26
|
-
String lastTopologyHash; // Detect changes
|
|
27
|
-
String firmwareVersion;
|
|
28
|
-
|
|
29
|
-
public:
|
|
30
|
-
MeshTopologyReporter(painlessMesh& mesh, const String& meshId, const String& fwVersion = "GW 2.3.4")
|
|
31
|
-
: mesh(mesh), meshId(meshId), firmwareVersion(fwVersion) {}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Generate full topology message (schema v0.5.0 compliant)
|
|
35
|
-
*
|
|
36
|
-
* Returns JSON string ready for MQTT publish to:
|
|
37
|
-
* alteriom/mesh/{mesh_id}/topology
|
|
38
|
-
*/
|
|
39
|
-
String generateFullTopology() {
|
|
40
|
-
JsonDocument doc; // ArduinoJson v7: automatic sizing
|
|
41
|
-
|
|
42
|
-
// Envelope fields (from @alteriom/mqtt-schema)
|
|
43
|
-
doc["schema_version"] = 1;
|
|
44
|
-
doc["device_id"] = generateDeviceId(mesh.getNodeId());
|
|
45
|
-
doc["device_type"] = "gateway";
|
|
46
|
-
doc["timestamp"] = getISO8601Timestamp();
|
|
47
|
-
doc["firmware_version"] = firmwareVersion;
|
|
48
|
-
|
|
49
|
-
// Event discriminator
|
|
50
|
-
doc["event"] = "mesh_topology";
|
|
51
|
-
|
|
52
|
-
// Mesh identification
|
|
53
|
-
doc["mesh_id"] = meshId;
|
|
54
|
-
doc["gateway_node_id"] = generateDeviceId(mesh.getNodeId());
|
|
55
|
-
|
|
56
|
-
// Nodes array - ArduinoJson v7 syntax
|
|
57
|
-
JsonArray nodes = doc["nodes"].to<JsonArray>();
|
|
58
|
-
addNodeInfo(nodes, mesh.getNodeId(), "gateway"); // Self
|
|
59
|
-
|
|
60
|
-
auto nodeList = mesh.getNodeList(false);
|
|
61
|
-
for (auto nodeId : nodeList) {
|
|
62
|
-
addNodeInfo(nodes, nodeId, "sensor"); // Assume sensor role
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Connections array - ArduinoJson v7 syntax
|
|
66
|
-
JsonArray connections = doc["connections"].to<JsonArray>();
|
|
67
|
-
addConnectionInfo(connections);
|
|
68
|
-
|
|
69
|
-
// Network metrics - ArduinoJson v7 syntax
|
|
70
|
-
JsonObject metrics = doc["metrics"].to<JsonObject>();
|
|
71
|
-
metrics["total_nodes"] = nodeList.size() + 1; // +1 for gateway
|
|
72
|
-
metrics["online_nodes"] = nodeList.size() + 1;
|
|
73
|
-
metrics["network_diameter"] = calculateNetworkDiameter();
|
|
74
|
-
metrics["avg_connection_quality"] = calculateAvgQuality();
|
|
75
|
-
metrics["messages_per_second"] = calculateThroughput();
|
|
76
|
-
|
|
77
|
-
doc["update_type"] = "full";
|
|
78
|
-
|
|
79
|
-
String output;
|
|
80
|
-
serializeJson(doc, output);
|
|
81
|
-
return output;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Generate incremental topology update
|
|
86
|
-
*
|
|
87
|
-
* @param nodeId Node that joined or left
|
|
88
|
-
* @param joined true if node joined, false if left
|
|
89
|
-
*/
|
|
90
|
-
String generateIncrementalUpdate(uint32_t nodeId, bool joined) {
|
|
91
|
-
JsonDocument doc; // ArduinoJson v7: automatic sizing
|
|
92
|
-
|
|
93
|
-
// Envelope fields
|
|
94
|
-
doc["schema_version"] = 1;
|
|
95
|
-
doc["device_id"] = generateDeviceId(mesh.getNodeId());
|
|
96
|
-
doc["device_type"] = "gateway";
|
|
97
|
-
doc["timestamp"] = getISO8601Timestamp();
|
|
98
|
-
doc["firmware_version"] = firmwareVersion;
|
|
99
|
-
|
|
100
|
-
doc["event"] = "mesh_topology";
|
|
101
|
-
doc["mesh_id"] = meshId;
|
|
102
|
-
doc["gateway_node_id"] = generateDeviceId(mesh.getNodeId());
|
|
103
|
-
|
|
104
|
-
// Node that changed - ArduinoJson v7 syntax
|
|
105
|
-
JsonArray nodes = doc["nodes"].to<JsonArray>();
|
|
106
|
-
if (joined) {
|
|
107
|
-
addNodeInfo(nodes, nodeId, "sensor");
|
|
108
|
-
} else {
|
|
109
|
-
// For node leaving, mark as offline
|
|
110
|
-
JsonObject node = nodes.add<JsonObject>();
|
|
111
|
-
node["node_id"] = generateDeviceId(nodeId);
|
|
112
|
-
node["status"] = "offline";
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Update connections - ArduinoJson v7 syntax
|
|
116
|
-
JsonArray connections = doc["connections"].to<JsonArray>();
|
|
117
|
-
// Add connections related to this node
|
|
118
|
-
addConnectionInfoForNode(connections, nodeId);
|
|
119
|
-
|
|
120
|
-
// Updated metrics - ArduinoJson v7 syntax
|
|
121
|
-
auto nodeList = mesh.getNodeList(false);
|
|
122
|
-
JsonObject metrics = doc["metrics"].to<JsonObject>();
|
|
123
|
-
metrics["total_nodes"] = nodeList.size() + 1;
|
|
124
|
-
metrics["online_nodes"] = nodeList.size() + 1;
|
|
125
|
-
|
|
126
|
-
doc["update_type"] = "incremental";
|
|
127
|
-
|
|
128
|
-
String output;
|
|
129
|
-
serializeJson(doc, output);
|
|
130
|
-
return output;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Check if topology has changed since last check
|
|
135
|
-
* Updates internal hash if changed
|
|
136
|
-
*/
|
|
137
|
-
bool hasTopologyChanged() {
|
|
138
|
-
String currentHash = calculateTopologyHash();
|
|
139
|
-
if (currentHash != lastTopologyHash) {
|
|
140
|
-
lastTopologyHash = currentHash;
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
private:
|
|
147
|
-
/**
|
|
148
|
-
* Add node information to JSON array
|
|
149
|
-
*/
|
|
150
|
-
void addNodeInfo(JsonArray& nodes, uint32_t nodeId, const char* role) {
|
|
151
|
-
JsonObject node = nodes.add<JsonObject>(); // ArduinoJson v7 syntax
|
|
152
|
-
node["node_id"] = generateDeviceId(nodeId);
|
|
153
|
-
node["role"] = role;
|
|
154
|
-
node["status"] = "online";
|
|
155
|
-
node["last_seen"] = getISO8601Timestamp();
|
|
156
|
-
|
|
157
|
-
// Gateway node has additional info
|
|
158
|
-
if (nodeId == mesh.getNodeId()) {
|
|
159
|
-
node["firmware_version"] = firmwareVersion;
|
|
160
|
-
node["uptime_seconds"] = millis() / 1000;
|
|
161
|
-
#if defined(ESP32) || defined(ESP8266)
|
|
162
|
-
node["free_memory_kb"] = ESP.getFreeHeap() / 1024;
|
|
163
|
-
#else
|
|
164
|
-
node["free_memory_kb"] = 0;
|
|
165
|
-
#endif
|
|
166
|
-
node["connection_count"] = mesh.getNodeList().size();
|
|
167
|
-
} else {
|
|
168
|
-
// For other nodes, use placeholder values
|
|
169
|
-
// TODO: Get actual values from node status messages
|
|
170
|
-
node["firmware_version"] = "SN 2.3.4";
|
|
171
|
-
node["uptime_seconds"] = 0;
|
|
172
|
-
node["free_memory_kb"] = 0;
|
|
173
|
-
node["connection_count"] = 0;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Add connection information to JSON array
|
|
179
|
-
*/
|
|
180
|
-
void addConnectionInfo(JsonArray& connections) {
|
|
181
|
-
// Get direct connections with quality metrics
|
|
182
|
-
auto connDetails = mesh.getConnectionDetails();
|
|
183
|
-
|
|
184
|
-
String gatewayId = generateDeviceId(mesh.getNodeId());
|
|
185
|
-
|
|
186
|
-
for (auto& conn : connDetails) {
|
|
187
|
-
JsonObject connObj = connections.add<JsonObject>(); // ArduinoJson v7 syntax
|
|
188
|
-
connObj["from_node"] = gatewayId;
|
|
189
|
-
connObj["to_node"] = generateDeviceId(conn.nodeId);
|
|
190
|
-
connObj["quality"] = conn.quality;
|
|
191
|
-
connObj["latency_ms"] = conn.avgLatency;
|
|
192
|
-
connObj["rssi"] = conn.rssi;
|
|
193
|
-
connObj["hop_count"] = conn.hopCount;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// TODO: Add indirect connections from mesh topology
|
|
197
|
-
// For now, we only report direct connections from gateway
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Add connection information for a specific node
|
|
202
|
-
*/
|
|
203
|
-
void addConnectionInfoForNode(JsonArray& connections, uint32_t nodeId) {
|
|
204
|
-
auto connDetails = mesh.getConnectionDetails();
|
|
205
|
-
String gatewayId = generateDeviceId(mesh.getNodeId());
|
|
206
|
-
String targetId = generateDeviceId(nodeId);
|
|
207
|
-
|
|
208
|
-
for (auto& conn : connDetails) {
|
|
209
|
-
if (conn.nodeId == nodeId) {
|
|
210
|
-
JsonObject connObj = connections.add<JsonObject>(); // ArduinoJson v7 syntax
|
|
211
|
-
connObj["from_node"] = gatewayId;
|
|
212
|
-
connObj["to_node"] = targetId;
|
|
213
|
-
connObj["quality"] = conn.quality;
|
|
214
|
-
connObj["latency_ms"] = conn.avgLatency;
|
|
215
|
-
connObj["rssi"] = conn.rssi;
|
|
216
|
-
connObj["hop_count"] = conn.hopCount;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Calculate network diameter (max hop count)
|
|
223
|
-
*/
|
|
224
|
-
int calculateNetworkDiameter() {
|
|
225
|
-
int maxHops = 0;
|
|
226
|
-
auto nodeList = mesh.getNodeList(false);
|
|
227
|
-
|
|
228
|
-
for (auto nodeId : nodeList) {
|
|
229
|
-
int hops = mesh.getHopCount(nodeId);
|
|
230
|
-
if (hops > maxHops) {
|
|
231
|
-
maxHops = hops;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return maxHops;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Calculate average connection quality
|
|
240
|
-
*/
|
|
241
|
-
float calculateAvgQuality() {
|
|
242
|
-
auto connDetails = mesh.getConnectionDetails();
|
|
243
|
-
|
|
244
|
-
if (connDetails.empty()) {
|
|
245
|
-
return 0.0;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
int totalQuality = 0;
|
|
249
|
-
for (auto& conn : connDetails) {
|
|
250
|
-
totalQuality += conn.quality;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return (float)totalQuality / connDetails.size();
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Calculate network throughput (messages per second)
|
|
258
|
-
*/
|
|
259
|
-
float calculateThroughput() {
|
|
260
|
-
// TODO: Implement actual throughput tracking
|
|
261
|
-
// For now return placeholder
|
|
262
|
-
return 12.4;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Calculate topology hash for change detection
|
|
267
|
-
*/
|
|
268
|
-
String calculateTopologyHash() {
|
|
269
|
-
auto nodeList = mesh.getNodeList(true);
|
|
270
|
-
String hash = String(nodeList.size());
|
|
271
|
-
for (auto nodeId : nodeList) {
|
|
272
|
-
hash += String(nodeId);
|
|
273
|
-
}
|
|
274
|
-
return hash;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Generate device ID in Alteriom format (ALT-XXXXXXXXXXXX)
|
|
279
|
-
*/
|
|
280
|
-
String generateDeviceId(uint32_t nodeId) {
|
|
281
|
-
char deviceId[20];
|
|
282
|
-
snprintf(deviceId, sizeof(deviceId), "ALT-%012X", nodeId);
|
|
283
|
-
return String(deviceId);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Get current timestamp in ISO 8601 format
|
|
288
|
-
* TODO: Use proper NTP time if available
|
|
289
|
-
*/
|
|
290
|
-
String getISO8601Timestamp() {
|
|
291
|
-
// For now, use epoch-based timestamp
|
|
292
|
-
// In production, this should use actual NTP-synced time
|
|
293
|
-
unsigned long ms = millis();
|
|
294
|
-
char timestamp[32];
|
|
295
|
-
snprintf(timestamp, sizeof(timestamp), "2025-10-12T%02lu:%02lu:%02luZ",
|
|
296
|
-
(ms / 3600000) % 24,
|
|
297
|
-
(ms / 60000) % 60,
|
|
298
|
-
(ms / 1000) % 60);
|
|
299
|
-
return String(timestamp);
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
#endif // MESH_TOPOLOGY_REPORTER_HPP
|
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
#include <Arduino.h>
|
|
2
|
-
#include "painlessTaskOptions.h" // Must be first to configure TaskScheduler
|
|
3
|
-
#include <TaskScheduler.h> // Required for LDF to find TaskScheduler dependency
|
|
4
|
-
#include "painlessMesh.h"
|
|
5
|
-
#include <PubSubClient.h>
|
|
6
|
-
#include "mqtt_command_bridge.hpp"
|
|
7
|
-
#include "mesh_topology_reporter.hpp"
|
|
8
|
-
#include "mesh_event_publisher.hpp"
|
|
9
|
-
|
|
10
|
-
// Mesh configuration
|
|
11
|
-
#define MESH_PREFIX "AlteriomMesh"
|
|
12
|
-
#define MESH_PASSWORD "somethingSneaky"
|
|
13
|
-
#define MESH_PORT 5555
|
|
14
|
-
|
|
15
|
-
// WiFi configuration
|
|
16
|
-
#define STATION_SSID "YourWiFi"
|
|
17
|
-
#define STATION_PASSWORD "YourPassword"
|
|
18
|
-
|
|
19
|
-
// MQTT configuration
|
|
20
|
-
#define MQTT_BROKER_IP "192.168.1.100"
|
|
21
|
-
#define MQTT_BROKER_PORT 1883
|
|
22
|
-
#define MQTT_CLIENT_ID "painlessMesh-commandBridge"
|
|
23
|
-
|
|
24
|
-
Scheduler userScheduler;
|
|
25
|
-
painlessMesh mesh;
|
|
26
|
-
WiFiClient wifiClient;
|
|
27
|
-
PubSubClient mqttClient(wifiClient);
|
|
28
|
-
MqttCommandBridge* commandBridge;
|
|
29
|
-
MeshTopologyReporter* topologyReporter;
|
|
30
|
-
MeshEventPublisher* eventPublisher;
|
|
31
|
-
|
|
32
|
-
// Task for MQTT reconnection
|
|
33
|
-
Task taskMqttReconnect(TASK_SECOND * 5, TASK_FOREVER, []() {
|
|
34
|
-
if (!mqttClient.connected()) {
|
|
35
|
-
Serial.println("MQTT disconnected, reconnecting...");
|
|
36
|
-
if (mqttClient.connect(MQTT_CLIENT_ID)) {
|
|
37
|
-
Serial.println("MQTT reconnected!");
|
|
38
|
-
commandBridge->begin(); // Re-subscribe to topics
|
|
39
|
-
} else {
|
|
40
|
-
Serial.printf("MQTT reconnect failed, rc=%d\n", mqttClient.state());
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Task for periodic gateway status
|
|
46
|
-
Task taskGatewayStatus(TASK_MINUTE, TASK_FOREVER, []() {
|
|
47
|
-
if (mqttClient.connected()) {
|
|
48
|
-
JsonDocument status; // ArduinoJson v7: automatic sizing
|
|
49
|
-
status["gateway_id"] = mesh.getNodeId();
|
|
50
|
-
status["status"] = "online";
|
|
51
|
-
status["uptime"] = millis() / 1000;
|
|
52
|
-
status["free_memory"] = ESP.getFreeHeap();
|
|
53
|
-
status["connected_nodes"] = mesh.getNodeList().size();
|
|
54
|
-
status["wifi_rssi"] = WiFi.RSSI();
|
|
55
|
-
|
|
56
|
-
String payload;
|
|
57
|
-
serializeJson(status, payload);
|
|
58
|
-
|
|
59
|
-
mqttClient.publish("mesh/gateway/status", payload.c_str());
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// Task for topology updates (full topology every 60 seconds)
|
|
64
|
-
Task taskTopology(TASK_SECOND * 60, TASK_FOREVER, []() {
|
|
65
|
-
if (mqttClient.connected() && topologyReporter != nullptr) {
|
|
66
|
-
Serial.println("[Topology] Publishing full mesh topology...");
|
|
67
|
-
|
|
68
|
-
String topology = topologyReporter->generateFullTopology();
|
|
69
|
-
bool success = mqttClient.publish("alteriom/mesh/MESH-001/topology", topology.c_str());
|
|
70
|
-
|
|
71
|
-
if (success) {
|
|
72
|
-
Serial.printf("[Topology] ✅ Published (%d bytes)\n", topology.length());
|
|
73
|
-
} else {
|
|
74
|
-
Serial.println("[Topology] ❌ Failed to publish (message too large or MQTT error)");
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// Task for incremental topology updates (check every 5 seconds)
|
|
80
|
-
Task taskTopologyIncremental(TASK_SECOND * 5, TASK_FOREVER, []() {
|
|
81
|
-
if (mqttClient.connected() && topologyReporter != nullptr) {
|
|
82
|
-
if (topologyReporter->hasTopologyChanged()) {
|
|
83
|
-
Serial.println("[Topology] Topology changed, publishing incremental update...");
|
|
84
|
-
|
|
85
|
-
String topology = topologyReporter->generateFullTopology();
|
|
86
|
-
bool success = mqttClient.publish("alteriom/mesh/MESH-001/topology", topology.c_str());
|
|
87
|
-
|
|
88
|
-
if (success) {
|
|
89
|
-
Serial.printf("[Topology] ✅ Published incremental update (%d bytes)\n", topology.length());
|
|
90
|
-
} else {
|
|
91
|
-
Serial.println("[Topology] ❌ Failed to publish incremental update");
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
void setup() {
|
|
98
|
-
Serial.begin(115200);
|
|
99
|
-
|
|
100
|
-
Serial.println("\n\n=================================");
|
|
101
|
-
Serial.println("MQTT Command Bridge for painlessMesh");
|
|
102
|
-
Serial.println("=================================\n");
|
|
103
|
-
|
|
104
|
-
// Initialize mesh as bridge (root node)
|
|
105
|
-
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
106
|
-
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT, WIFI_AP_STA);
|
|
107
|
-
mesh.setRoot(true);
|
|
108
|
-
mesh.setContainsRoot(true);
|
|
109
|
-
|
|
110
|
-
// Connect to WiFi station
|
|
111
|
-
Serial.printf("Connecting to WiFi: %s\n", STATION_SSID);
|
|
112
|
-
mesh.stationManual(STATION_SSID, STATION_PASSWORD);
|
|
113
|
-
|
|
114
|
-
// Wait for WiFi connection
|
|
115
|
-
int attempts = 0;
|
|
116
|
-
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
|
|
117
|
-
delay(500);
|
|
118
|
-
Serial.print(".");
|
|
119
|
-
attempts++;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (WiFi.status() == WL_CONNECTED) {
|
|
123
|
-
Serial.printf("\nWiFi connected!\n");
|
|
124
|
-
Serial.printf("IP Address: %s\n", WiFi.localIP().toString().c_str());
|
|
125
|
-
Serial.printf("RSSI: %d dBm\n", WiFi.RSSI());
|
|
126
|
-
} else {
|
|
127
|
-
Serial.println("\nWiFi connection failed!");
|
|
128
|
-
Serial.println("Bridge will continue with mesh-only mode");
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Configure MQTT
|
|
132
|
-
mqttClient.setServer(MQTT_BROKER_IP, MQTT_BROKER_PORT);
|
|
133
|
-
mqttClient.setBufferSize(2048); // Increase buffer for larger messages
|
|
134
|
-
|
|
135
|
-
// Connect to MQTT broker
|
|
136
|
-
Serial.printf("\nConnecting to MQTT broker: %s:%d\n", MQTT_BROKER_IP, MQTT_BROKER_PORT);
|
|
137
|
-
|
|
138
|
-
int mqttAttempts = 0;
|
|
139
|
-
while (!mqttClient.connected() && mqttAttempts < 10) {
|
|
140
|
-
Serial.print("Attempting MQTT connection...");
|
|
141
|
-
|
|
142
|
-
if (mqttClient.connect(MQTT_CLIENT_ID)) {
|
|
143
|
-
Serial.println("connected!");
|
|
144
|
-
} else {
|
|
145
|
-
Serial.printf("failed, rc=%d\n", mqttClient.state());
|
|
146
|
-
Serial.println("Error codes: -4=timeout, -3=conn lost, -2=conn failed, -1=disconnected");
|
|
147
|
-
delay(2000);
|
|
148
|
-
mqttAttempts++;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (!mqttClient.connected()) {
|
|
153
|
-
Serial.println("WARNING: MQTT connection failed, bridge will retry");
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Initialize topology reporter and event publisher first
|
|
157
|
-
topologyReporter = new MeshTopologyReporter(mesh, "MESH-001", "GW 2.3.4");
|
|
158
|
-
eventPublisher = new MeshEventPublisher(mesh, mqttClient, "MESH-001", "alteriom/mesh/MESH-001/events", "GW 2.3.4");
|
|
159
|
-
|
|
160
|
-
Serial.println("\n✅ Topology Reporter initialized");
|
|
161
|
-
Serial.println("✅ Event Publisher initialized");
|
|
162
|
-
|
|
163
|
-
// Initialize bidirectional MQTT-mesh bridge with topology reporter
|
|
164
|
-
commandBridge = new MqttCommandBridge(mesh, mqttClient, topologyReporter);
|
|
165
|
-
commandBridge->setMqttCallback();
|
|
166
|
-
commandBridge->setMeshCallback();
|
|
167
|
-
commandBridge->begin();
|
|
168
|
-
|
|
169
|
-
// Add background tasks
|
|
170
|
-
userScheduler.addTask(taskMqttReconnect);
|
|
171
|
-
userScheduler.addTask(taskGatewayStatus);
|
|
172
|
-
userScheduler.addTask(taskTopology);
|
|
173
|
-
userScheduler.addTask(taskTopologyIncremental);
|
|
174
|
-
|
|
175
|
-
taskMqttReconnect.enable();
|
|
176
|
-
taskGatewayStatus.enable();
|
|
177
|
-
taskTopology.enable();
|
|
178
|
-
taskTopologyIncremental.enable();
|
|
179
|
-
|
|
180
|
-
// Mesh callbacks with schema-compliant event publishing
|
|
181
|
-
mesh.onNewConnection([](uint32_t nodeId) {
|
|
182
|
-
Serial.printf("[Mesh] 🔗 New node connected: %u\n", nodeId);
|
|
183
|
-
|
|
184
|
-
// Publish schema-compliant node join event
|
|
185
|
-
if (eventPublisher != nullptr) {
|
|
186
|
-
eventPublisher->publishNodeJoin(nodeId);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Publish incremental topology update
|
|
190
|
-
if (mqttClient.connected() && topologyReporter != nullptr) {
|
|
191
|
-
String topology = topologyReporter->generateIncrementalUpdate(nodeId, true);
|
|
192
|
-
mqttClient.publish("alteriom/mesh/MESH-001/topology", topology.c_str());
|
|
193
|
-
Serial.println("[Topology] Published incremental update (node join)");
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
mesh.onDroppedConnection([](uint32_t nodeId) {
|
|
198
|
-
Serial.printf("[Mesh] ⚠️ Node disconnected: %u\n", nodeId);
|
|
199
|
-
|
|
200
|
-
// Publish schema-compliant node leave event
|
|
201
|
-
if (eventPublisher != nullptr) {
|
|
202
|
-
eventPublisher->publishNodeLeave(nodeId);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Publish incremental topology update
|
|
206
|
-
if (mqttClient.connected() && topologyReporter != nullptr) {
|
|
207
|
-
String topology = topologyReporter->generateIncrementalUpdate(nodeId, false);
|
|
208
|
-
mqttClient.publish("alteriom/mesh/MESH-001/topology", topology.c_str());
|
|
209
|
-
Serial.println("[Topology] Published incremental update (node leave)");
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
Serial.println("\n=== MQTT Command Bridge Ready ===");
|
|
214
|
-
Serial.printf("Gateway ID: %u\n", mesh.getNodeId());
|
|
215
|
-
Serial.printf("Connected Nodes: %d\n", mesh.getNodeList().size());
|
|
216
|
-
Serial.println("\nMQTT Topics:");
|
|
217
|
-
Serial.println(" Commands IN:");
|
|
218
|
-
Serial.println(" - mesh/command/{nodeId}");
|
|
219
|
-
Serial.println(" - mesh/command/broadcast");
|
|
220
|
-
Serial.println(" - mesh/config/{nodeId}/get");
|
|
221
|
-
Serial.println(" - mesh/config/{nodeId}/set");
|
|
222
|
-
Serial.println(" Messages OUT:");
|
|
223
|
-
Serial.println(" - mesh/response/{nodeId}");
|
|
224
|
-
Serial.println(" - mesh/status/{nodeId}");
|
|
225
|
-
Serial.println(" - mesh/sensor/{nodeId}");
|
|
226
|
-
Serial.println(" - mesh/health/{nodeId}");
|
|
227
|
-
Serial.println(" - mesh/gateway/status");
|
|
228
|
-
Serial.println(" - alteriom/mesh/MESH-001/topology (schema v0.5.0)");
|
|
229
|
-
Serial.println(" - alteriom/mesh/MESH-001/events (schema v0.5.0)");
|
|
230
|
-
Serial.println("\nSchema Compliance:");
|
|
231
|
-
Serial.println(" ✅ @alteriom/mqtt-schema v0.5.0");
|
|
232
|
-
Serial.println(" ✅ mesh_topology.schema.json");
|
|
233
|
-
Serial.println(" ✅ mesh_event.schema.json");
|
|
234
|
-
Serial.println("\nBridge is now listening for commands...\n");
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
void loop() {
|
|
238
|
-
mesh.update();
|
|
239
|
-
|
|
240
|
-
// Process MQTT messages
|
|
241
|
-
if (mqttClient.connected()) {
|
|
242
|
-
mqttClient.loop();
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Handle WiFi reconnection
|
|
246
|
-
if (WiFi.status() != WL_CONNECTED) {
|
|
247
|
-
static unsigned long lastReconnectAttempt = 0;
|
|
248
|
-
if (millis() - lastReconnectAttempt > 30000) {
|
|
249
|
-
Serial.println("WiFi disconnected, attempting reconnect...");
|
|
250
|
-
WiFi.reconnect();
|
|
251
|
-
lastReconnectAttempt = millis();
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|