@alteriom/painlessmesh 1.8.2 → 1.8.4
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 +60 -0
- package/README.md +74 -11
- package/RELEASE_GUIDE.md +57 -16
- package/docs/ARDUINO_LIBRARY_MANAGER_SUBMISSION.md +331 -0
- package/docs/features/DIAGNOSTICS_API.md +534 -0
- package/docs/getting-started/arduino-manual-install.md +313 -0
- package/docs/implementation/BRIDGE_ARCHITECTURE_IMPLEMENTATION.md +340 -0
- package/docs/implementation/BRIDGE_HEALTH_MONITORING_IMPLEMENTATION.md +213 -0
- package/docs/implementation/BRIDGE_STATUS_FEATURE.md +635 -0
- package/docs/implementation/DIAGNOSTICS_API_IMPLEMENTATION.md +232 -0
- package/docs/implementation/IMPLEMENTATION_COMPLETE.md +228 -0
- package/docs/implementation/IMPLEMENTATION_NTP_TIME_SYNC.md +325 -0
- package/docs/implementation/IMPLEMENTATION_SUMMARY.md +316 -0
- package/docs/implementation/MESSAGE_QUEUE_IMPLEMENTATION.md +405 -0
- package/docs/implementation/MULTI_BRIDGE_IMPLEMENTATION.md +520 -0
- package/docs/implementation/NTP_TIME_SYNC_FEATURE.md +392 -0
- package/docs/internal/CUSTOM_AGENT_ANALYSIS.md +391 -0
- package/docs/internal/ISSUE_65_VERIFICATION.md +947 -0
- package/docs/internal/ISSUE_66_CLOSURE.md +249 -0
- package/docs/internal/ISSUE_66_STATUS.md +316 -0
- package/docs/internal/PR_SUMMARY.md +315 -0
- package/docs/internal/REVIEW_SUMMARY.md +332 -0
- package/docs/releases/PUBLISH_v1.8.0_INSTRUCTIONS.md +163 -0
- package/docs/releases/QUICK_START_RELEASES.md +113 -0
- package/docs/releases/RELEASE_CHECKLIST_v1.8.0.md +331 -0
- package/docs/releases/RELEASE_CHECKLIST_v1.8.2.md +309 -0
- package/docs/releases/RELEASE_NOTES_v1.8.0.md +685 -0
- package/docs/releases/RELEASE_NOTES_v1.8.1.md +221 -0
- package/docs/releases/RELEASE_NOTES_v1.8.2.md +421 -0
- package/docs/releases/RELEASE_NOTES_v1.8.3.md +292 -0
- package/docs/releases/RELEASE_NOTES_v1.8.4.md +277 -0
- package/docs/troubleshooting/ARDUINO_IDE_VERSION_FIX_SUMMARY.md +229 -0
- package/docs/troubleshooting/ARDUINO_LIBRARY_NAME_FIX.md +197 -0
- package/docs/troubleshooting/NPM_PUBLISHING_ISSUE_SUMMARY.md +110 -0
- package/docs/troubleshooting/station-reconnection-issues.md +172 -0
- package/examples/bridge_failover/README.md +17 -1
- package/examples/priority/README.md +274 -0
- package/examples/priority/priority_basic_example.ino +115 -0
- package/examples/priority/priority_with_queue.ino +249 -0
- package/examples/routing_demo/README.md +172 -0
- package/examples/routing_demo/routing_demo.ino +102 -0
- package/library.json +1 -1
- package/library.properties +3 -3
- package/package.json +1 -1
- package/src/arduino/wifi.hpp +62 -16
- package/src/painlessMesh.h +15 -0
- package/src/painlessMeshSTA.cpp +7 -1
- package/src/painlessmesh/buffer.hpp +218 -37
- package/src/painlessmesh/connection.hpp +21 -1
- package/src/painlessmesh/mesh.hpp +253 -19
- package/src/painlessmesh/router.hpp +31 -0
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
# Enhanced Diagnostics API for Bridge Operations
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Enhanced Diagnostics API provides comprehensive tools for monitoring, debugging, and analyzing painlessMesh bridge operations. This API gives developers programmatic access to bridge state, election history, network topology, and connectivity testing.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
✅ Bridge status monitoring
|
|
10
|
+
✅ Election history tracking
|
|
11
|
+
✅ Network topology visualization
|
|
12
|
+
✅ Connectivity testing
|
|
13
|
+
✅ Comprehensive diagnostic reports
|
|
14
|
+
✅ Minimal overhead when enabled
|
|
15
|
+
|
|
16
|
+
## Table of Contents
|
|
17
|
+
|
|
18
|
+
- [Getting Started](#getting-started)
|
|
19
|
+
- [Bridge State API](#bridge-state-api)
|
|
20
|
+
- [Network Topology API](#network-topology-api)
|
|
21
|
+
- [Diagnostics API](#diagnostics-api)
|
|
22
|
+
- [Data Structures](#data-structures)
|
|
23
|
+
- [Examples](#examples)
|
|
24
|
+
- [Best Practices](#best-practices)
|
|
25
|
+
|
|
26
|
+
## Getting Started
|
|
27
|
+
|
|
28
|
+
### Enable Diagnostics
|
|
29
|
+
|
|
30
|
+
Diagnostics must be explicitly enabled to track election history and bridge changes:
|
|
31
|
+
|
|
32
|
+
```cpp
|
|
33
|
+
void setup() {
|
|
34
|
+
mesh.init(MESH_SSID, MESH_PASSWORD, &scheduler, MESH_PORT);
|
|
35
|
+
|
|
36
|
+
// Enable diagnostics tracking
|
|
37
|
+
mesh.enableDiagnostics(true);
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Note:** Diagnostics have minimal overhead and only track data when enabled.
|
|
42
|
+
|
|
43
|
+
## Bridge State API
|
|
44
|
+
|
|
45
|
+
### getBridgeStatus()
|
|
46
|
+
|
|
47
|
+
Get current bridge status and role information for this node.
|
|
48
|
+
|
|
49
|
+
```cpp
|
|
50
|
+
BridgeStatus status = mesh.getBridgeStatus();
|
|
51
|
+
|
|
52
|
+
Serial.printf("Role: %s\n", status.role.c_str());
|
|
53
|
+
Serial.printf("Is Bridge: %s\n", status.isBridge ? "Yes" : "No");
|
|
54
|
+
Serial.printf("Internet: %s\n", status.internetConnected ? "Yes" : "No");
|
|
55
|
+
|
|
56
|
+
if (status.bridgeNodeId != 0) {
|
|
57
|
+
Serial.printf("Bridge Node: %u (RSSI: %d dBm)\n",
|
|
58
|
+
status.bridgeNodeId, status.bridgeRSSI);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Returns:** `BridgeStatus` structure containing:
|
|
63
|
+
- `isBridge` - Is this node acting as a bridge?
|
|
64
|
+
- `internetConnected` - Is Internet available?
|
|
65
|
+
- `role` - Node role: "regular", "bridge", or "root"
|
|
66
|
+
- `bridgeNodeId` - Current bridge node ID (0 if none)
|
|
67
|
+
- `bridgeRSSI` - Signal strength to bridge/router (dBm)
|
|
68
|
+
- `timeSinceBridgeChange` - Time since last bridge change (ms)
|
|
69
|
+
|
|
70
|
+
### getElectionHistory()
|
|
71
|
+
|
|
72
|
+
Get list of recent bridge elections (requires diagnostics enabled).
|
|
73
|
+
|
|
74
|
+
```cpp
|
|
75
|
+
auto history = mesh.getElectionHistory();
|
|
76
|
+
|
|
77
|
+
for (const auto& election : history) {
|
|
78
|
+
Serial.printf("Election: Winner=%u, RSSI=%d dBm, Candidates=%u\n",
|
|
79
|
+
election.winnerNodeId, election.winnerRSSI,
|
|
80
|
+
election.candidateCount);
|
|
81
|
+
Serial.printf(" Reason: %s\n", election.reason.c_str());
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Returns:** `std::vector<ElectionRecord>` (limited to last 10 elections)
|
|
86
|
+
|
|
87
|
+
**Note:** Returns empty vector if diagnostics are not enabled.
|
|
88
|
+
|
|
89
|
+
### getLastBridgeChange()
|
|
90
|
+
|
|
91
|
+
Get information about the most recent bridge change event.
|
|
92
|
+
|
|
93
|
+
```cpp
|
|
94
|
+
auto event = mesh.getLastBridgeChange();
|
|
95
|
+
|
|
96
|
+
if (event.timestamp > 0) {
|
|
97
|
+
Serial.printf("Bridge changed from %u to %u\n",
|
|
98
|
+
event.oldBridgeId, event.newBridgeId);
|
|
99
|
+
Serial.printf("Reason: %s\n", event.reason.c_str());
|
|
100
|
+
Serial.printf("Internet available: %s\n",
|
|
101
|
+
event.internetAvailable ? "Yes" : "No");
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Returns:** `BridgeChangeEvent` structure
|
|
106
|
+
|
|
107
|
+
## Network Topology API
|
|
108
|
+
|
|
109
|
+
### getInternetPath(nodeId)
|
|
110
|
+
|
|
111
|
+
Find the routing path from a specific node to the Internet bridge.
|
|
112
|
+
|
|
113
|
+
```cpp
|
|
114
|
+
auto path = mesh.getInternetPath(targetNodeId);
|
|
115
|
+
|
|
116
|
+
if (path.size() > 0) {
|
|
117
|
+
Serial.print("Path to Internet: ");
|
|
118
|
+
for (auto nodeId : path) {
|
|
119
|
+
Serial.printf("%u -> ", nodeId);
|
|
120
|
+
}
|
|
121
|
+
Serial.println("Internet");
|
|
122
|
+
} else {
|
|
123
|
+
Serial.println("No path to Internet available");
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Parameters:**
|
|
128
|
+
- `nodeId` - Node to find path from
|
|
129
|
+
|
|
130
|
+
**Returns:** `std::vector<uint32_t>` containing node IDs in the path (empty if no path)
|
|
131
|
+
|
|
132
|
+
### getBridgeForNodeId(nodeId)
|
|
133
|
+
|
|
134
|
+
Get the bridge node ID that a specific node should use to reach the Internet.
|
|
135
|
+
|
|
136
|
+
```cpp
|
|
137
|
+
uint32_t bridgeId = mesh.getBridgeForNodeId(targetNodeId);
|
|
138
|
+
|
|
139
|
+
if (bridgeId != 0) {
|
|
140
|
+
Serial.printf("Node %u uses bridge %u\n", targetNodeId, bridgeId);
|
|
141
|
+
} else {
|
|
142
|
+
Serial.println("No bridge available");
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Parameters:**
|
|
147
|
+
- `nodeId` - Node to find bridge for
|
|
148
|
+
|
|
149
|
+
**Returns:** Bridge node ID, or 0 if no bridge available
|
|
150
|
+
|
|
151
|
+
### exportTopologyDOT()
|
|
152
|
+
|
|
153
|
+
Export mesh topology in GraphViz DOT format for visualization.
|
|
154
|
+
|
|
155
|
+
```cpp
|
|
156
|
+
String dot = mesh.exportTopologyDOT();
|
|
157
|
+
Serial.println(dot);
|
|
158
|
+
|
|
159
|
+
// Save to file or send to visualization tool
|
|
160
|
+
// Visualize at: http://www.webgraphviz.com/
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Returns:** String containing DOT format graph
|
|
164
|
+
|
|
165
|
+
**Example Output:**
|
|
166
|
+
```dot
|
|
167
|
+
digraph mesh {
|
|
168
|
+
rankdir=TB;
|
|
169
|
+
node [shape=box];
|
|
170
|
+
|
|
171
|
+
"12345" [style=filled,fillcolor=lightblue,label="12345\nBridge"];
|
|
172
|
+
"Internet" [shape=cloud,style=filled,fillcolor=lightgreen];
|
|
173
|
+
"12345" -> "Internet" [style=dashed,color=green];
|
|
174
|
+
"67890";
|
|
175
|
+
"12345" -> "67890" [label="25ms"];
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Diagnostics API
|
|
180
|
+
|
|
181
|
+
### enableDiagnostics(enabled)
|
|
182
|
+
|
|
183
|
+
Enable or disable diagnostics collection.
|
|
184
|
+
|
|
185
|
+
```cpp
|
|
186
|
+
// Enable diagnostics
|
|
187
|
+
mesh.enableDiagnostics(true);
|
|
188
|
+
|
|
189
|
+
// Disable diagnostics
|
|
190
|
+
mesh.enableDiagnostics(false);
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Parameters:**
|
|
194
|
+
- `enabled` - true to enable, false to disable
|
|
195
|
+
|
|
196
|
+
**Note:** Must be enabled before calling `getElectionHistory()` or to track bridge changes.
|
|
197
|
+
|
|
198
|
+
### testBridgeConnectivity()
|
|
199
|
+
|
|
200
|
+
Test connectivity to the primary bridge and measure latency.
|
|
201
|
+
|
|
202
|
+
```cpp
|
|
203
|
+
auto result = mesh.testBridgeConnectivity();
|
|
204
|
+
|
|
205
|
+
if (result.success) {
|
|
206
|
+
Serial.printf("✓ Bridge test PASSED: %s\n", result.message.c_str());
|
|
207
|
+
Serial.printf(" Latency: %u ms\n", result.latencyMs);
|
|
208
|
+
Serial.printf(" Internet reachable: %s\n",
|
|
209
|
+
result.internetReachable ? "Yes" : "No");
|
|
210
|
+
} else {
|
|
211
|
+
Serial.printf("✗ Bridge test FAILED: %s\n", result.message.c_str());
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Returns:** `BridgeTestResult` structure containing:
|
|
216
|
+
- `success` - Overall test success
|
|
217
|
+
- `bridgeReachable` - Can reach bridge node
|
|
218
|
+
- `internetReachable` - Can reach Internet through bridge
|
|
219
|
+
- `latencyMs` - Round-trip latency to bridge
|
|
220
|
+
- `message` - Detailed test message
|
|
221
|
+
|
|
222
|
+
### isBridgeReachable(bridgeNodeId)
|
|
223
|
+
|
|
224
|
+
Check if a specific bridge node is reachable from this node.
|
|
225
|
+
|
|
226
|
+
```cpp
|
|
227
|
+
if (mesh.isBridgeReachable(bridgeNodeId)) {
|
|
228
|
+
Serial.println("Bridge is reachable");
|
|
229
|
+
} else {
|
|
230
|
+
Serial.println("Bridge is NOT reachable");
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Parameters:**
|
|
235
|
+
- `bridgeNodeId` - Bridge node ID to test
|
|
236
|
+
|
|
237
|
+
**Returns:** true if reachable, false otherwise
|
|
238
|
+
|
|
239
|
+
### getDiagnosticReport()
|
|
240
|
+
|
|
241
|
+
Generate a comprehensive, human-readable diagnostic report.
|
|
242
|
+
|
|
243
|
+
```cpp
|
|
244
|
+
Serial.println(mesh.getDiagnosticReport());
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Example Output:**
|
|
248
|
+
```
|
|
249
|
+
=== painlessMesh Diagnostics ===
|
|
250
|
+
Node ID: 12345
|
|
251
|
+
Mode: regular
|
|
252
|
+
Mesh Nodes: 5
|
|
253
|
+
Bridge: 99999 (RSSI: -45 dBm, Internet: ✓)
|
|
254
|
+
Direct Connections: 2
|
|
255
|
+
Messages RX: 1234
|
|
256
|
+
Messages TX: 987
|
|
257
|
+
Messages Dropped: 5
|
|
258
|
+
Avg Latency: 25 ms
|
|
259
|
+
Uptime: 02:15:33
|
|
260
|
+
Last Election: 00:45:12 ago (Winner: 99999, 3 candidates)
|
|
261
|
+
================================
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Returns:** String containing formatted diagnostic report
|
|
265
|
+
|
|
266
|
+
## Data Structures
|
|
267
|
+
|
|
268
|
+
### BridgeStatus
|
|
269
|
+
|
|
270
|
+
```cpp
|
|
271
|
+
struct BridgeStatus {
|
|
272
|
+
bool isBridge; // Is this node acting as a bridge?
|
|
273
|
+
bool internetConnected; // Is Internet available?
|
|
274
|
+
TSTRING role; // "regular", "bridge", or "root"
|
|
275
|
+
uint32_t bridgeNodeId; // Current bridge node ID (0 if none)
|
|
276
|
+
int8_t bridgeRSSI; // Signal strength to bridge (dBm)
|
|
277
|
+
uint32_t timeSinceBridgeChange; // Time since last bridge change (ms)
|
|
278
|
+
};
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### ElectionRecord
|
|
282
|
+
|
|
283
|
+
```cpp
|
|
284
|
+
struct ElectionRecord {
|
|
285
|
+
uint32_t timestamp; // When election occurred (millis)
|
|
286
|
+
uint32_t winnerNodeId; // Node that won election
|
|
287
|
+
int8_t winnerRSSI; // Winner's router RSSI
|
|
288
|
+
uint32_t candidateCount; // Number of candidates
|
|
289
|
+
TSTRING reason; // Why election was triggered
|
|
290
|
+
};
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### BridgeChangeEvent
|
|
294
|
+
|
|
295
|
+
```cpp
|
|
296
|
+
struct BridgeChangeEvent {
|
|
297
|
+
uint32_t timestamp; // When change occurred (millis)
|
|
298
|
+
uint32_t oldBridgeId; // Previous bridge node ID
|
|
299
|
+
uint32_t newBridgeId; // New bridge node ID
|
|
300
|
+
TSTRING reason; // Reason for change
|
|
301
|
+
bool internetAvailable; // Internet available after change
|
|
302
|
+
};
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### BridgeTestResult
|
|
306
|
+
|
|
307
|
+
```cpp
|
|
308
|
+
struct BridgeTestResult {
|
|
309
|
+
bool success; // Overall test success
|
|
310
|
+
bool bridgeReachable; // Can reach bridge node
|
|
311
|
+
bool internetReachable; // Can reach Internet
|
|
312
|
+
uint32_t latencyMs; // Round-trip latency (ms)
|
|
313
|
+
TSTRING message; // Detailed test message
|
|
314
|
+
};
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Examples
|
|
318
|
+
|
|
319
|
+
### Basic Diagnostics Monitoring
|
|
320
|
+
|
|
321
|
+
```cpp
|
|
322
|
+
void setup() {
|
|
323
|
+
mesh.init(MESH_SSID, MESH_PASSWORD, &scheduler, MESH_PORT);
|
|
324
|
+
mesh.enableDiagnostics(true);
|
|
325
|
+
|
|
326
|
+
// Print diagnostics every 30 seconds
|
|
327
|
+
userScheduler.addTask(Task(30000, TASK_FOREVER, []() {
|
|
328
|
+
Serial.println(mesh.getDiagnosticReport());
|
|
329
|
+
}));
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Bridge Status Monitoring with Callback
|
|
334
|
+
|
|
335
|
+
```cpp
|
|
336
|
+
void setup() {
|
|
337
|
+
mesh.onBridgeStatusChanged([](uint32_t bridgeId, bool hasInternet) {
|
|
338
|
+
if (hasInternet) {
|
|
339
|
+
Serial.println("Internet available - sending queued data");
|
|
340
|
+
sendQueuedMessages();
|
|
341
|
+
} else {
|
|
342
|
+
Serial.println("Internet offline - queueing messages");
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Periodic Bridge Connectivity Testing
|
|
349
|
+
|
|
350
|
+
```cpp
|
|
351
|
+
Task testTask(60000, TASK_FOREVER, []() {
|
|
352
|
+
auto result = mesh.testBridgeConnectivity();
|
|
353
|
+
|
|
354
|
+
if (!result.success) {
|
|
355
|
+
Serial.printf("Bridge issue: %s\n", result.message.c_str());
|
|
356
|
+
// Trigger failover or alert
|
|
357
|
+
} else if (result.latencyMs > 100) {
|
|
358
|
+
Serial.println("Warning: High latency to bridge");
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Topology Visualization Export
|
|
364
|
+
|
|
365
|
+
```cpp
|
|
366
|
+
// Export topology every 5 minutes for external visualization
|
|
367
|
+
Task exportTask(300000, TASK_FOREVER, []() {
|
|
368
|
+
String dot = mesh.exportTopologyDOT();
|
|
369
|
+
|
|
370
|
+
// Send to monitoring server or save to SD card
|
|
371
|
+
sendToMonitoringServer(dot);
|
|
372
|
+
|
|
373
|
+
// Or save locally
|
|
374
|
+
File file = SD.open("/topology.dot", FILE_WRITE);
|
|
375
|
+
file.print(dot);
|
|
376
|
+
file.close();
|
|
377
|
+
});
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Best Practices
|
|
381
|
+
|
|
382
|
+
### 1. Enable Diagnostics Selectively
|
|
383
|
+
|
|
384
|
+
Only enable diagnostics when needed for debugging or monitoring:
|
|
385
|
+
|
|
386
|
+
```cpp
|
|
387
|
+
#ifdef DEBUG
|
|
388
|
+
mesh.enableDiagnostics(true);
|
|
389
|
+
#endif
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### 2. Monitor Bridge Changes
|
|
393
|
+
|
|
394
|
+
Always set up a bridge status callback to react to connectivity changes:
|
|
395
|
+
|
|
396
|
+
```cpp
|
|
397
|
+
mesh.onBridgeStatusChanged([](uint32_t bridgeId, bool hasInternet) {
|
|
398
|
+
// Handle bridge state changes
|
|
399
|
+
if (!hasInternet) {
|
|
400
|
+
startOfflineMode();
|
|
401
|
+
} else {
|
|
402
|
+
resumeOnlineMode();
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### 3. Test Connectivity Before Critical Operations
|
|
408
|
+
|
|
409
|
+
Before sending important data, test bridge connectivity:
|
|
410
|
+
|
|
411
|
+
```cpp
|
|
412
|
+
void sendCriticalData(String data) {
|
|
413
|
+
auto result = mesh.testBridgeConnectivity();
|
|
414
|
+
|
|
415
|
+
if (result.success && result.internetReachable) {
|
|
416
|
+
mesh.sendSingle(bridgeId, data);
|
|
417
|
+
} else {
|
|
418
|
+
queueForLater(data);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### 4. Use Diagnostic Reports for Troubleshooting
|
|
424
|
+
|
|
425
|
+
When users report issues, ask them to copy the diagnostic report:
|
|
426
|
+
|
|
427
|
+
```cpp
|
|
428
|
+
// Add a command to print diagnostics on demand
|
|
429
|
+
if (Serial.available()) {
|
|
430
|
+
char cmd = Serial.read();
|
|
431
|
+
if (cmd == 'd') {
|
|
432
|
+
Serial.println(mesh.getDiagnosticReport());
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### 5. Export Topology for Visualization
|
|
438
|
+
|
|
439
|
+
Regularly export topology to understand mesh structure:
|
|
440
|
+
|
|
441
|
+
```cpp
|
|
442
|
+
// Export topology to help visualize network issues
|
|
443
|
+
void exportTopology() {
|
|
444
|
+
String dot = mesh.exportTopologyDOT();
|
|
445
|
+
|
|
446
|
+
// Save or transmit for later analysis
|
|
447
|
+
// Visualize at http://www.webgraphviz.com/
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## Performance Considerations
|
|
452
|
+
|
|
453
|
+
- **Memory:** Election history limited to 10 records (approximately 200 bytes)
|
|
454
|
+
- **CPU:** Minimal overhead when diagnostics enabled (<1% CPU)
|
|
455
|
+
- **Network:** No additional network traffic (uses existing bridge status messages)
|
|
456
|
+
|
|
457
|
+
## Integration with Monitoring Systems
|
|
458
|
+
|
|
459
|
+
### MQTT Example
|
|
460
|
+
|
|
461
|
+
```cpp
|
|
462
|
+
void publishDiagnostics() {
|
|
463
|
+
String report = mesh.getDiagnosticReport();
|
|
464
|
+
mqttClient.publish("mesh/diagnostics", report.c_str());
|
|
465
|
+
|
|
466
|
+
auto status = mesh.getBridgeStatus();
|
|
467
|
+
String json = String("{\"role\":\"") + status.role +
|
|
468
|
+
"\",\"internet\":" + (status.internetConnected ? "true" : "false") +
|
|
469
|
+
",\"bridge\":" + status.bridgeNodeId + "}";
|
|
470
|
+
mqttClient.publish("mesh/status", json.c_str());
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### HTTP REST API Example
|
|
475
|
+
|
|
476
|
+
```cpp
|
|
477
|
+
void handleDiagnosticsRequest() {
|
|
478
|
+
server.send(200, "text/plain", mesh.getDiagnosticReport());
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
void handleTopologyRequest() {
|
|
482
|
+
server.send(200, "text/plain", mesh.exportTopologyDOT());
|
|
483
|
+
}
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
## Troubleshooting
|
|
487
|
+
|
|
488
|
+
### Q: getElectionHistory() returns empty vector
|
|
489
|
+
|
|
490
|
+
**A:** Ensure diagnostics are enabled with `mesh.enableDiagnostics(true)` before elections occur.
|
|
491
|
+
|
|
492
|
+
### Q: testBridgeConnectivity() always fails
|
|
493
|
+
|
|
494
|
+
**A:** Check that:
|
|
495
|
+
1. A bridge node exists in the mesh
|
|
496
|
+
2. The bridge is broadcasting status (enabled by default)
|
|
497
|
+
3. Your node can route to the bridge
|
|
498
|
+
|
|
499
|
+
### Q: getDiagnosticReport() shows "Bridge: None available"
|
|
500
|
+
|
|
501
|
+
**A:** This means no healthy bridge with Internet connection was found. Check:
|
|
502
|
+
1. Bridge node is running and configured correctly
|
|
503
|
+
2. Bridge has Internet connectivity
|
|
504
|
+
3. Bridge status broadcasts are enabled
|
|
505
|
+
|
|
506
|
+
## API Reference Summary
|
|
507
|
+
|
|
508
|
+
| Method | Description | Returns |
|
|
509
|
+
|--------|-------------|---------|
|
|
510
|
+
| `enableDiagnostics(bool)` | Enable/disable diagnostics tracking | void |
|
|
511
|
+
| `getBridgeStatus()` | Get current bridge status | BridgeStatus |
|
|
512
|
+
| `getElectionHistory()` | Get recent elections | vector<ElectionRecord> |
|
|
513
|
+
| `getLastBridgeChange()` | Get last bridge change | BridgeChangeEvent |
|
|
514
|
+
| `getInternetPath(nodeId)` | Get path to Internet | vector<uint32_t> |
|
|
515
|
+
| `getBridgeForNodeId(nodeId)` | Get bridge for node | uint32_t |
|
|
516
|
+
| `exportTopologyDOT()` | Export topology | String |
|
|
517
|
+
| `testBridgeConnectivity()` | Test bridge connection | BridgeTestResult |
|
|
518
|
+
| `isBridgeReachable(id)` | Check bridge reachability | bool |
|
|
519
|
+
| `getDiagnosticReport()` | Get comprehensive report | String |
|
|
520
|
+
|
|
521
|
+
## See Also
|
|
522
|
+
|
|
523
|
+
- [Bridge Architecture](BRIDGE_ARCHITECTURE_IMPLEMENTATION.md)
|
|
524
|
+
- [Bridge Health Monitoring](BRIDGE_HEALTH_MONITORING_IMPLEMENTATION.md)
|
|
525
|
+
- [Example Sketch](examples/diagnosticsExample/diagnosticsExample.ino)
|
|
526
|
+
- [API Documentation](docs/)
|
|
527
|
+
|
|
528
|
+
## Version History
|
|
529
|
+
|
|
530
|
+
- **v1.8.1** - Initial release of Enhanced Diagnostics API
|
|
531
|
+
|
|
532
|
+
## License
|
|
533
|
+
|
|
534
|
+
This feature is part of painlessMesh and follows the same license terms.
|