@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.
Files changed (129) hide show
  1. package/CHANGELOG.md +380 -143
  2. package/LICENSE +674 -674
  3. package/README.md +477 -434
  4. package/RELEASE_GUIDE.md +504 -418
  5. package/docs/DOCUMENTATION_MIGRATION_PLAN.md +175 -175
  6. package/docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md +1062 -0
  7. package/docs/MESH_TOPOLOGY_GUIDE.md +992 -0
  8. package/docs/MESH_TOPOLOGY_PROGRESS.md +422 -0
  9. package/docs/MQTT_BRIDGE_COMMANDS.md +894 -0
  10. package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +324 -0
  11. package/docs/MQTT_COMMAND_SCHEMA_PROPOSAL.md +576 -0
  12. package/docs/MQTT_SCHEMA_COMPLIANCE.md +285 -0
  13. package/docs/MQTT_SCHEMA_PROPOSALS.md +446 -0
  14. package/docs/MQTT_SCHEMA_REVIEW.md +690 -0
  15. package/docs/OTA_COMMANDS_REFERENCE.md +554 -0
  16. package/docs/PHASE1_GUIDE.md +349 -0
  17. package/docs/PHASE2_GUIDE.md +543 -0
  18. package/docs/README.md +77 -70
  19. package/docs/SCHEMA_VALIDATION_CHECKLIST.md +222 -0
  20. package/docs/alteriom/overview.md +507 -507
  21. package/docs/api/core-api.md +606 -606
  22. package/docs/architecture/mesh-architecture.md +378 -378
  23. package/docs/architecture/plugin-system.md +516 -516
  24. package/docs/getting-started/first-mesh.md +409 -409
  25. package/docs/getting-started/installation.md +274 -274
  26. package/docs/getting-started/quickstart.md +157 -157
  27. package/docs/improvements/FEATURE_PROPOSALS.md +337 -0
  28. package/docs/improvements/PHASE1_IMPLEMENTATION.md +325 -0
  29. package/docs/improvements/PHASE2_IMPLEMENTATION.md +567 -0
  30. package/docs/improvements/README.md +86 -68
  31. package/docs/improvements/ota-and-status-enhancements.md +911 -0
  32. package/docs/improvements/ota-status-architecture-diagrams.md +658 -0
  33. package/docs/improvements/ota-status-quick-reference.md +284 -0
  34. package/docs/platformio-publishing.md +255 -0
  35. package/docs/platformio-setup-summary.md +121 -0
  36. package/docs/troubleshooting/common-issues.md +520 -520
  37. package/docs/troubleshooting/faq.md +472 -472
  38. package/docs/tutorials/basic-examples.md +717 -717
  39. package/docs/wiki/API-Reference.md +245 -245
  40. package/docs/wiki/Complete-Documentation.md +122 -122
  41. package/examples/alteriom/README.md +139 -81
  42. package/examples/alteriom/alteriom.ino +186 -185
  43. package/examples/alteriom/alteriom_sensor_package.hpp +240 -127
  44. package/examples/alteriom/platformio.ini +24 -24
  45. package/examples/alteriomImproved/alteriom_sensor_package.hpp +224 -0
  46. package/examples/{alteriom → alteriomImproved}/improved_sensor_node.ino +245 -245
  47. package/examples/alteriomImproved/platformio.ini +25 -0
  48. package/examples/alteriomPhase1/alteriom_sensor_package.hpp +224 -0
  49. package/examples/alteriomPhase1/phase1_features.ino +242 -0
  50. package/examples/alteriomPhase1/platformio.ini +25 -0
  51. package/examples/alteriomPhase2/alteriom_sensor_package.hpp +224 -0
  52. package/examples/alteriomPhase2/phase2_features.ino +186 -0
  53. package/examples/alteriomPhase2/platformio.ini +25 -0
  54. package/examples/{alteriom → alteriomSensorNode}/alteriom_sensor_node.ino +183 -183
  55. package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +224 -0
  56. package/examples/alteriomSensorNode/platformio.ini +25 -0
  57. package/examples/basic/basic.ino +66 -66
  58. package/examples/basic/platformio.ini +25 -25
  59. package/examples/bridge/bridge.ino +51 -51
  60. package/examples/bridge/mesh_event_publisher.hpp +253 -0
  61. package/examples/bridge/mesh_topology_reporter.hpp +303 -0
  62. package/examples/bridge/mqtt_command_bridge.hpp +459 -0
  63. package/examples/bridge/mqtt_status_bridge.hpp +519 -0
  64. package/examples/bridge/platformio.ini +25 -25
  65. package/examples/echoNode/echoNode.ino +33 -33
  66. package/examples/echoNode/platformio.ini +25 -25
  67. package/examples/logClient/logClient.ino +109 -109
  68. package/examples/logClient/platformio.ini +25 -25
  69. package/examples/logServer/logServer.ino +81 -81
  70. package/examples/logServer/platformio.ini +25 -25
  71. package/examples/meshCommandNode/alteriom_sensor_package.hpp +235 -0
  72. package/examples/meshCommandNode/meshCommandNode.ino +263 -0
  73. package/examples/meshCommandNode/platformio.ini +25 -0
  74. package/examples/mqttBridge/mqttBridge.ino +118 -118
  75. package/examples/mqttBridge/platformio.ini +26 -26
  76. package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +235 -0
  77. package/examples/mqttCommandBridge/mesh_event_publisher.hpp +253 -0
  78. package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +303 -0
  79. package/examples/mqttCommandBridge/mqttCommandBridge.ino +252 -0
  80. package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +459 -0
  81. package/examples/mqttCommandBridge/platformio.ini +26 -0
  82. package/examples/mqttStatusBridge/mqttStatusBridge.ino +216 -0
  83. package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +522 -0
  84. package/examples/mqttStatusBridge/platformio.ini +26 -0
  85. package/examples/mqttTopologyTest/README.md +467 -0
  86. package/examples/mqttTopologyTest/mqttTopologyTest.ino +748 -0
  87. package/examples/mqttTopologyTest/platformio.ini +26 -0
  88. package/examples/namedMesh/namedMesh.ino +97 -97
  89. package/examples/namedMesh/platformio.ini +25 -25
  90. package/examples/otaReceiver/otaReceiver.ino +79 -79
  91. package/examples/otaReceiver/platformio.ini +25 -25
  92. package/examples/otaSender/otaSender.ino +160 -151
  93. package/examples/otaSender/platformio.ini +25 -25
  94. package/examples/startHere/platformio.ini +25 -25
  95. package/examples/startHere/startHere.ino +159 -159
  96. package/examples/webServer/platformio.ini +27 -27
  97. package/examples/webServer/webServer.ino +89 -89
  98. package/keywords.txt +48 -48
  99. package/library.json +55 -34
  100. package/library.properties +10 -10
  101. package/package.json +86 -78
  102. package/src/AlteriomPainlessMesh.h +97 -97
  103. package/src/arduino/wifi.hpp +365 -365
  104. package/src/boost/asynctcp.hpp +279 -279
  105. package/src/painlessMesh.h +70 -70
  106. package/src/painlessMeshSTA.cpp +236 -236
  107. package/src/painlessMeshSTA.h +58 -58
  108. package/src/painlessTaskOptions.h +4 -4
  109. package/src/painlessmesh/base64.hpp +111 -111
  110. package/src/painlessmesh/buffer.hpp +229 -229
  111. package/src/painlessmesh/callback.hpp +91 -91
  112. package/src/painlessmesh/configuration.hpp +77 -77
  113. package/src/painlessmesh/connection.hpp +192 -192
  114. package/src/painlessmesh/layout.hpp +188 -188
  115. package/src/painlessmesh/logger.hpp +158 -158
  116. package/src/painlessmesh/memory.hpp +119 -119
  117. package/src/painlessmesh/mesh.hpp +761 -560
  118. package/src/painlessmesh/metrics.hpp +322 -322
  119. package/src/painlessmesh/ntp.hpp +263 -263
  120. package/src/painlessmesh/ota.hpp +582 -553
  121. package/src/painlessmesh/plugin.hpp +188 -188
  122. package/src/painlessmesh/protocol.hpp +813 -813
  123. package/src/painlessmesh/router.hpp +322 -322
  124. package/src/painlessmesh/tcp.hpp +71 -71
  125. package/src/painlessmesh/validation.hpp +238 -238
  126. package/src/plugin/performance.hpp +214 -214
  127. package/src/plugin/remote.hpp +64 -64
  128. package/src/scheduler.cpp +10 -10
  129. package/src/wifi.cpp +2 -2
@@ -1,246 +1,246 @@
1
- /**
2
- * Improved Sensor Node Example with Validation and Metrics
3
- *
4
- * This example demonstrates the new security and performance improvements
5
- * in painlessMesh including input validation, rate limiting, and performance
6
- * metrics.
7
- */
8
-
9
- #include "alteriom_sensor_package.hpp"
10
- #include "painlessMesh.h"
11
-
12
- // Note: The improvement modules (validation, metrics, memory) are automatically
13
- // included through painlessMesh.h when the corresponding features are enabled
14
-
15
- #define MESH_PREFIX "AlteriomImprovedMesh"
16
- #define MESH_PASSWORD "securePassword123"
17
- #define MESH_PORT 5555
18
-
19
- #define SENSOR_TASK_INTERVAL 30000 // Send sensor data every 30 seconds
20
- #define METRICS_TASK_INTERVAL 60000 // Report metrics every minute
21
- #define VALIDATION_ENABLED true // Enable message validation
22
-
23
- Scheduler userScheduler;
24
- painlessMesh mesh;
25
-
26
- // New improvement features
27
- painlessmesh::validation::MessageValidator validator;
28
- painlessmesh::validation::RateLimiter rateLimiter(5, 1000); // 5 msgs/sec max
29
- painlessmesh::metrics::MetricsCollector metrics;
30
- painlessmesh::memory::ObjectPool<alteriom::SensorPackage> sensorPool(5);
31
-
32
- // Task declarations
33
- Task sensorTask(SENSOR_TASK_INTERVAL, TASK_FOREVER, &sendSensorData);
34
- Task metricsTask(METRICS_TASK_INTERVAL, TASK_FOREVER, &reportMetrics);
35
-
36
- void setup() {
37
- Serial.begin(115200);
38
-
39
- // Configure validation with custom settings
40
- painlessmesh::validation::ValidationConfig config;
41
- config.max_message_size = 4096; // Smaller max size for sensors
42
- config.max_string_length = 256; // Reasonable string limits
43
- config.strict_type_checking = true; // Enable strict validation
44
- validator.set_config(config);
45
-
46
- mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
47
- mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
48
- mesh.onReceive(&receivedCallback);
49
- mesh.onNewConnection(&newConnectionCallback);
50
- mesh.onChangedConnections(&changedConnectionCallback);
51
- mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
52
-
53
- userScheduler.addTask(sensorTask);
54
- userScheduler.addTask(metricsTask);
55
- sensorTask.enable();
56
- metricsTask.enable();
57
-
58
- Serial.println("Enhanced Sensor Node Started");
59
- Serial.println(
60
- "Features: Validation, Rate Limiting, Metrics, Memory Optimization");
61
- }
62
-
63
- void loop() {
64
- mesh.update();
65
- metrics.update(); // Update performance metrics
66
- }
67
-
68
- void sendSensorData() {
69
- // Use object pool for memory efficiency
70
- auto sensorPackage = sensorPool.acquire();
71
-
72
- // Simulate sensor readings
73
- sensorPackage->temperature = 20.0 + random(-5, 15); // 15-35°C
74
- sensorPackage->humidity = 40.0 + random(0, 40); // 40-80%
75
- sensorPackage->pressure = 1013.25 + random(-50, 50); // Near sea level
76
- sensorPackage->batteryLevel = 85 + random(-10, 15); // Battery simulation
77
- sensorPackage->sensorId = mesh.getNodeId();
78
- sensorPackage->timestamp = mesh.getNodeTime();
79
-
80
- // Convert to message variant
81
- painlessmesh::protocol::Variant variant(sensorPackage.get());
82
- String message;
83
- variant.printTo(message);
84
-
85
- // Validate message before sending (optional security check)
86
- if (VALIDATION_ENABLED) {
87
- JsonDocument doc;
88
- deserializeJson(doc, message);
89
- JsonObject obj = doc.as<JsonObject>();
90
-
91
- auto result = validator.validate_message(obj, message.length());
92
- if (result != painlessmesh::validation::ValidationResult::VALID) {
93
- Serial.printf("Message validation failed: %s\n",
94
- validator.get_error_message(result));
95
- sensorPool.release(std::move(sensorPackage)); // Return to pool
96
- return;
97
- }
98
- }
99
-
100
- // Send the message
101
- bool sent = mesh.sendBroadcast(message);
102
- if (sent) {
103
- metrics.message_stats().record_sent_message(message.length());
104
- Serial.printf(
105
- "Sensor data sent: T=%.1f°C, H=%.1f%%, P=%.1f hPa, Batt=%d%%\n",
106
- sensorPackage->temperature, sensorPackage->humidity,
107
- sensorPackage->pressure, sensorPackage->batteryLevel);
108
- } else {
109
- metrics.message_stats().record_dropped_message();
110
- Serial.println("Failed to send sensor data - network congestion");
111
- }
112
-
113
- // Return object to pool for reuse
114
- sensorPool.release(std::move(sensorPackage));
115
- }
116
-
117
- void reportMetrics() {
118
- String metricsJson = metrics.generate_status_json();
119
- Serial.println("=== Performance Metrics ===");
120
- Serial.println(metricsJson);
121
-
122
- // Check for performance issues
123
- if (metrics.has_performance_issues()) {
124
- Serial.println("WARNING: Performance issues detected!");
125
-
126
- if (metrics.memory_stats().is_memory_critical()) {
127
- Serial.println("- Critical memory shortage");
128
- }
129
-
130
- if (metrics.message_stats().packet_loss_rate() > 0.1) {
131
- Serial.printf("- High packet loss: %.1f%%\n",
132
- metrics.message_stats().packet_loss_rate() * 100);
133
- }
134
-
135
- if (metrics.topology_stats().connection_stability() < 0.8) {
136
- Serial.printf("- Poor connection stability: %.1f%%\n",
137
- metrics.topology_stats().connection_stability() * 100);
138
- }
139
- }
140
-
141
- Serial.println("===========================");
142
- }
143
-
144
- void receivedCallback(uint32_t from, String& msg) {
145
- // Record metrics
146
- metrics.message_stats().record_received_message(msg.length());
147
-
148
- // Rate limiting check
149
- if (!rateLimiter.allow_message(from)) {
150
- Serial.printf("Rate limit exceeded for node %u, dropping message\n", from);
151
- metrics.message_stats().record_dropped_message();
152
- return;
153
- }
154
-
155
- // Validate incoming message
156
- if (VALIDATION_ENABLED) {
157
- JsonDocument doc;
158
- DeserializationError error = deserializeJson(doc, msg);
159
-
160
- if (error) {
161
- Serial.printf("JSON parsing failed from %u: %s\n", from, error.c_str());
162
- metrics.message_stats().record_parse_error();
163
- return;
164
- }
165
-
166
- JsonObject obj = doc.as<JsonObject>();
167
- auto result = validator.validate_message(obj, msg.length());
168
-
169
- if (result != painlessmesh::validation::ValidationResult::VALID) {
170
- Serial.printf("Message validation failed from %u: %s\n", from,
171
- validator.get_error_message(result));
172
- metrics.message_stats().record_validation_error();
173
- return;
174
- }
175
- }
176
-
177
- // Process the validated message
178
- JsonDocument doc;
179
- deserializeJson(doc, msg);
180
- JsonObject obj = doc.as<JsonObject>();
181
- uint8_t msgType = obj["type"];
182
-
183
- switch (msgType) {
184
- case 200: // SensorPackage
185
- handleSensorData(alteriom::SensorPackage(obj), from);
186
- break;
187
- case 201: // CommandPackage
188
- handleCommand(alteriom::CommandPackage(obj), from);
189
- break;
190
- case 202: // StatusPackage
191
- handleStatus(alteriom::StatusPackage(obj), from);
192
- break;
193
- default:
194
- Serial.printf("Unknown message type %d from %u\n", msgType, from);
195
- }
196
- }
197
-
198
- void handleSensorData(alteriom::SensorPackage sensorData, uint32_t from) {
199
- Serial.printf("Sensor data from %u: T=%.1f°C, H=%.1f%%, P=%.1f hPa\n", from,
200
- sensorData.temperature, sensorData.humidity,
201
- sensorData.pressure);
202
- }
203
-
204
- void handleCommand(alteriom::CommandPackage command, uint32_t from) {
205
- Serial.printf("Command from %u: cmd=%d, target=%u\n", from, command.command,
206
- command.targetDevice);
207
-
208
- // Example: Handle LED control command
209
- if (command.command == 1 && command.targetDevice == mesh.getNodeId()) {
210
- digitalWrite(LED_BUILTIN,
211
- command.parameters.indexOf("ON") >= 0 ? HIGH : LOW);
212
- Serial.println("LED command executed");
213
- }
214
- }
215
-
216
- void handleStatus(alteriom::StatusPackage status, uint32_t from) {
217
- Serial.printf("Status from %u: status=%d, uptime=%u, mem=%u\n", from,
218
- status.deviceStatus, status.uptime, status.freeMemory);
219
- }
220
-
221
- void newConnectionCallback(uint32_t nodeId) {
222
- Serial.printf("New connection: %u\n", nodeId);
223
-
224
- // Update topology metrics
225
- auto nodeList = mesh.getNodeList();
226
- metrics.topology_stats().record_topology_change(
227
- nodeList.size() + 1, // +1 for this node
228
- mesh.connectionCount(),
229
- 0 // Max hops calculation not implemented in this example
230
- );
231
- }
232
-
233
- void changedConnectionCallback() {
234
- Serial.printf("Changed connections\n");
235
-
236
- // Update topology metrics
237
- auto nodeList = mesh.getNodeList();
238
- metrics.topology_stats().record_topology_change(
239
- nodeList.size() + 1, mesh.connectionCount(),
240
- 0 // Max hops calculation not implemented in this example
241
- );
242
- }
243
-
244
- void nodeTimeAdjustedCallback(int32_t offset) {
245
- Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(), offset);
1
+ /**
2
+ * Improved Sensor Node Example with Validation and Metrics
3
+ *
4
+ * This example demonstrates the new security and performance improvements
5
+ * in painlessMesh including input validation, rate limiting, and performance
6
+ * metrics.
7
+ */
8
+
9
+ #include "alteriom_sensor_package.hpp"
10
+ #include "painlessMesh.h"
11
+
12
+ // Note: The improvement modules (validation, metrics, memory) are automatically
13
+ // included through painlessMesh.h when the corresponding features are enabled
14
+
15
+ #define MESH_PREFIX "AlteriomImprovedMesh"
16
+ #define MESH_PASSWORD "securePassword123"
17
+ #define MESH_PORT 5555
18
+
19
+ #define SENSOR_TASK_INTERVAL 30000 // Send sensor data every 30 seconds
20
+ #define METRICS_TASK_INTERVAL 60000 // Report metrics every minute
21
+ #define VALIDATION_ENABLED true // Enable message validation
22
+
23
+ Scheduler userScheduler;
24
+ painlessMesh mesh;
25
+
26
+ // New improvement features
27
+ painlessmesh::validation::MessageValidator validator;
28
+ painlessmesh::validation::RateLimiter rateLimiter(5, 1000); // 5 msgs/sec max
29
+ painlessmesh::metrics::MetricsCollector metrics;
30
+ painlessmesh::memory::ObjectPool<alteriom::SensorPackage> sensorPool(5);
31
+
32
+ // Task declarations
33
+ Task sensorTask(SENSOR_TASK_INTERVAL, TASK_FOREVER, &sendSensorData);
34
+ Task metricsTask(METRICS_TASK_INTERVAL, TASK_FOREVER, &reportMetrics);
35
+
36
+ void setup() {
37
+ Serial.begin(115200);
38
+
39
+ // Configure validation with custom settings
40
+ painlessmesh::validation::ValidationConfig config;
41
+ config.max_message_size = 4096; // Smaller max size for sensors
42
+ config.max_string_length = 256; // Reasonable string limits
43
+ config.strict_type_checking = true; // Enable strict validation
44
+ validator.set_config(config);
45
+
46
+ mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
47
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
48
+ mesh.onReceive(&receivedCallback);
49
+ mesh.onNewConnection(&newConnectionCallback);
50
+ mesh.onChangedConnections(&changedConnectionCallback);
51
+ mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
52
+
53
+ userScheduler.addTask(sensorTask);
54
+ userScheduler.addTask(metricsTask);
55
+ sensorTask.enable();
56
+ metricsTask.enable();
57
+
58
+ Serial.println("Enhanced Sensor Node Started");
59
+ Serial.println(
60
+ "Features: Validation, Rate Limiting, Metrics, Memory Optimization");
61
+ }
62
+
63
+ void loop() {
64
+ mesh.update();
65
+ metrics.update(); // Update performance metrics
66
+ }
67
+
68
+ void sendSensorData() {
69
+ // Use object pool for memory efficiency
70
+ auto sensorPackage = sensorPool.acquire();
71
+
72
+ // Simulate sensor readings
73
+ sensorPackage->temperature = 20.0 + random(-5, 15); // 15-35°C
74
+ sensorPackage->humidity = 40.0 + random(0, 40); // 40-80%
75
+ sensorPackage->pressure = 1013.25 + random(-50, 50); // Near sea level
76
+ sensorPackage->batteryLevel = 85 + random(-10, 15); // Battery simulation
77
+ sensorPackage->sensorId = mesh.getNodeId();
78
+ sensorPackage->timestamp = mesh.getNodeTime();
79
+
80
+ // Convert to message variant
81
+ painlessmesh::protocol::Variant variant(sensorPackage.get());
82
+ String message;
83
+ variant.printTo(message);
84
+
85
+ // Validate message before sending (optional security check)
86
+ if (VALIDATION_ENABLED) {
87
+ JsonDocument doc;
88
+ deserializeJson(doc, message);
89
+ JsonObject obj = doc.as<JsonObject>();
90
+
91
+ auto result = validator.validate_message(obj, message.length());
92
+ if (result != painlessmesh::validation::ValidationResult::VALID) {
93
+ Serial.printf("Message validation failed: %s\n",
94
+ validator.get_error_message(result));
95
+ sensorPool.release(std::move(sensorPackage)); // Return to pool
96
+ return;
97
+ }
98
+ }
99
+
100
+ // Send the message
101
+ bool sent = mesh.sendBroadcast(message);
102
+ if (sent) {
103
+ metrics.message_stats().record_sent_message(message.length());
104
+ Serial.printf(
105
+ "Sensor data sent: T=%.1f°C, H=%.1f%%, P=%.1f hPa, Batt=%d%%\n",
106
+ sensorPackage->temperature, sensorPackage->humidity,
107
+ sensorPackage->pressure, sensorPackage->batteryLevel);
108
+ } else {
109
+ metrics.message_stats().record_dropped_message();
110
+ Serial.println("Failed to send sensor data - network congestion");
111
+ }
112
+
113
+ // Return object to pool for reuse
114
+ sensorPool.release(std::move(sensorPackage));
115
+ }
116
+
117
+ void reportMetrics() {
118
+ String metricsJson = metrics.generate_status_json();
119
+ Serial.println("=== Performance Metrics ===");
120
+ Serial.println(metricsJson);
121
+
122
+ // Check for performance issues
123
+ if (metrics.has_performance_issues()) {
124
+ Serial.println("WARNING: Performance issues detected!");
125
+
126
+ if (metrics.memory_stats().is_memory_critical()) {
127
+ Serial.println("- Critical memory shortage");
128
+ }
129
+
130
+ if (metrics.message_stats().packet_loss_rate() > 0.1) {
131
+ Serial.printf("- High packet loss: %.1f%%\n",
132
+ metrics.message_stats().packet_loss_rate() * 100);
133
+ }
134
+
135
+ if (metrics.topology_stats().connection_stability() < 0.8) {
136
+ Serial.printf("- Poor connection stability: %.1f%%\n",
137
+ metrics.topology_stats().connection_stability() * 100);
138
+ }
139
+ }
140
+
141
+ Serial.println("===========================");
142
+ }
143
+
144
+ void receivedCallback(uint32_t from, String& msg) {
145
+ // Record metrics
146
+ metrics.message_stats().record_received_message(msg.length());
147
+
148
+ // Rate limiting check
149
+ if (!rateLimiter.allow_message(from)) {
150
+ Serial.printf("Rate limit exceeded for node %u, dropping message\n", from);
151
+ metrics.message_stats().record_dropped_message();
152
+ return;
153
+ }
154
+
155
+ // Validate incoming message
156
+ if (VALIDATION_ENABLED) {
157
+ JsonDocument doc;
158
+ DeserializationError error = deserializeJson(doc, msg);
159
+
160
+ if (error) {
161
+ Serial.printf("JSON parsing failed from %u: %s\n", from, error.c_str());
162
+ metrics.message_stats().record_parse_error();
163
+ return;
164
+ }
165
+
166
+ JsonObject obj = doc.as<JsonObject>();
167
+ auto result = validator.validate_message(obj, msg.length());
168
+
169
+ if (result != painlessmesh::validation::ValidationResult::VALID) {
170
+ Serial.printf("Message validation failed from %u: %s\n", from,
171
+ validator.get_error_message(result));
172
+ metrics.message_stats().record_validation_error();
173
+ return;
174
+ }
175
+ }
176
+
177
+ // Process the validated message
178
+ JsonDocument doc;
179
+ deserializeJson(doc, msg);
180
+ JsonObject obj = doc.as<JsonObject>();
181
+ uint8_t msgType = obj["type"];
182
+
183
+ switch (msgType) {
184
+ case 200: // SensorPackage
185
+ handleSensorData(alteriom::SensorPackage(obj), from);
186
+ break;
187
+ case 201: // CommandPackage
188
+ handleCommand(alteriom::CommandPackage(obj), from);
189
+ break;
190
+ case 202: // StatusPackage
191
+ handleStatus(alteriom::StatusPackage(obj), from);
192
+ break;
193
+ default:
194
+ Serial.printf("Unknown message type %d from %u\n", msgType, from);
195
+ }
196
+ }
197
+
198
+ void handleSensorData(alteriom::SensorPackage sensorData, uint32_t from) {
199
+ Serial.printf("Sensor data from %u: T=%.1f°C, H=%.1f%%, P=%.1f hPa\n", from,
200
+ sensorData.temperature, sensorData.humidity,
201
+ sensorData.pressure);
202
+ }
203
+
204
+ void handleCommand(alteriom::CommandPackage command, uint32_t from) {
205
+ Serial.printf("Command from %u: cmd=%d, target=%u\n", from, command.command,
206
+ command.targetDevice);
207
+
208
+ // Example: Handle LED control command
209
+ if (command.command == 1 && command.targetDevice == mesh.getNodeId()) {
210
+ digitalWrite(LED_BUILTIN,
211
+ command.parameters.indexOf("ON") >= 0 ? HIGH : LOW);
212
+ Serial.println("LED command executed");
213
+ }
214
+ }
215
+
216
+ void handleStatus(alteriom::StatusPackage status, uint32_t from) {
217
+ Serial.printf("Status from %u: status=%d, uptime=%u, mem=%u\n", from,
218
+ status.deviceStatus, status.uptime, status.freeMemory);
219
+ }
220
+
221
+ void newConnectionCallback(uint32_t nodeId) {
222
+ Serial.printf("New connection: %u\n", nodeId);
223
+
224
+ // Update topology metrics
225
+ auto nodeList = mesh.getNodeList();
226
+ metrics.topology_stats().record_topology_change(
227
+ nodeList.size() + 1, // +1 for this node
228
+ mesh.connectionCount(),
229
+ 0 // Max hops calculation not implemented in this example
230
+ );
231
+ }
232
+
233
+ void changedConnectionCallback() {
234
+ Serial.printf("Changed connections\n");
235
+
236
+ // Update topology metrics
237
+ auto nodeList = mesh.getNodeList();
238
+ metrics.topology_stats().record_topology_change(
239
+ nodeList.size() + 1, mesh.connectionCount(),
240
+ 0 // Max hops calculation not implemented in this example
241
+ );
242
+ }
243
+
244
+ void nodeTimeAdjustedCallback(int32_t offset) {
245
+ Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(), offset);
246
246
  }
@@ -0,0 +1,25 @@
1
+ [platformio]
2
+ src_dir = .
3
+
4
+ [env]
5
+ lib_deps =
6
+ bblanchon/ArduinoJson
7
+ arkhipenko/TaskScheduler
8
+
9
+ [env:esp8266]
10
+ platform = espressif8266
11
+ board = nodemcuv2
12
+ framework = arduino
13
+ lib_extra_dirs = ../../ ; Load the local copy of painlessmesh. For your own example add painlessmesh to the lib_deps
14
+ lib_deps =
15
+ ${env.lib_deps} ; Inherit common dependencies
16
+ esp32async/ESPAsyncTCP ; Only for ESP8266
17
+
18
+ [env:esp32]
19
+ platform = espressif32
20
+ board = esp32dev
21
+ framework = arduino
22
+ lib_extra_dirs = ../../ ; Load the local copy of painlessmesh. For your own example add painlessmesh to the lib_deps
23
+ lib_deps =
24
+ ${env.lib_deps} ; Inherit common dependencies
25
+ esp32async/AsyncTCP