@alteriom/painlessmesh 1.7.6 → 1.7.7

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 (36) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/README.md +81 -6
  3. package/RELEASE_GUIDE.md +36 -0
  4. package/docs/MQTT_BRIDGE_COMMANDS.md +10 -10
  5. package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +1 -1
  6. package/docs/MQTT_SCHEMA_COMPLIANCE.md +57 -2
  7. package/docs/PHASE1_GUIDE.md +1 -1
  8. package/docs/alteriom/overview.md +2 -2
  9. package/docs/architecture/plugin-system.md +1 -1
  10. package/docs/archive/RELEASE_SUMMARY.md +1 -1
  11. package/docs/releases/RELEASE_CHECKLIST_v1.7.6.md +389 -0
  12. package/docs/releases/RELEASE_SUMMARY_v1.7.7.md +391 -0
  13. package/docs/v1.7.7_MQTT_IMPROVEMENTS.md +776 -0
  14. package/docs/wiki/API-Reference.md +2 -2
  15. package/docs/wiki/Complete-Documentation.md +1 -1
  16. package/examples/alteriom/README.md +137 -3
  17. package/examples/alteriom/alteriom.ino +1 -1
  18. package/examples/alteriom/alteriom_sensor_package.hpp +557 -2
  19. package/examples/alteriomImproved/alteriom_sensor_package.hpp +1 -1
  20. package/examples/alteriomImproved/improved_sensor_node.ino +1 -1
  21. package/examples/alteriomMetricsHealth/alteriom_sensor_package.hpp +796 -0
  22. package/examples/alteriomMetricsHealth/metrics_health_node.ino +418 -0
  23. package/examples/alteriomMetricsHealth/platformio.ini +26 -0
  24. package/examples/alteriomPhase1/alteriom_sensor_package.hpp +1 -1
  25. package/examples/alteriomPhase1/phase1_features.ino +2 -2
  26. package/examples/alteriomPhase2/alteriom_sensor_package.hpp +1 -1
  27. package/examples/alteriomSensorNode/alteriom_sensor_node.ino +1 -1
  28. package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +1 -1
  29. package/examples/bridge/enhanced_mqtt_bridge.hpp +610 -0
  30. package/examples/bridge/enhanced_mqtt_bridge_example.ino +226 -0
  31. package/examples/meshCommandNode/alteriom_sensor_package.hpp +1 -1
  32. package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +1 -1
  33. package/examples/mqttTopologyTest/mqttTopologyTest.ino +5 -1
  34. package/library.json +1 -1
  35. package/library.properties +1 -1
  36. package/package.json +2 -2
@@ -0,0 +1,418 @@
1
+ /**
2
+ * Alteriom Metrics and Health Monitoring Node
3
+ *
4
+ * This example demonstrates the new MetricsPackage (Type 204) and
5
+ * HealthCheckPackage (Type 605) introduced in painlessMesh v1.7.7.
6
+ *
7
+ * Features:
8
+ * - Comprehensive performance metrics collection
9
+ * - Proactive health monitoring with problem detection
10
+ * - Configurable collection intervals
11
+ * - Alert threshold detection
12
+ * - Memory leak detection
13
+ * - Network quality monitoring
14
+ *
15
+ * Hardware: ESP32 or ESP8266
16
+ */
17
+
18
+ #include "painlessMesh.h"
19
+ #include "alteriom_sensor_package.hpp"
20
+
21
+ using namespace alteriom;
22
+
23
+ // Mesh Configuration
24
+ #define MESH_PREFIX "AlteriomMesh"
25
+ #define MESH_PASSWORD "your_password"
26
+ #define MESH_PORT 5555
27
+
28
+ // Collection Intervals (milliseconds)
29
+ #define METRICS_INTERVAL 30000 // 30 seconds
30
+ #define HEALTH_INTERVAL 60000 // 60 seconds
31
+
32
+ Scheduler userScheduler;
33
+ painlessMesh mesh;
34
+
35
+ // Tasks
36
+ Task taskSendMetrics(METRICS_INTERVAL, TASK_FOREVER, &sendMetrics);
37
+ Task taskSendHealth(HEALTH_INTERVAL, TASK_FOREVER, &sendHealthCheck);
38
+
39
+ // Metrics tracking
40
+ uint32_t loopCount = 0;
41
+ uint32_t lastLoopCount = 0;
42
+ uint32_t lastMetricsTime = 0;
43
+ uint32_t maxLoopDuration = 0;
44
+ uint32_t loopStartTime = 0;
45
+
46
+ // Network statistics
47
+ uint32_t totalBytesRx = 0;
48
+ uint32_t totalBytesTx = 0;
49
+ uint32_t totalPacketsRx = 0;
50
+ uint32_t totalPacketsTx = 0;
51
+ uint32_t packetsDropped = 0;
52
+
53
+ // Health tracking
54
+ uint32_t minHeapEverSeen = 0xFFFFFFFF;
55
+ uint32_t previousHeap = 0;
56
+ uint32_t memoryCheckCount = 0;
57
+ int32_t memoryTrendAccumulator = 0;
58
+ uint16_t reconnectionCount = 0;
59
+
60
+ void setup() {
61
+ Serial.begin(115200);
62
+ Serial.println("\n\n=== Alteriom Metrics & Health Monitoring Node ===");
63
+ Serial.println("painlessMesh v1.7.7 - Type 204, 604 & 605 Packages");
64
+
65
+ // Initialize mesh
66
+ mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
67
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
68
+
69
+ // Set up callbacks
70
+ mesh.onReceive(&receivedCallback);
71
+ mesh.onNewConnection(&newConnectionCallback);
72
+ mesh.onChangedConnections(&changedConnectionCallback);
73
+ mesh.onDroppedConnection(&droppedConnectionCallback);
74
+
75
+ // Add tasks to scheduler
76
+ userScheduler.addTask(taskSendMetrics);
77
+ userScheduler.addTask(taskSendHealth);
78
+
79
+ taskSendMetrics.enable();
80
+ taskSendHealth.enable();
81
+
82
+ // Initialize tracking
83
+ lastMetricsTime = millis();
84
+ minHeapEverSeen = ESP.getFreeHeap();
85
+ previousHeap = minHeapEverSeen;
86
+
87
+ Serial.printf("Node ID: %u\n", mesh.getNodeId());
88
+ Serial.printf("Free Heap: %u bytes\n", ESP.getFreeHeap());
89
+ Serial.println("Setup complete!");
90
+ }
91
+
92
+ void loop() {
93
+ loopStartTime = micros();
94
+ loopCount++;
95
+
96
+ mesh.update();
97
+
98
+ // Track maximum loop duration
99
+ uint32_t loopDuration = micros() - loopStartTime;
100
+ if (loopDuration > maxLoopDuration) {
101
+ maxLoopDuration = loopDuration;
102
+ }
103
+ }
104
+
105
+ void sendMetrics() {
106
+ Serial.println("\n--- Sending Metrics Package ---");
107
+
108
+ MetricsPackage metrics;
109
+ metrics.from = mesh.getNodeId();
110
+
111
+ // Calculate time since last metrics
112
+ uint32_t now = millis();
113
+ uint32_t timeDelta = now - lastMetricsTime;
114
+ if (timeDelta == 0) timeDelta = 1; // Prevent division by zero
115
+
116
+ // CPU and Processing
117
+ metrics.loopIterations = ((loopCount - lastLoopCount) * 1000) / timeDelta;
118
+ metrics.cpuUsage = calculateCPUUsage();
119
+ metrics.taskQueueSize = userScheduler.size();
120
+
121
+ // Memory Metrics
122
+ metrics.freeHeap = ESP.getFreeHeap();
123
+ metrics.minFreeHeap = minHeapEverSeen;
124
+ #ifdef ESP32
125
+ metrics.heapFragmentation = 0; // ESP32 doesn't provide fragmentation
126
+ metrics.maxAllocHeap = ESP.getMaxAllocHeap();
127
+ #else
128
+ metrics.heapFragmentation = ESP.getHeapFragmentation();
129
+ metrics.maxAllocHeap = ESP.getMaxFreeBlockSize();
130
+ #endif
131
+
132
+ // Update minimum heap tracking
133
+ if (metrics.freeHeap < minHeapEverSeen) {
134
+ minHeapEverSeen = metrics.freeHeap;
135
+ }
136
+
137
+ // Network Performance
138
+ metrics.bytesReceived = totalBytesRx;
139
+ metrics.bytesSent = totalBytesTx;
140
+ metrics.packetsReceived = totalPacketsRx;
141
+ metrics.packetsSent = totalPacketsTx;
142
+ metrics.packetsDropped = packetsDropped;
143
+ metrics.currentThroughput = ((totalBytesRx + totalBytesTx) * 1000) / timeDelta;
144
+
145
+ // Timing and Latency
146
+ metrics.avgResponseTime = mesh.getNodeTime() % 1000000; // Mock value
147
+ metrics.maxResponseTime = maxLoopDuration;
148
+ metrics.avgMeshLatency = 25; // Would need to calculate from actual delays
149
+
150
+ // Connection Quality
151
+ metrics.connectionQuality = calculateConnectionQuality();
152
+ metrics.wifiRSSI = WiFi.RSSI();
153
+
154
+ // Metadata
155
+ metrics.collectionTimestamp = mesh.getNodeTime();
156
+ metrics.collectionInterval = METRICS_INTERVAL;
157
+
158
+ // Send the metrics
159
+ String msg = metrics.toJsonString();
160
+ bool sent = mesh.sendBroadcast(msg);
161
+
162
+ if (sent) {
163
+ Serial.println("Metrics sent successfully");
164
+ Serial.printf(" CPU: %d%%, Loops/sec: %u\n", metrics.cpuUsage, metrics.loopIterations);
165
+ Serial.printf(" Free Heap: %u bytes, Min: %u bytes\n", metrics.freeHeap, metrics.minFreeHeap);
166
+ Serial.printf(" Throughput: %u bytes/sec\n", metrics.currentThroughput);
167
+ Serial.printf(" WiFi RSSI: %d dBm\n", metrics.wifiRSSI);
168
+ } else {
169
+ Serial.println("ERROR: Failed to send metrics");
170
+ packetsDropped++;
171
+ }
172
+
173
+ // Update tracking
174
+ lastLoopCount = loopCount;
175
+ lastMetricsTime = now;
176
+ maxLoopDuration = 0;
177
+ }
178
+
179
+ void sendHealthCheck() {
180
+ Serial.println("\n--- Sending Health Check Package ---");
181
+
182
+ HealthCheckPackage health;
183
+ health.from = mesh.getNodeId();
184
+
185
+ // Collect health metrics
186
+ uint32_t freeHeap = ESP.getFreeHeap();
187
+ uint8_t memHealth = calculateMemoryHealth(freeHeap);
188
+ uint8_t netHealth = calculateNetworkHealth();
189
+ uint8_t perfHealth = calculatePerformanceHealth();
190
+
191
+ // Overall health status (0=critical, 1=warning, 2=healthy)
192
+ if (memHealth < 30 || netHealth < 30 || perfHealth < 30) {
193
+ health.healthStatus = 0; // Critical
194
+ } else if (memHealth < 60 || netHealth < 60 || perfHealth < 60) {
195
+ health.healthStatus = 1; // Warning
196
+ } else {
197
+ health.healthStatus = 2; // Healthy
198
+ }
199
+
200
+ // Problem flags
201
+ health.problemFlags = 0;
202
+ if (memHealth < 60) health.problemFlags |= 0x0001; // Low memory
203
+ if (perfHealth < 60) health.problemFlags |= 0x0002; // High CPU
204
+ if (netHealth < 60) health.problemFlags |= 0x0004; // Connection instability
205
+ if (packetsDropped > 0) health.problemFlags |= 0x0008; // High packet loss
206
+
207
+ // Memory Health
208
+ health.memoryHealth = memHealth;
209
+
210
+ // Calculate memory trend (bytes per hour)
211
+ if (memoryCheckCount > 0) {
212
+ int32_t memoryDelta = (int32_t)previousHeap - (int32_t)freeHeap;
213
+ memoryTrendAccumulator += memoryDelta;
214
+ health.memoryTrend = (memoryTrendAccumulator * 3600000) / (HEALTH_INTERVAL * memoryCheckCount);
215
+ }
216
+ previousHeap = freeHeap;
217
+ memoryCheckCount++;
218
+
219
+ // Network Health
220
+ health.networkHealth = netHealth;
221
+ health.packetLossPercent = calculatePacketLoss();
222
+ health.reconnectionCount = reconnectionCount;
223
+
224
+ // Performance Health
225
+ health.performanceHealth = perfHealth;
226
+ health.missedDeadlines = 0; // Would need task scheduler integration
227
+ health.maxLoopTime = maxLoopDuration / 1000; // Convert to ms
228
+
229
+ // Environmental (if available)
230
+ #ifdef TEMP_SENSOR_PIN
231
+ health.temperature = readTemperature();
232
+ health.temperatureHealth = calculateTemperatureHealth(health.temperature);
233
+ #else
234
+ health.temperature = 0;
235
+ health.temperatureHealth = 100;
236
+ #endif
237
+
238
+ // Uptime and Stability
239
+ health.uptime = millis() / 1000;
240
+ health.crashCount = 0; // Would need EEPROM tracking
241
+ health.lastRebootReason = 1; // Normal startup
242
+
243
+ // Predictive indicators
244
+ if (health.memoryTrend > 0 && freeHeap > health.memoryTrend) {
245
+ health.estimatedTimeToFailure = (freeHeap / health.memoryTrend);
246
+ } else {
247
+ health.estimatedTimeToFailure = 0; // Unknown
248
+ }
249
+
250
+ // Recommendations
251
+ if (health.healthStatus == 0) {
252
+ health.recommendations = "CRITICAL: Immediate attention required";
253
+ } else if (health.healthStatus == 1) {
254
+ if (memHealth < 60) {
255
+ health.recommendations = "Increase memory allocation or reduce message frequency";
256
+ } else if (netHealth < 60) {
257
+ health.recommendations = "Check network connections and reduce interference";
258
+ } else {
259
+ health.recommendations = "Monitor performance closely";
260
+ }
261
+ } else {
262
+ health.recommendations = "System operating normally";
263
+ }
264
+
265
+ // Metadata
266
+ health.checkTimestamp = mesh.getNodeTime();
267
+ health.nextCheckDue = health.checkTimestamp + (HEALTH_INTERVAL * 1000);
268
+
269
+ // Send the health check
270
+ String msg = health.toJsonString();
271
+ bool sent = mesh.sendBroadcast(msg);
272
+
273
+ if (sent) {
274
+ Serial.println("Health check sent successfully");
275
+ Serial.printf(" Overall Health: %s (Status: %d)\n",
276
+ health.healthStatus == 2 ? "HEALTHY" :
277
+ health.healthStatus == 1 ? "WARNING" : "CRITICAL",
278
+ health.healthStatus);
279
+ Serial.printf(" Memory Health: %d%%, Network Health: %d%%, Performance: %d%%\n",
280
+ health.memoryHealth, health.networkHealth, health.performanceHealth);
281
+ if (health.problemFlags > 0) {
282
+ Serial.printf(" Problem Flags: 0x%04X\n", health.problemFlags);
283
+ }
284
+ Serial.printf(" Memory Trend: %d bytes/hour\n", health.memoryTrend);
285
+ if (health.estimatedTimeToFailure > 0) {
286
+ Serial.printf(" Est. Time to Failure: %d hours\n", health.estimatedTimeToFailure);
287
+ }
288
+ Serial.printf(" Recommendations: %s\n", health.recommendations.c_str());
289
+ } else {
290
+ Serial.println("ERROR: Failed to send health check");
291
+ packetsDropped++;
292
+ }
293
+ }
294
+
295
+ // Utility functions for health calculations
296
+ uint8_t calculateCPUUsage() {
297
+ // Simplified CPU usage estimation based on loop execution
298
+ // In reality, this would need more sophisticated timing
299
+ uint32_t loopsPerSec = (loopCount - lastLoopCount) * 1000 / (millis() - lastMetricsTime);
300
+ if (loopsPerSec > 10000) return 20; // Low usage
301
+ if (loopsPerSec > 5000) return 40;
302
+ if (loopsPerSec > 2000) return 60;
303
+ if (loopsPerSec > 1000) return 80;
304
+ return 95; // High usage
305
+ }
306
+
307
+ uint8_t calculateConnectionQuality() {
308
+ int8_t rssi = WiFi.RSSI();
309
+ uint8_t lossPercent = calculatePacketLoss();
310
+
311
+ // Quality based on RSSI (0-50 points)
312
+ uint8_t rssiScore = 0;
313
+ if (rssi > -50) rssiScore = 50;
314
+ else if (rssi > -70) rssiScore = 40;
315
+ else if (rssi > -80) rssiScore = 30;
316
+ else if (rssi > -90) rssiScore = 20;
317
+ else rssiScore = 10;
318
+
319
+ // Quality based on packet loss (0-50 points)
320
+ uint8_t lossScore = 50 - (lossPercent / 2);
321
+ if (lossScore < 0) lossScore = 0;
322
+
323
+ return rssiScore + lossScore;
324
+ }
325
+
326
+ uint8_t calculateMemoryHealth(uint32_t freeHeap) {
327
+ #ifdef ESP32
328
+ uint32_t totalHeap = ESP.getHeapSize();
329
+ #else
330
+ uint32_t totalHeap = 81920; // ESP8266 ~80KB
331
+ #endif
332
+
333
+ uint8_t heapPercent = (freeHeap * 100) / totalHeap;
334
+
335
+ if (heapPercent > 60) return 100;
336
+ if (heapPercent > 40) return 80;
337
+ if (heapPercent > 20) return 50;
338
+ if (heapPercent > 10) return 30;
339
+ return 10;
340
+ }
341
+
342
+ uint8_t calculateNetworkHealth() {
343
+ uint8_t connectionCount = mesh.getNodeList().size();
344
+ uint8_t lossPercent = calculatePacketLoss();
345
+
346
+ // Good if we have connections and low packet loss
347
+ if (connectionCount > 0 && lossPercent < 5) return 100;
348
+ if (connectionCount > 0 && lossPercent < 10) return 80;
349
+ if (connectionCount > 0 && lossPercent < 20) return 60;
350
+ if (connectionCount > 0) return 40;
351
+ return 20; // No connections
352
+ }
353
+
354
+ uint8_t calculatePerformanceHealth() {
355
+ // Based on loop performance
356
+ if (maxLoopDuration < 10000) return 100; // < 10ms excellent
357
+ if (maxLoopDuration < 50000) return 80; // < 50ms good
358
+ if (maxLoopDuration < 100000) return 60; // < 100ms fair
359
+ if (maxLoopDuration < 200000) return 40; // < 200ms poor
360
+ return 20; // Very poor
361
+ }
362
+
363
+ uint8_t calculatePacketLoss() {
364
+ uint32_t totalPackets = totalPacketsTx + totalPacketsRx;
365
+ if (totalPackets == 0) return 0;
366
+ return (packetsDropped * 100) / totalPackets;
367
+ }
368
+
369
+ // Mesh callbacks
370
+ void receivedCallback(uint32_t from, String& msg) {
371
+ totalBytesRx += msg.length();
372
+ totalPacketsRx++;
373
+
374
+ // Parse message type
375
+ DynamicJsonDocument doc(1024);
376
+ deserializeJson(doc, msg);
377
+ JsonObject obj = doc.as<JsonObject>();
378
+ uint8_t msgType = obj["type"];
379
+
380
+ Serial.printf("\nReceived Type %d from %u\n", msgType, from);
381
+
382
+ switch(msgType) {
383
+ case 200: // SensorPackage
384
+ Serial.println(" -> Sensor data");
385
+ break;
386
+ case 400: // CommandPackage (COMMAND per schema v0.7.2+)
387
+ Serial.println(" -> Command");
388
+ break;
389
+ case 202: // StatusPackage
390
+ Serial.println(" -> Status");
391
+ break;
392
+ case 604: // EnhancedStatusPackage (MESH_STATUS per schema v0.7.2+)
393
+ Serial.println(" -> Enhanced Status");
394
+ break;
395
+ case 204: // MetricsPackage (SENSOR_METRICS per schema v0.7.2+)
396
+ Serial.println(" -> Metrics");
397
+ break;
398
+ case 605: // HealthCheckPackage (MESH_METRICS per schema v0.7.2+)
399
+ Serial.println(" -> Health Check");
400
+ break;
401
+ default:
402
+ Serial.println(" -> Unknown type");
403
+ }
404
+ }
405
+
406
+ void newConnectionCallback(uint32_t nodeId) {
407
+ Serial.printf("\nNew Connection: %u\n", nodeId);
408
+ Serial.printf("Total nodes: %d\n", mesh.getNodeList().size() + 1);
409
+ }
410
+
411
+ void changedConnectionCallback() {
412
+ Serial.println("\nMesh topology changed");
413
+ }
414
+
415
+ void droppedConnectionCallback(uint32_t nodeId) {
416
+ Serial.printf("\nConnection dropped: %u\n", nodeId);
417
+ reconnectionCount++;
418
+ }
@@ -0,0 +1,26 @@
1
+ [platformio]
2
+ src_dir = .
3
+
4
+ [env]
5
+ lib_deps =
6
+ bblanchon/ArduinoJson
7
+ arkhipenko/TaskScheduler
8
+
9
+ lib_ldf_mode = deep+
10
+ [env:esp8266]
11
+ platform = espressif8266
12
+ board = nodemcuv2
13
+ framework = arduino
14
+ lib_extra_dirs = ../../ ; Load the local copy of painlessmesh. For your own example add painlessmesh to the lib_deps
15
+ lib_deps =
16
+ ${env.lib_deps} ; Inherit common dependencies
17
+ esp32async/ESPAsyncTCP ; Only for ESP8266
18
+
19
+ [env:esp32]
20
+ platform = espressif32
21
+ board = esp32dev
22
+ framework = arduino
23
+ lib_extra_dirs = ../../ ; Load the local copy of painlessmesh. For your own example add painlessmesh to the lib_deps
24
+ lib_deps =
25
+ ${env.lib_deps} ; Inherit common dependencies
26
+ esp32async/AsyncTCP
@@ -60,7 +60,7 @@ class CommandPackage : public painlessmesh::plugin::SinglePackage {
60
60
  TSTRING parameters = ""; // Command parameters as JSON string
61
61
  uint32_t commandId = 0; // Unique command identifier for tracking
62
62
 
63
- CommandPackage() : SinglePackage(201) {} // Type ID 201 for Alteriom commands
63
+ CommandPackage() : SinglePackage(400) {} // Type ID 201 for Alteriom commands
64
64
 
65
65
  CommandPackage(JsonObject jsonObj) : SinglePackage(jsonObj) {
66
66
  command = jsonObj["cmd"];
@@ -113,7 +113,7 @@ void sendEnhancedStatus() {
113
113
 
114
114
  // Convert to JSON and send
115
115
  String msg;
116
- DynamicJsonDocument doc(status.jsonObjectSize());
116
+ JsonDocument doc; // ArduinoJson v7 uses automatic sizing
117
117
  JsonObject obj = doc.to<JsonObject>();
118
118
  status.addTo(std::move(obj));
119
119
  serializeJson(doc, msg);
@@ -132,7 +132,7 @@ void receivedCallback(uint32_t from, String& msg) {
132
132
  totalMessagesReceived++;
133
133
 
134
134
  // Parse the message to identify the type
135
- DynamicJsonDocument doc(2048);
135
+ JsonDocument doc; // ArduinoJson v7 uses automatic sizing
136
136
  DeserializationError error = deserializeJson(doc, msg);
137
137
 
138
138
  if (error) {
@@ -60,7 +60,7 @@ class CommandPackage : public painlessmesh::plugin::SinglePackage {
60
60
  TSTRING parameters = ""; // Command parameters as JSON string
61
61
  uint32_t commandId = 0; // Unique command identifier for tracking
62
62
 
63
- CommandPackage() : SinglePackage(201) {} // Type ID 201 for Alteriom commands
63
+ CommandPackage() : SinglePackage(400) {} // Type ID 201 for Alteriom commands
64
64
 
65
65
  CommandPackage(JsonObject jsonObj) : SinglePackage(jsonObj) {
66
66
  command = jsonObj["cmd"];
@@ -125,7 +125,7 @@ void handleIncomingPackage(uint32_t from, String& msg) {
125
125
  // Process sensor data (store, forward, analyze, etc.)
126
126
  } break;
127
127
 
128
- case 201: // CommandPackage
128
+ case 400: // CommandPackage
129
129
  {
130
130
  CommandPackage receivedCmd(obj);
131
131
  if (receivedCmd.dest == mesh.getNodeId()) {
@@ -60,7 +60,7 @@ class CommandPackage : public painlessmesh::plugin::SinglePackage {
60
60
  TSTRING parameters = ""; // Command parameters as JSON string
61
61
  uint32_t commandId = 0; // Unique command identifier for tracking
62
62
 
63
- CommandPackage() : SinglePackage(201) {} // Type ID 201 for Alteriom commands
63
+ CommandPackage() : SinglePackage(400) {} // Type ID 201 for Alteriom commands
64
64
 
65
65
  CommandPackage(JsonObject jsonObj) : SinglePackage(jsonObj) {
66
66
  command = jsonObj["cmd"];