@alteriom/painlessmesh 1.6.1 → 1.7.2
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/CHANGELOG.md +380 -143
- package/LICENSE +674 -674
- package/README.md +477 -434
- package/RELEASE_GUIDE.md +504 -418
- package/docs/DOCUMENTATION_MIGRATION_PLAN.md +175 -175
- package/docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md +1062 -0
- package/docs/MESH_TOPOLOGY_GUIDE.md +992 -0
- package/docs/MESH_TOPOLOGY_PROGRESS.md +422 -0
- package/docs/MQTT_BRIDGE_COMMANDS.md +894 -0
- package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +324 -0
- package/docs/MQTT_COMMAND_SCHEMA_PROPOSAL.md +576 -0
- package/docs/MQTT_SCHEMA_COMPLIANCE.md +285 -0
- package/docs/MQTT_SCHEMA_PROPOSALS.md +446 -0
- package/docs/MQTT_SCHEMA_REVIEW.md +690 -0
- package/docs/OTA_COMMANDS_REFERENCE.md +554 -0
- package/docs/PHASE1_GUIDE.md +349 -0
- package/docs/PHASE2_GUIDE.md +543 -0
- package/docs/README.md +77 -70
- package/docs/SCHEMA_VALIDATION_CHECKLIST.md +222 -0
- package/docs/alteriom/overview.md +507 -507
- package/docs/api/core-api.md +606 -606
- package/docs/architecture/mesh-architecture.md +378 -378
- package/docs/architecture/plugin-system.md +516 -516
- package/docs/getting-started/first-mesh.md +409 -409
- package/docs/getting-started/installation.md +274 -274
- package/docs/getting-started/quickstart.md +157 -157
- package/docs/improvements/FEATURE_PROPOSALS.md +337 -0
- package/docs/improvements/PHASE1_IMPLEMENTATION.md +325 -0
- package/docs/improvements/PHASE2_IMPLEMENTATION.md +567 -0
- package/docs/improvements/README.md +86 -68
- package/docs/improvements/ota-and-status-enhancements.md +911 -0
- package/docs/improvements/ota-status-architecture-diagrams.md +658 -0
- package/docs/improvements/ota-status-quick-reference.md +284 -0
- package/docs/platformio-publishing.md +255 -0
- package/docs/platformio-setup-summary.md +121 -0
- package/docs/troubleshooting/common-issues.md +520 -520
- package/docs/troubleshooting/faq.md +472 -472
- package/docs/tutorials/basic-examples.md +717 -717
- package/docs/wiki/API-Reference.md +245 -245
- package/docs/wiki/Complete-Documentation.md +122 -122
- package/examples/alteriom/README.md +139 -81
- package/examples/alteriom/alteriom.ino +186 -185
- package/examples/alteriom/alteriom_sensor_package.hpp +240 -127
- package/examples/alteriom/platformio.ini +24 -24
- package/examples/alteriomImproved/alteriom_sensor_package.hpp +224 -0
- package/examples/{alteriom → alteriomImproved}/improved_sensor_node.ino +245 -245
- package/examples/alteriomImproved/platformio.ini +25 -0
- package/examples/alteriomPhase1/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomPhase1/phase1_features.ino +242 -0
- package/examples/alteriomPhase1/platformio.ini +25 -0
- package/examples/alteriomPhase2/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomPhase2/phase2_features.ino +186 -0
- package/examples/alteriomPhase2/platformio.ini +25 -0
- package/examples/{alteriom → alteriomSensorNode}/alteriom_sensor_node.ino +183 -183
- package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomSensorNode/platformio.ini +25 -0
- package/examples/basic/basic.ino +66 -66
- package/examples/basic/platformio.ini +25 -25
- package/examples/bridge/bridge.ino +51 -51
- package/examples/bridge/mesh_event_publisher.hpp +253 -0
- package/examples/bridge/mesh_topology_reporter.hpp +303 -0
- package/examples/bridge/mqtt_command_bridge.hpp +459 -0
- package/examples/bridge/mqtt_status_bridge.hpp +519 -0
- package/examples/bridge/platformio.ini +25 -25
- package/examples/echoNode/echoNode.ino +33 -33
- package/examples/echoNode/platformio.ini +25 -25
- package/examples/logClient/logClient.ino +109 -109
- package/examples/logClient/platformio.ini +25 -25
- package/examples/logServer/logServer.ino +81 -81
- package/examples/logServer/platformio.ini +25 -25
- package/examples/meshCommandNode/alteriom_sensor_package.hpp +235 -0
- package/examples/meshCommandNode/meshCommandNode.ino +263 -0
- package/examples/meshCommandNode/platformio.ini +25 -0
- package/examples/mqttBridge/mqttBridge.ino +118 -118
- package/examples/mqttBridge/platformio.ini +26 -26
- package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +235 -0
- package/examples/mqttCommandBridge/mesh_event_publisher.hpp +253 -0
- package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +303 -0
- package/examples/mqttCommandBridge/mqttCommandBridge.ino +252 -0
- package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +459 -0
- package/examples/mqttCommandBridge/platformio.ini +26 -0
- package/examples/mqttStatusBridge/mqttStatusBridge.ino +216 -0
- package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +522 -0
- package/examples/mqttStatusBridge/platformio.ini +26 -0
- package/examples/mqttTopologyTest/README.md +467 -0
- package/examples/mqttTopologyTest/mqttTopologyTest.ino +748 -0
- package/examples/mqttTopologyTest/platformio.ini +26 -0
- package/examples/namedMesh/namedMesh.ino +97 -97
- package/examples/namedMesh/platformio.ini +25 -25
- package/examples/otaReceiver/otaReceiver.ino +79 -79
- package/examples/otaReceiver/platformio.ini +25 -25
- package/examples/otaSender/otaSender.ino +160 -151
- package/examples/otaSender/platformio.ini +25 -25
- package/examples/startHere/platformio.ini +25 -25
- package/examples/startHere/startHere.ino +159 -159
- package/examples/webServer/platformio.ini +27 -27
- package/examples/webServer/webServer.ino +89 -89
- package/keywords.txt +48 -48
- package/library.json +55 -34
- package/library.properties +10 -10
- package/package.json +86 -78
- package/src/AlteriomPainlessMesh.h +97 -97
- package/src/arduino/wifi.hpp +365 -365
- package/src/boost/asynctcp.hpp +279 -279
- package/src/painlessMesh.h +70 -70
- package/src/painlessMeshSTA.cpp +236 -236
- package/src/painlessMeshSTA.h +58 -58
- package/src/painlessTaskOptions.h +4 -4
- package/src/painlessmesh/base64.hpp +111 -111
- package/src/painlessmesh/buffer.hpp +229 -229
- package/src/painlessmesh/callback.hpp +91 -91
- package/src/painlessmesh/configuration.hpp +77 -77
- package/src/painlessmesh/connection.hpp +192 -192
- package/src/painlessmesh/layout.hpp +188 -188
- package/src/painlessmesh/logger.hpp +158 -158
- package/src/painlessmesh/memory.hpp +119 -119
- package/src/painlessmesh/mesh.hpp +761 -560
- package/src/painlessmesh/metrics.hpp +322 -322
- package/src/painlessmesh/ntp.hpp +263 -263
- package/src/painlessmesh/ota.hpp +582 -553
- package/src/painlessmesh/plugin.hpp +188 -188
- package/src/painlessmesh/protocol.hpp +813 -813
- package/src/painlessmesh/router.hpp +322 -322
- package/src/painlessmesh/tcp.hpp +71 -71
- package/src/painlessmesh/validation.hpp +238 -238
- package/src/plugin/performance.hpp +214 -214
- package/src/plugin/remote.hpp +64 -64
- package/src/scheduler.cpp +10 -10
- package/src/wifi.cpp +2 -2
|
@@ -0,0 +1,303 @@
|
|
|
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
|
+
DynamicJsonDocument doc(8192); // Large buffer for full topology
|
|
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
|
|
57
|
+
JsonArray nodes = doc.createNestedArray("nodes");
|
|
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
|
|
66
|
+
JsonArray connections = doc.createNestedArray("connections");
|
|
67
|
+
addConnectionInfo(connections);
|
|
68
|
+
|
|
69
|
+
// Network metrics
|
|
70
|
+
JsonObject metrics = doc.createNestedObject("metrics");
|
|
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
|
+
DynamicJsonDocument doc(2048);
|
|
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
|
|
105
|
+
JsonArray nodes = doc.createNestedArray("nodes");
|
|
106
|
+
if (joined) {
|
|
107
|
+
addNodeInfo(nodes, nodeId, "sensor");
|
|
108
|
+
} else {
|
|
109
|
+
// For node leaving, mark as offline
|
|
110
|
+
JsonObject node = nodes.createNestedObject();
|
|
111
|
+
node["node_id"] = generateDeviceId(nodeId);
|
|
112
|
+
node["status"] = "offline";
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Update connections
|
|
116
|
+
JsonArray connections = doc.createNestedArray("connections");
|
|
117
|
+
// Add connections related to this node
|
|
118
|
+
addConnectionInfoForNode(connections, nodeId);
|
|
119
|
+
|
|
120
|
+
// Updated metrics
|
|
121
|
+
auto nodeList = mesh.getNodeList(false);
|
|
122
|
+
JsonObject metrics = doc.createNestedObject("metrics");
|
|
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.createNestedObject();
|
|
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.createNestedObject();
|
|
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.createNestedObject();
|
|
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
|