@alteriom/painlessmesh 1.7.6 → 1.7.8
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 +177 -0
- package/README.md +96 -14
- package/RELEASE_GUIDE.md +36 -0
- package/docs/API_DESIGN_GUIDELINES.md +414 -0
- package/docs/BOOLEAN_NAMING_CONVENTION.md +235 -0
- package/docs/MQTT_BRIDGE_COMMANDS.md +10 -10
- package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +1 -1
- package/docs/MQTT_SCHEMA_COMPLIANCE.md +57 -2
- package/docs/PHASE1_GUIDE.md +1 -1
- package/docs/alteriom/overview.md +25 -2
- package/docs/architecture/plugin-system.md +1 -1
- package/docs/archive/RELEASE_SUMMARY.md +1 -1
- package/docs/releases/RELEASE_CHECKLIST_v1.7.6.md +389 -0
- package/docs/releases/RELEASE_SUMMARY_v1.7.7.md +391 -0
- package/docs/v1.7.7_MQTT_IMPROVEMENTS.md +794 -0
- package/docs/wiki/API-Reference.md +2 -2
- package/docs/wiki/Complete-Documentation.md +1 -1
- package/examples/alteriom/README.md +150 -4
- package/examples/alteriom/alteriom.ino +1 -1
- package/examples/alteriom/alteriom_sensor_package.hpp +914 -4
- package/examples/alteriomImproved/alteriom_sensor_package.hpp +1 -1
- package/examples/alteriomImproved/improved_sensor_node.ino +1 -1
- package/examples/alteriomMetricsHealth/alteriom_sensor_package.hpp +796 -0
- package/examples/alteriomMetricsHealth/metrics_health_node.ino +418 -0
- package/examples/alteriomMetricsHealth/platformio.ini +26 -0
- package/examples/alteriomPhase1/alteriom_sensor_package.hpp +1 -1
- package/examples/alteriomPhase1/phase1_features.ino +2 -2
- package/examples/alteriomPhase2/alteriom_sensor_package.hpp +1 -1
- package/examples/alteriomSensorNode/alteriom_sensor_node.ino +1 -1
- package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +1 -1
- package/examples/bridge/enhanced_mqtt_bridge.hpp +610 -0
- package/examples/bridge/enhanced_mqtt_bridge_example.ino +226 -0
- package/examples/meshCommandNode/alteriom_sensor_package.hpp +1 -1
- package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +1 -1
- package/examples/mqttTopologyTest/mqttTopologyTest.ino +5 -1
- package/library.json +1 -1
- package/library.properties +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,794 @@
|
|
|
1
|
+
# Version 1.7.7 - Enhanced MQTT Communication for Metrics & Health Monitoring
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Version 1.7.7 introduces two new specialized packages designed to enhance MQTT communication efficiency for monitoring mesh networks. These packages provide comprehensive visibility into system performance, proactive problem detection, and predictive maintenance capabilities.
|
|
6
|
+
|
|
7
|
+
## New Package Types
|
|
8
|
+
|
|
9
|
+
### MetricsPackage (Type 204)
|
|
10
|
+
|
|
11
|
+
A comprehensive performance metrics package designed for real-time dashboards, capacity planning, and network optimization.
|
|
12
|
+
|
|
13
|
+
#### Purpose
|
|
14
|
+
|
|
15
|
+
- **Real-time Monitoring** - Track system performance in real-time
|
|
16
|
+
- **Capacity Planning** - Identify bottlenecks and plan upgrades
|
|
17
|
+
- **Performance Optimization** - Analyze and improve system efficiency
|
|
18
|
+
- **Troubleshooting** - Diagnose performance issues quickly
|
|
19
|
+
|
|
20
|
+
#### Key Metrics Categories
|
|
21
|
+
|
|
22
|
+
**CPU and Processing:**
|
|
23
|
+
- `cpuUsage` (uint8_t) - CPU usage percentage (0-100)
|
|
24
|
+
- `loopIterations` (uint32_t) - Loop iterations per second
|
|
25
|
+
- `taskQueueSize` (uint16_t) - Number of pending tasks
|
|
26
|
+
|
|
27
|
+
**Memory Metrics:**
|
|
28
|
+
- `freeHeap` (uint32_t) - Current free heap memory in bytes
|
|
29
|
+
- `minFreeHeap` (uint32_t) - Minimum free heap since boot
|
|
30
|
+
- `heapFragmentation` (uint32_t) - Heap fragmentation percentage
|
|
31
|
+
- `maxAllocHeap` (uint32_t) - Largest allocatable block
|
|
32
|
+
|
|
33
|
+
**Network Performance:**
|
|
34
|
+
- `bytesReceived` (uint32_t) - Total bytes received
|
|
35
|
+
- `bytesSent` (uint32_t) - Total bytes sent
|
|
36
|
+
- `packetsReceived` (uint16_t) - Total packets received
|
|
37
|
+
- `packetsSent` (uint16_t) - Total packets sent
|
|
38
|
+
- `packetsDropped` (uint16_t) - Packets dropped
|
|
39
|
+
- `currentThroughput` (uint16_t) - Current throughput in bytes/sec
|
|
40
|
+
|
|
41
|
+
**Timing and Latency:**
|
|
42
|
+
- `avgResponseTime` (uint32_t) - Average response time in microseconds
|
|
43
|
+
- `maxResponseTime` (uint32_t) - Maximum response time in microseconds
|
|
44
|
+
- `avgMeshLatency` (uint16_t) - Average mesh latency in milliseconds
|
|
45
|
+
|
|
46
|
+
**Connection Quality:**
|
|
47
|
+
- `connectionQuality` (uint8_t) - Overall connection quality score (0-100)
|
|
48
|
+
- `wifiRSSI` (int8_t) - WiFi RSSI in dBm
|
|
49
|
+
|
|
50
|
+
**Metadata:**
|
|
51
|
+
- `collectionTimestamp` (uint32_t) - When metrics were collected
|
|
52
|
+
- `collectionInterval` (uint32_t) - Interval between collections in ms
|
|
53
|
+
|
|
54
|
+
#### Example Usage
|
|
55
|
+
|
|
56
|
+
```cpp
|
|
57
|
+
#include "alteriom_sensor_package.hpp"
|
|
58
|
+
using namespace alteriom;
|
|
59
|
+
|
|
60
|
+
void collectAndSendMetrics() {
|
|
61
|
+
MetricsPackage metrics;
|
|
62
|
+
metrics.from = mesh.getNodeId();
|
|
63
|
+
|
|
64
|
+
// Collect CPU metrics
|
|
65
|
+
metrics.cpuUsage = calculateCPUUsage();
|
|
66
|
+
metrics.loopIterations = getLoopsPerSecond();
|
|
67
|
+
metrics.taskQueueSize = scheduler.size();
|
|
68
|
+
|
|
69
|
+
// Collect memory metrics
|
|
70
|
+
metrics.freeHeap = ESP.getFreeHeap();
|
|
71
|
+
metrics.minFreeHeap = getMinHeapSinceBoot();
|
|
72
|
+
#ifdef ESP32
|
|
73
|
+
metrics.maxAllocHeap = ESP.getMaxAllocHeap();
|
|
74
|
+
#else
|
|
75
|
+
metrics.heapFragmentation = ESP.getHeapFragmentation();
|
|
76
|
+
metrics.maxAllocHeap = ESP.getMaxFreeBlockSize();
|
|
77
|
+
#endif
|
|
78
|
+
|
|
79
|
+
// Collect network metrics
|
|
80
|
+
metrics.bytesReceived = getTotalBytesRx();
|
|
81
|
+
metrics.bytesSent = getTotalBytesTx();
|
|
82
|
+
metrics.currentThroughput = calculateThroughput();
|
|
83
|
+
|
|
84
|
+
// Connection quality
|
|
85
|
+
metrics.connectionQuality = calculateConnectionQuality();
|
|
86
|
+
metrics.wifiRSSI = WiFi.RSSI();
|
|
87
|
+
|
|
88
|
+
// Metadata
|
|
89
|
+
metrics.collectionTimestamp = mesh.getNodeTime();
|
|
90
|
+
metrics.collectionInterval = 30000; // 30 seconds
|
|
91
|
+
|
|
92
|
+
// Send metrics
|
|
93
|
+
mesh.sendBroadcast(metrics.toJsonString());
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
#### MQTT Integration
|
|
98
|
+
|
|
99
|
+
When using with the MQTT bridge, metrics are published to:
|
|
100
|
+
- `mesh/metrics/{node_id}` - Per-node metrics
|
|
101
|
+
- `mesh/metrics/aggregated` - Aggregated mesh-wide metrics
|
|
102
|
+
|
|
103
|
+
#### Dashboard Integration
|
|
104
|
+
|
|
105
|
+
**Grafana:**
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"cpu_usage": "${cpuUsage}",
|
|
109
|
+
"free_heap": "${freeHeap}",
|
|
110
|
+
"throughput": "${currentThroughput}",
|
|
111
|
+
"rssi": "${wifiRSSI}",
|
|
112
|
+
"quality": "${connectionQuality}"
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**InfluxDB Line Protocol:**
|
|
117
|
+
```
|
|
118
|
+
metrics,node_id=12345 cpu=${cpuUsage},heap=${freeHeap},throughput=${currentThroughput} ${timestamp}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### HealthCheckPackage (Type 605)
|
|
122
|
+
|
|
123
|
+
A proactive health monitoring package designed for early problem detection, predictive maintenance, and automated alerting.
|
|
124
|
+
|
|
125
|
+
#### Purpose
|
|
126
|
+
|
|
127
|
+
- **Proactive Detection** - Identify problems before they cause failures
|
|
128
|
+
- **Predictive Maintenance** - Estimate time to failure and plan maintenance
|
|
129
|
+
- **Automated Alerting** - Trigger alerts based on health thresholds
|
|
130
|
+
- **Root Cause Analysis** - Provide detailed health indicators for troubleshooting
|
|
131
|
+
|
|
132
|
+
#### Health Status Levels
|
|
133
|
+
|
|
134
|
+
- **2 (Healthy)** - All systems operating normally
|
|
135
|
+
- **1 (Warning)** - Some issues detected, monitoring required
|
|
136
|
+
- **0 (Critical)** - Immediate attention required
|
|
137
|
+
|
|
138
|
+
#### Problem Flags (Bit Flags)
|
|
139
|
+
|
|
140
|
+
| Flag | Value | Description |
|
|
141
|
+
|------|-------|-------------|
|
|
142
|
+
| Low Memory | 0x0001 | Free memory below threshold |
|
|
143
|
+
| High CPU | 0x0002 | CPU usage above threshold |
|
|
144
|
+
| Connection Instability | 0x0004 | Frequent reconnections |
|
|
145
|
+
| High Packet Loss | 0x0008 | Packet loss above threshold |
|
|
146
|
+
| Network Congestion | 0x0010 | Network congestion detected |
|
|
147
|
+
| Low Battery | 0x0020 | Battery level critical |
|
|
148
|
+
| Thermal Warning | 0x0040 | Temperature above safe limit |
|
|
149
|
+
| Mesh Partition | 0x0080 | Mesh network partitioned |
|
|
150
|
+
| OTA in Progress | 0x0100 | Firmware update active |
|
|
151
|
+
| Configuration Error | 0x0200 | Configuration issue detected |
|
|
152
|
+
|
|
153
|
+
#### Health Scores (0-100)
|
|
154
|
+
|
|
155
|
+
Each component (memory, network, performance) has a health score:
|
|
156
|
+
- **90-100** - Excellent
|
|
157
|
+
- **70-89** - Good
|
|
158
|
+
- **50-69** - Fair
|
|
159
|
+
- **30-49** - Poor
|
|
160
|
+
- **0-29** - Critical
|
|
161
|
+
|
|
162
|
+
#### Key Fields
|
|
163
|
+
|
|
164
|
+
**Overall Health:**
|
|
165
|
+
- `healthStatus` (uint8_t) - Overall status (0-2)
|
|
166
|
+
- `problemFlags` (uint16_t) - Bit flags for specific problems
|
|
167
|
+
|
|
168
|
+
**Component Health:**
|
|
169
|
+
- `memoryHealth` (uint8_t) - Memory health score (0-100)
|
|
170
|
+
- `memoryTrend` (uint32_t) - Memory loss rate in bytes/hour
|
|
171
|
+
- `networkHealth` (uint8_t) - Network health score (0-100)
|
|
172
|
+
- `packetLossPercent` (uint8_t) - Current packet loss percentage
|
|
173
|
+
- `reconnectionCount` (uint8_t) - Reconnections in last hour
|
|
174
|
+
- `performanceHealth` (uint8_t) - Performance health score (0-100)
|
|
175
|
+
- `missedDeadlines` (uint32_t) - Missed task deadlines
|
|
176
|
+
- `maxLoopTime` (uint16_t) - Maximum loop execution time in ms
|
|
177
|
+
|
|
178
|
+
**Environmental:**
|
|
179
|
+
- `temperature` (int8_t) - Device temperature in Celsius
|
|
180
|
+
- `temperatureHealth` (uint8_t) - Temperature health score
|
|
181
|
+
|
|
182
|
+
**Stability:**
|
|
183
|
+
- `uptime` (uint32_t) - Uptime in seconds
|
|
184
|
+
- `crashCount` (uint16_t) - Crash/restart count
|
|
185
|
+
- `lastRebootReason` (uint32_t) - Last reboot reason code
|
|
186
|
+
|
|
187
|
+
**Predictive:**
|
|
188
|
+
- `estimatedTimeToFailure` (uint16_t) - Estimated hours until failure (0=unknown)
|
|
189
|
+
- `recommendations` (TSTRING) - Recommended actions
|
|
190
|
+
|
|
191
|
+
#### Example Usage
|
|
192
|
+
|
|
193
|
+
```cpp
|
|
194
|
+
void performHealthCheck() {
|
|
195
|
+
HealthCheckPackage health;
|
|
196
|
+
health.from = mesh.getNodeId();
|
|
197
|
+
|
|
198
|
+
// Calculate component health scores
|
|
199
|
+
uint8_t memHealth = calculateMemoryHealth();
|
|
200
|
+
uint8_t netHealth = calculateNetworkHealth();
|
|
201
|
+
uint8_t perfHealth = calculatePerformanceHealth();
|
|
202
|
+
|
|
203
|
+
// Determine overall health status
|
|
204
|
+
if (memHealth < 30 || netHealth < 30 || perfHealth < 30) {
|
|
205
|
+
health.healthStatus = 0; // Critical
|
|
206
|
+
} else if (memHealth < 60 || netHealth < 60 || perfHealth < 60) {
|
|
207
|
+
health.healthStatus = 1; // Warning
|
|
208
|
+
} else {
|
|
209
|
+
health.healthStatus = 2; // Healthy
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Set problem flags
|
|
213
|
+
health.problemFlags = 0;
|
|
214
|
+
if (memHealth < 60) health.problemFlags |= 0x0001;
|
|
215
|
+
if (perfHealth < 60) health.problemFlags |= 0x0002;
|
|
216
|
+
if (netHealth < 60) health.problemFlags |= 0x0004;
|
|
217
|
+
|
|
218
|
+
// Component health
|
|
219
|
+
health.memoryHealth = memHealth;
|
|
220
|
+
health.memoryTrend = calculateMemoryTrend();
|
|
221
|
+
health.networkHealth = netHealth;
|
|
222
|
+
health.packetLossPercent = getPacketLossPercent();
|
|
223
|
+
health.performanceHealth = perfHealth;
|
|
224
|
+
|
|
225
|
+
// Predictive indicators
|
|
226
|
+
if (health.memoryTrend > 0) {
|
|
227
|
+
uint32_t freeHeap = ESP.getFreeHeap();
|
|
228
|
+
health.estimatedTimeToFailure = freeHeap / health.memoryTrend;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Recommendations
|
|
232
|
+
if (health.healthStatus == 0) {
|
|
233
|
+
health.recommendations = "CRITICAL: Immediate attention required";
|
|
234
|
+
} else if (health.healthStatus == 1) {
|
|
235
|
+
if (memHealth < 60) {
|
|
236
|
+
health.recommendations = "Increase memory allocation";
|
|
237
|
+
} else if (netHealth < 60) {
|
|
238
|
+
health.recommendations = "Check network connections";
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
health.recommendations = "System operating normally";
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Send health check
|
|
245
|
+
mesh.sendBroadcast(health.toJsonString());
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
#### Alert Integration
|
|
250
|
+
|
|
251
|
+
**Home Assistant:**
|
|
252
|
+
```yaml
|
|
253
|
+
- platform: mqtt
|
|
254
|
+
name: "Mesh Node Health"
|
|
255
|
+
state_topic: "mesh/health/12345"
|
|
256
|
+
value_template: "{{ value_json.healthStatus }}"
|
|
257
|
+
json_attributes_topic: "mesh/health/12345"
|
|
258
|
+
json_attributes_template: "{{ value_json | tojson }}"
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Alerting Rules:**
|
|
262
|
+
```yaml
|
|
263
|
+
alerts:
|
|
264
|
+
- name: critical_health
|
|
265
|
+
condition: healthStatus == 0
|
|
266
|
+
action: send_notification
|
|
267
|
+
- name: memory_warning
|
|
268
|
+
condition: memoryHealth < 60
|
|
269
|
+
action: log_warning
|
|
270
|
+
- name: predicted_failure
|
|
271
|
+
condition: estimatedTimeToFailure < 24
|
|
272
|
+
action: schedule_maintenance
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Collection Intervals
|
|
276
|
+
|
|
277
|
+
### Recommended Intervals
|
|
278
|
+
|
|
279
|
+
| Package Type | Interval | Use Case |
|
|
280
|
+
|--------------|----------|----------|
|
|
281
|
+
| MetricsPackage | 30-60s | Normal monitoring |
|
|
282
|
+
| MetricsPackage | 10-30s | Active troubleshooting |
|
|
283
|
+
| MetricsPackage | 5-10s | Critical performance analysis |
|
|
284
|
+
| HealthCheckPackage | 60s | Normal health monitoring |
|
|
285
|
+
| HealthCheckPackage | 30s | Warning state monitoring |
|
|
286
|
+
| HealthCheckPackage | 10s | Critical state monitoring |
|
|
287
|
+
|
|
288
|
+
### Configurable Collection
|
|
289
|
+
|
|
290
|
+
```cpp
|
|
291
|
+
// In setup()
|
|
292
|
+
#define METRICS_INTERVAL 30000 // 30 seconds
|
|
293
|
+
#define HEALTH_INTERVAL 60000 // 60 seconds
|
|
294
|
+
|
|
295
|
+
Task taskMetrics(METRICS_INTERVAL, TASK_FOREVER, &sendMetrics);
|
|
296
|
+
Task taskHealth(HEALTH_INTERVAL, TASK_FOREVER, &sendHealthCheck);
|
|
297
|
+
|
|
298
|
+
userScheduler.addTask(taskMetrics);
|
|
299
|
+
userScheduler.addTask(taskHealth);
|
|
300
|
+
|
|
301
|
+
taskMetrics.enable();
|
|
302
|
+
taskHealth.enable();
|
|
303
|
+
|
|
304
|
+
// Dynamic adjustment based on health status
|
|
305
|
+
void adjustCollectionIntervals(uint8_t healthStatus) {
|
|
306
|
+
if (healthStatus == 0) { // Critical
|
|
307
|
+
taskMetrics.setInterval(10000); // 10 seconds
|
|
308
|
+
taskHealth.setInterval(10000);
|
|
309
|
+
} else if (healthStatus == 1) { // Warning
|
|
310
|
+
taskMetrics.setInterval(20000); // 20 seconds
|
|
311
|
+
taskHealth.setInterval(30000);
|
|
312
|
+
} else { // Healthy
|
|
313
|
+
taskMetrics.setInterval(60000); // 60 seconds
|
|
314
|
+
taskHealth.setInterval(60000);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## MQTT Bridge Integration
|
|
320
|
+
|
|
321
|
+
### Publishing Topics
|
|
322
|
+
|
|
323
|
+
#### Per-Node Topics
|
|
324
|
+
- `mesh/metrics/{node_id}` - Individual node metrics
|
|
325
|
+
- `mesh/health/{node_id}` - Individual node health checks
|
|
326
|
+
|
|
327
|
+
#### Aggregated Topics
|
|
328
|
+
- `mesh/metrics/aggregated` - Mesh-wide aggregated metrics
|
|
329
|
+
- `mesh/health/summary` - Overall mesh health summary
|
|
330
|
+
- `mesh/alerts` - Active alerts across the mesh
|
|
331
|
+
|
|
332
|
+
### Message Format (Updated for @alteriom/mqtt-schema v0.7.2+)
|
|
333
|
+
|
|
334
|
+
Packages now include the `message_type` field for 90% faster message classification:
|
|
335
|
+
|
|
336
|
+
```json
|
|
337
|
+
{
|
|
338
|
+
"schema_version": 1,
|
|
339
|
+
"device_id": "ALT-12345",
|
|
340
|
+
"timestamp": "2025-10-23T21:30:00Z",
|
|
341
|
+
"type": 204,
|
|
342
|
+
"message_type": 204,
|
|
343
|
+
"from": 12345,
|
|
344
|
+
"cpuUsage": 45,
|
|
345
|
+
"freeHeap": 100000,
|
|
346
|
+
"currentThroughput": 8192,
|
|
347
|
+
"connectionQuality": 85,
|
|
348
|
+
"wifiRSSI": -55,
|
|
349
|
+
...
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Message Type Codes (mqtt-schema v0.7.2+):**
|
|
354
|
+
|
|
355
|
+
For performance optimization and standardized routing, all Alteriom packages include the `message_type` field:
|
|
356
|
+
|
|
357
|
+
| Code | Constant | Message Type | Category | Description | PainlessMesh Package |
|
|
358
|
+
|------|----------|--------------|----------|-------------|---------------------|
|
|
359
|
+
| 200 | SENSOR_DATA | sensor_data | telemetry | Sensor telemetry readings | SensorPackage |
|
|
360
|
+
| 202 | SENSOR_STATUS | sensor_status | telemetry | Sensor status change | StatusPackage |
|
|
361
|
+
| 204 | SENSOR_METRICS | sensor_metrics | telemetry | Sensor health and performance metrics | MetricsPackage |
|
|
362
|
+
| 400 | COMMAND | command | control | Device control command | CommandPackage |
|
|
363
|
+
| 600 | MESH_NODE_LIST | mesh_node_list | mesh | Mesh node inventory | MeshNodeListPackage |
|
|
364
|
+
| 601 | MESH_TOPOLOGY | mesh_topology | mesh | Mesh network topology | MeshTopologyPackage |
|
|
365
|
+
| 602 | MESH_ALERT | mesh_alert | mesh | Mesh network alert | MeshAlertPackage |
|
|
366
|
+
| 603 | MESH_BRIDGE | mesh_bridge | mesh | Mesh protocol bridge | MeshBridgePackage |
|
|
367
|
+
| 604 | MESH_STATUS | mesh_status | mesh | Mesh network health status | EnhancedStatusPackage |
|
|
368
|
+
| 605 | MESH_METRICS | mesh_metrics | mesh | Mesh network performance metrics | HealthCheckPackage |
|
|
369
|
+
|
|
370
|
+
**Key Points:**
|
|
371
|
+
- The `message_type` field enables 90% faster message classification compared to parsing JSON
|
|
372
|
+
- All Alteriom packages align with @alteriom/mqtt-schema v0.7.2+ standards
|
|
373
|
+
- Message type codes are consistent across MQTT bridge, gateway, and mesh nodes
|
|
374
|
+
|
|
375
|
+
## Implementation Guide
|
|
376
|
+
|
|
377
|
+
### Basic Implementation
|
|
378
|
+
|
|
379
|
+
See `examples/alteriom/metrics_health_node.ino` for a complete working example.
|
|
380
|
+
|
|
381
|
+
### Integration with Existing Code
|
|
382
|
+
|
|
383
|
+
```cpp
|
|
384
|
+
#include "alteriom_sensor_package.hpp"
|
|
385
|
+
using namespace alteriom;
|
|
386
|
+
|
|
387
|
+
// Add to your existing mesh node
|
|
388
|
+
void setup() {
|
|
389
|
+
// ... existing mesh setup ...
|
|
390
|
+
|
|
391
|
+
// Add metrics collection task
|
|
392
|
+
userScheduler.addTask(Task(30000, TASK_FOREVER, []() {
|
|
393
|
+
MetricsPackage metrics;
|
|
394
|
+
// ... populate metrics ...
|
|
395
|
+
mesh.sendBroadcast(metrics.toJsonString());
|
|
396
|
+
}));
|
|
397
|
+
|
|
398
|
+
// Add health check task
|
|
399
|
+
userScheduler.addTask(Task(60000, TASK_FOREVER, []() {
|
|
400
|
+
HealthCheckPackage health;
|
|
401
|
+
// ... populate health data ...
|
|
402
|
+
mesh.sendBroadcast(health.toJsonString());
|
|
403
|
+
}));
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Gateway Bridge Integration
|
|
408
|
+
|
|
409
|
+
```cpp
|
|
410
|
+
// In MQTT bridge receivedCallback
|
|
411
|
+
void receivedCallback(uint32_t from, String& msg) {
|
|
412
|
+
DynamicJsonDocument doc(2048);
|
|
413
|
+
deserializeJson(doc, msg);
|
|
414
|
+
|
|
415
|
+
uint8_t msgType = doc["type"];
|
|
416
|
+
|
|
417
|
+
switch(msgType) {
|
|
418
|
+
case 204: // MetricsPackage
|
|
419
|
+
publishMetricsToMQTT(from, doc);
|
|
420
|
+
break;
|
|
421
|
+
case 605: // HealthCheckPackage (MESH_METRICS)
|
|
422
|
+
publishHealthToMQTT(from, doc);
|
|
423
|
+
checkForAlerts(doc);
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
void publishMetricsToMQTT(uint32_t from, JsonDocument& doc) {
|
|
429
|
+
String topic = "mesh/metrics/" + String(from);
|
|
430
|
+
String payload;
|
|
431
|
+
serializeJson(doc, payload);
|
|
432
|
+
mqttClient.publish(topic.c_str(), payload.c_str());
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
void checkForAlerts(JsonDocument& doc) {
|
|
436
|
+
uint8_t healthStatus = doc["health"];
|
|
437
|
+
uint16_t problemFlags = doc["problems"];
|
|
438
|
+
|
|
439
|
+
if (healthStatus == 0) {
|
|
440
|
+
String alertTopic = "mesh/alerts/critical";
|
|
441
|
+
String alertMsg = "Critical health on node " + String(doc["from"].as<uint32_t>());
|
|
442
|
+
mqttClient.publish(alertTopic.c_str(), alertMsg.c_str());
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
## Performance Considerations
|
|
448
|
+
|
|
449
|
+
### Memory Usage
|
|
450
|
+
|
|
451
|
+
- **MetricsPackage**: ~200 bytes per message
|
|
452
|
+
- **HealthCheckPackage**: ~250 bytes per message (including recommendations string)
|
|
453
|
+
- **Total overhead**: <1KB for both packages with reasonable collection intervals
|
|
454
|
+
|
|
455
|
+
### Network Bandwidth
|
|
456
|
+
|
|
457
|
+
With 10 nodes and recommended intervals:
|
|
458
|
+
- **Metrics (30s)**: 10 nodes × 200 bytes / 30s = ~67 bytes/sec
|
|
459
|
+
- **Health (60s)**: 10 nodes × 250 bytes / 60s = ~42 bytes/sec
|
|
460
|
+
- **Total**: ~109 bytes/sec = minimal overhead
|
|
461
|
+
|
|
462
|
+
### Optimization Tips
|
|
463
|
+
|
|
464
|
+
1. **Adjust intervals based on load** - Increase intervals during normal operation
|
|
465
|
+
2. **Use selective reporting** - Only send metrics that changed significantly
|
|
466
|
+
3. **Aggregate at gateway** - Combine multiple node metrics before MQTT publish
|
|
467
|
+
4. **Compress recommendations** - Use short, standardized recommendation codes
|
|
468
|
+
5. **Throttle during congestion** - Reduce collection frequency when network is busy
|
|
469
|
+
|
|
470
|
+
## Testing
|
|
471
|
+
|
|
472
|
+
### Unit Tests
|
|
473
|
+
|
|
474
|
+
Run the comprehensive test suite:
|
|
475
|
+
```bash
|
|
476
|
+
./bin/catch_metrics_health_packages
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Tests validate:
|
|
480
|
+
- Serialization/deserialization
|
|
481
|
+
- Field preservation
|
|
482
|
+
- Edge cases (min/max values)
|
|
483
|
+
- Problem flag handling
|
|
484
|
+
- Health status levels
|
|
485
|
+
- Integration with painlessMesh plugin system
|
|
486
|
+
|
|
487
|
+
### Integration Testing
|
|
488
|
+
|
|
489
|
+
```cpp
|
|
490
|
+
// Test metrics collection
|
|
491
|
+
void testMetrics() {
|
|
492
|
+
MetricsPackage metrics;
|
|
493
|
+
metrics.from = 12345;
|
|
494
|
+
metrics.cpuUsage = 45;
|
|
495
|
+
metrics.freeHeap = 100000;
|
|
496
|
+
|
|
497
|
+
auto var = protocol::Variant(&metrics);
|
|
498
|
+
auto metrics2 = var.to<MetricsPackage>();
|
|
499
|
+
|
|
500
|
+
assert(metrics2.cpuUsage == 45);
|
|
501
|
+
assert(metrics2.freeHeap == 100000);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Test health monitoring
|
|
505
|
+
void testHealth() {
|
|
506
|
+
HealthCheckPackage health;
|
|
507
|
+
health.from = 12345;
|
|
508
|
+
health.healthStatus = 1;
|
|
509
|
+
health.problemFlags = 0x0001;
|
|
510
|
+
|
|
511
|
+
auto var = protocol::Variant(&health);
|
|
512
|
+
auto health2 = var.to<HealthCheckPackage>();
|
|
513
|
+
|
|
514
|
+
assert(health2.healthStatus == 1);
|
|
515
|
+
assert(health2.problemFlags == 0x0001);
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
## Migration from Previous Versions
|
|
520
|
+
|
|
521
|
+
### From v1.7.6
|
|
522
|
+
|
|
523
|
+
No breaking changes. Simply add the new packages to your code:
|
|
524
|
+
|
|
525
|
+
```cpp
|
|
526
|
+
// Add new includes
|
|
527
|
+
#include "alteriom_sensor_package.hpp"
|
|
528
|
+
using namespace alteriom;
|
|
529
|
+
|
|
530
|
+
// Add new collection tasks
|
|
531
|
+
// ... see examples above ...
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Backward Compatibility
|
|
535
|
+
|
|
536
|
+
- All existing packages (200-203) continue to work unchanged
|
|
537
|
+
- New packages (204, 604, 605) are optional additions
|
|
538
|
+
- No changes required to existing code
|
|
539
|
+
- Can be adopted incrementally
|
|
540
|
+
|
|
541
|
+
## Best Practices
|
|
542
|
+
|
|
543
|
+
1. **Start with conservative intervals** - Begin with 60s intervals and adjust based on needs
|
|
544
|
+
2. **Monitor memory usage** - Watch heap fragmentation when enabling new packages
|
|
545
|
+
3. **Implement health-based throttling** - Reduce collection frequency when unhealthy
|
|
546
|
+
4. **Use problem flags effectively** - Check specific flags rather than just status
|
|
547
|
+
5. **Act on recommendations** - Implement automated responses to common recommendations
|
|
548
|
+
6. **Set up alerting** - Configure alerts for critical health status
|
|
549
|
+
7. **Track trends** - Use memoryTrend to detect slow memory leaks
|
|
550
|
+
8. **Test thoroughly** - Validate metrics accuracy in your specific environment
|
|
551
|
+
|
|
552
|
+
## Troubleshooting
|
|
553
|
+
|
|
554
|
+
### High Memory Usage
|
|
555
|
+
|
|
556
|
+
- Increase collection intervals
|
|
557
|
+
- Reduce number of active packages
|
|
558
|
+
- Use shorter recommendation strings
|
|
559
|
+
- Check for memory leaks using memoryTrend
|
|
560
|
+
|
|
561
|
+
### Network Congestion
|
|
562
|
+
|
|
563
|
+
- Increase collection intervals
|
|
564
|
+
- Use SINGLE routing instead of BROADCAST for some packages
|
|
565
|
+
- Implement throttling based on network health
|
|
566
|
+
- Reduce message size by removing optional fields
|
|
567
|
+
|
|
568
|
+
### Inaccurate Metrics
|
|
569
|
+
|
|
570
|
+
- Calibrate CPU usage calculation for your use case
|
|
571
|
+
- Validate timing measurements
|
|
572
|
+
- Check clock synchronization across mesh
|
|
573
|
+
- Verify RSSI readings match reality
|
|
574
|
+
|
|
575
|
+
## Future Enhancements
|
|
576
|
+
|
|
577
|
+
Planned for v1.8.0:
|
|
578
|
+
- Compressed metric packages for large meshes
|
|
579
|
+
- Historical trend storage in gateway
|
|
580
|
+
- Automatic threshold tuning
|
|
581
|
+
- Machine learning-based failure prediction
|
|
582
|
+
- Integration with cloud monitoring services
|
|
583
|
+
|
|
584
|
+
## Enhanced MQTT Bridge
|
|
585
|
+
|
|
586
|
+
### Overview
|
|
587
|
+
|
|
588
|
+
The enhanced MQTT bridge (`examples/bridge/enhanced_mqtt_bridge.hpp`) extends the basic MQTT status bridge with command handlers and aggregation capabilities.
|
|
589
|
+
|
|
590
|
+
### Features
|
|
591
|
+
|
|
592
|
+
1. **Command Handlers** - Request metrics and health checks on-demand
|
|
593
|
+
2. **Aggregated Statistics** - Mesh-wide metrics and health summaries
|
|
594
|
+
3. **Automatic Caching** - Stores recent metrics for aggregation
|
|
595
|
+
4. **Alert Detection** - Automatic critical health alerting
|
|
596
|
+
5. **Response Topics** - Dedicated topics for command responses
|
|
597
|
+
|
|
598
|
+
### MQTT Topics
|
|
599
|
+
|
|
600
|
+
#### Subscribe Topics (Commands)
|
|
601
|
+
|
|
602
|
+
| Topic | Payload | Description |
|
|
603
|
+
|-------|---------|-------------|
|
|
604
|
+
| `mesh/command/request_metrics` | `{"node_id": 0}` | Request metrics (0=all nodes) |
|
|
605
|
+
| `mesh/command/request_health` | `{"node_id": 12345}` | Request health check |
|
|
606
|
+
| `mesh/command/get_aggregated` | `{}` | Get current aggregated stats |
|
|
607
|
+
|
|
608
|
+
#### Publish Topics (Data)
|
|
609
|
+
|
|
610
|
+
| Topic | Description | Update Frequency |
|
|
611
|
+
|-------|-------------|------------------|
|
|
612
|
+
| `mesh/metrics/{node_id}` | Individual node metrics | When received from node |
|
|
613
|
+
| `mesh/health/{node_id}` | Individual node health | When received from node |
|
|
614
|
+
| `mesh/aggregated/metrics` | Mesh-wide metrics | Configurable (default 60s) |
|
|
615
|
+
| `mesh/aggregated/health` | Mesh health summary | Configurable (default 60s) |
|
|
616
|
+
| `mesh/alerts/critical` | Critical health alerts | When critical detected |
|
|
617
|
+
| `mesh/response/metrics` | Metrics command response | When node responds |
|
|
618
|
+
| `mesh/response/health` | Health command response | When node responds |
|
|
619
|
+
|
|
620
|
+
### Aggregated Metrics Format
|
|
621
|
+
|
|
622
|
+
```json
|
|
623
|
+
{
|
|
624
|
+
"node_count": 10,
|
|
625
|
+
"avg_cpu": 42,
|
|
626
|
+
"avg_heap": 125000,
|
|
627
|
+
"min_heap": 95000,
|
|
628
|
+
"max_heap": 150000,
|
|
629
|
+
"total_throughput": 81920,
|
|
630
|
+
"avg_quality": 87,
|
|
631
|
+
"min_quality": 65,
|
|
632
|
+
"max_quality": 98,
|
|
633
|
+
"avg_rssi": -58,
|
|
634
|
+
"timestamp": "2025-10-23T21:30:00Z"
|
|
635
|
+
}
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
### Aggregated Health Format
|
|
639
|
+
|
|
640
|
+
```json
|
|
641
|
+
{
|
|
642
|
+
"node_count": 10,
|
|
643
|
+
"mesh_health": 2,
|
|
644
|
+
"healthy_nodes": 8,
|
|
645
|
+
"warning_nodes": 2,
|
|
646
|
+
"critical_nodes": 0,
|
|
647
|
+
"aggregated_problems": 5,
|
|
648
|
+
"avg_memory_health": 82,
|
|
649
|
+
"avg_network_health": 88,
|
|
650
|
+
"avg_performance_health": 90,
|
|
651
|
+
"timestamp": "2025-10-23T21:30:00Z"
|
|
652
|
+
}
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
### Example Usage
|
|
656
|
+
|
|
657
|
+
#### Request Metrics from All Nodes
|
|
658
|
+
|
|
659
|
+
```bash
|
|
660
|
+
mosquitto_pub -h localhost -t mesh/command/request_metrics \
|
|
661
|
+
-m '{"node_id": 0}'
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
#### Request Health from Specific Node
|
|
665
|
+
|
|
666
|
+
```bash
|
|
667
|
+
mosquitto_pub -h localhost -t mesh/command/request_health \
|
|
668
|
+
-m '{"node_id": 12345}'
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
#### Get Current Aggregated Statistics
|
|
672
|
+
|
|
673
|
+
```bash
|
|
674
|
+
mosquitto_pub -h localhost -t mesh/command/get_aggregated -m '{}'
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
#### Subscribe to Aggregated Metrics
|
|
678
|
+
|
|
679
|
+
```bash
|
|
680
|
+
mosquitto_sub -h localhost -t mesh/aggregated/metrics
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
#### Subscribe to Critical Alerts
|
|
684
|
+
|
|
685
|
+
```bash
|
|
686
|
+
mosquitto_sub -h localhost -t mesh/alerts/critical
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
### Integration Example
|
|
690
|
+
|
|
691
|
+
```cpp
|
|
692
|
+
#include "enhanced_mqtt_bridge.hpp"
|
|
693
|
+
|
|
694
|
+
// In setup()
|
|
695
|
+
EnhancedMqttBridge bridge(mesh, mqttClient);
|
|
696
|
+
bridge.setTopicPrefix("mesh/");
|
|
697
|
+
bridge.enableAggregation(true);
|
|
698
|
+
bridge.setAggregationInterval(60000); // 60 seconds
|
|
699
|
+
bridge.begin();
|
|
700
|
+
|
|
701
|
+
// In loop()
|
|
702
|
+
bridge.update();
|
|
703
|
+
|
|
704
|
+
// In MQTT callback
|
|
705
|
+
void mqttCallback(char* topic, byte* payload, unsigned int length) {
|
|
706
|
+
String topicStr = String(topic);
|
|
707
|
+
String payloadStr = String((char*)payload).substring(0, length);
|
|
708
|
+
bridge.handleMQTTMessage(topicStr, payloadStr);
|
|
709
|
+
}
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
### Configuration
|
|
713
|
+
|
|
714
|
+
```cpp
|
|
715
|
+
// Set custom topic prefix
|
|
716
|
+
bridge.setTopicPrefix("alteriom/mesh/");
|
|
717
|
+
|
|
718
|
+
// Set device ID
|
|
719
|
+
bridge.setDeviceId("GATEWAY-001");
|
|
720
|
+
|
|
721
|
+
// Enable/disable aggregation
|
|
722
|
+
bridge.enableAggregation(true);
|
|
723
|
+
|
|
724
|
+
// Set aggregation interval
|
|
725
|
+
bridge.setAggregationInterval(30000); // 30 seconds
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
### Mesh Node Implementation
|
|
729
|
+
|
|
730
|
+
Nodes must respond to command requests:
|
|
731
|
+
|
|
732
|
+
```cpp
|
|
733
|
+
void receivedCallback(uint32_t from, String& msg) {
|
|
734
|
+
DynamicJsonDocument doc(1024);
|
|
735
|
+
deserializeJson(doc, msg);
|
|
736
|
+
|
|
737
|
+
uint8_t msgType = doc["type"];
|
|
738
|
+
|
|
739
|
+
if (msgType == 201) { // CommandPackage
|
|
740
|
+
uint8_t command = doc["cmd"];
|
|
741
|
+
|
|
742
|
+
if (command == 210) { // Request metrics
|
|
743
|
+
sendMetrics();
|
|
744
|
+
} else if (command == 211) { // Request health
|
|
745
|
+
sendHealthCheck();
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
### Performance Considerations
|
|
752
|
+
|
|
753
|
+
**Memory Usage:**
|
|
754
|
+
- Cache size: ~100 bytes per node (max 20 nodes)
|
|
755
|
+
- Total overhead: ~2KB for bridge + caching
|
|
756
|
+
|
|
757
|
+
**Network Bandwidth:**
|
|
758
|
+
- Aggregated metrics: ~200 bytes every 60s
|
|
759
|
+
- Per-node metrics: ~200 bytes when received
|
|
760
|
+
- Critical alerts: ~150 bytes when detected
|
|
761
|
+
|
|
762
|
+
**Optimization:**
|
|
763
|
+
- Adjust cache size via `MAX_STORED_NODES` constant
|
|
764
|
+
- Increase aggregation interval for lower bandwidth
|
|
765
|
+
- Disable aggregation if not needed
|
|
766
|
+
|
|
767
|
+
## Support
|
|
768
|
+
|
|
769
|
+
- **GitHub Issues**: https://github.com/Alteriom/painlessMesh/issues
|
|
770
|
+
- **Documentation**: https://alteriom.github.io/painlessMesh/
|
|
771
|
+
- **Examples**: `examples/alteriom/metrics_health_node.ino`, `examples/bridge/enhanced_mqtt_bridge_example.ino`
|
|
772
|
+
|
|
773
|
+
## Changelog
|
|
774
|
+
|
|
775
|
+
### v1.7.7 (2025-10-23)
|
|
776
|
+
|
|
777
|
+
**Added:**
|
|
778
|
+
- MetricsPackage (Type 204) for comprehensive performance monitoring
|
|
779
|
+
- HealthCheckPackage (Type 605) for proactive health monitoring (MESH_METRICS)
|
|
780
|
+
- Complete test suite for new packages
|
|
781
|
+
- Example implementation in `metrics_health_node.ino`
|
|
782
|
+
- Documentation for MQTT integration
|
|
783
|
+
- Dashboard integration examples
|
|
784
|
+
|
|
785
|
+
**Improved:**
|
|
786
|
+
- MQTT communication efficiency for metrics and health monitoring
|
|
787
|
+
- Problem detection and alerting capabilities
|
|
788
|
+
- Predictive maintenance support
|
|
789
|
+
- Memory leak detection
|
|
790
|
+
|
|
791
|
+
**Compatibility:**
|
|
792
|
+
- 100% backward compatible with v1.7.6
|
|
793
|
+
- All existing packages (200-203) unchanged
|
|
794
|
+
- Optional adoption of new features
|