@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
@@ -0,0 +1,554 @@
1
+ # OTA Commands and API Reference
2
+
3
+ ## Overview
4
+
5
+ This document provides a complete reference for OTA (Over-The-Air) firmware update commands in painlessMesh, including Phase 2 broadcast mode enhancements and Alteriom MQTT schema compliance for firmware status reporting.
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [OTA Command API](#ota-command-api)
10
+ 2. [Broadcast OTA (Phase 2)](#broadcast-ota-phase-2)
11
+ 3. [Firmware Status Reporting](#firmware-status-reporting)
12
+ 4. [MQTT Schema Compliance](#mqtt-schema-compliance)
13
+ 5. [Complete Examples](#complete-examples)
14
+ 6. [Troubleshooting](#troubleshooting)
15
+
16
+ ---
17
+
18
+ ## OTA Command API
19
+
20
+ ### mesh.offerOTA()
21
+
22
+ Announce and distribute firmware updates to mesh nodes.
23
+
24
+ ```cpp
25
+ std::shared_ptr<Task> offerOTA(
26
+ TSTRING role,
27
+ TSTRING hardware,
28
+ TSTRING md5,
29
+ size_t noPart,
30
+ bool forced = false,
31
+ bool broadcasted = false, // Phase 2 feature
32
+ bool compressed = false // Phase 1 feature
33
+ )
34
+ ```
35
+
36
+ #### Parameters
37
+
38
+ | Parameter | Type | Description | Default |
39
+ |-----------|------|-------------|---------|
40
+ | `role` | TSTRING | Target node role (e.g., "sensor", "gateway") | Required |
41
+ | `hardware` | TSTRING | Hardware type: "ESP32" or "ESP8266" | Required |
42
+ | `md5` | TSTRING | MD5 hash of firmware binary for version checking | Required |
43
+ | `noPart` | size_t | Total number of firmware chunks | Required |
44
+ | `forced` | bool | Force update even if MD5 matches current version | false |
45
+ | `broadcasted` | bool | **[Phase 2]** Enable broadcast distribution mode | false |
46
+ | `compressed` | bool | [Phase 1] Enable compression (40-60% bandwidth savings) | false |
47
+
48
+ #### Returns
49
+
50
+ `std::shared_ptr<Task>` - Shared pointer to task managing OTA announcements
51
+
52
+ #### Behavior
53
+
54
+ **Unicast Mode (broadcasted=false):**
55
+ - Each node requests chunks individually
56
+ - Root node responds to each request
57
+ - Network traffic: O(N × F) where N=nodes, F=firmware size
58
+ - Best for: 1-10 nodes
59
+
60
+ **Broadcast Mode (broadcasted=true):**
61
+ - Root node broadcasts chunks once
62
+ - All nodes receive simultaneously
63
+ - Network traffic: O(F) - independent of node count
64
+ - Best for: 10-100+ nodes
65
+ - ~98% traffic reduction for 50-node mesh
66
+
67
+ #### Example
68
+
69
+ ```cpp
70
+ // Phase 2 Broadcast OTA with compression
71
+ auto otaTask = mesh.offerOTA(
72
+ "sensor", // Role
73
+ "ESP32", // Hardware
74
+ firmwareMD5, // MD5 hash
75
+ numChunks, // Number of chunks
76
+ false, // Not forced
77
+ true, // BROADCAST MODE (Phase 2)
78
+ true // Compressed (Phase 1)
79
+ );
80
+
81
+ // Monitor OTA progress
82
+ otaTask->setCallback([]() {
83
+ Serial.println("OTA announcement sent");
84
+ });
85
+ ```
86
+
87
+ ### mesh.initOTAReceive()
88
+
89
+ Initialize OTA receiver on a node to accept firmware updates.
90
+
91
+ ```cpp
92
+ void initOTAReceive(
93
+ TSTRING role,
94
+ std::function<void(size_t current, size_t total)> progressCallback = nullptr,
95
+ bool acceptCompressed = true,
96
+ bool acceptBroadcast = true
97
+ )
98
+ ```
99
+
100
+ #### Parameters
101
+
102
+ | Parameter | Type | Description | Default |
103
+ |-----------|------|-------------|---------|
104
+ | `role` | TSTRING | This node's role for matching firmware | Required |
105
+ | `progressCallback` | function | Callback for progress updates (current, total) | nullptr |
106
+ | `acceptCompressed` | bool | Accept compressed firmware (Phase 1) | true |
107
+ | `acceptBroadcast` | bool | Accept broadcast OTA (Phase 2) | true |
108
+
109
+ #### Example
110
+
111
+ ```cpp
112
+ mesh.initOTAReceive(
113
+ "sensor",
114
+ [](size_t current, size_t total) {
115
+ Serial.printf("OTA Progress: %d/%d (%d%%)\n",
116
+ current, total, (current * 100) / total);
117
+ },
118
+ true, // Accept compressed
119
+ true // Accept broadcast
120
+ );
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Broadcast OTA (Phase 2)
126
+
127
+ ### Architecture
128
+
129
+ Broadcast OTA distributes firmware to all nodes simultaneously instead of individually, dramatically reducing network traffic and update time.
130
+
131
+ **Message Flow:**
132
+
133
+ ```
134
+ 1. Root Node Announces Update:
135
+ Root → ALL: Broadcast Announce {role, hardware, md5, noPart, broadcasted=true}
136
+
137
+ 2. Root Node Broadcasts Chunks:
138
+ Root → ALL: Broadcast Data(chunk 0)
139
+ Root → ALL: Broadcast Data(chunk 1)
140
+ Root → ALL: Broadcast Data(chunk 2)
141
+ ...
142
+ Root → ALL: Broadcast Data(chunk N)
143
+
144
+ 3. All Nodes Process:
145
+ Each node:
146
+ - Receives broadcasts
147
+ - Assembles chunks
148
+ - Verifies MD5
149
+ - Flashes firmware
150
+ - Reboots into new version
151
+ ```
152
+
153
+ ### Performance Comparison
154
+
155
+ | Mesh Size | Unicast Transmissions | Broadcast Transmissions | Reduction | Time Improvement |
156
+ |-----------|----------------------|------------------------|-----------|------------------|
157
+ | 10 nodes | 1,500 | 150 | 90% | ~10x faster |
158
+ | 50 nodes | 7,500 | 150 | 98% | ~50x faster |
159
+ | 100 nodes | 15,000 | 150 | 99% | ~100x faster |
160
+
161
+ *Assuming 150 firmware chunks*
162
+
163
+ ### Memory Requirements
164
+
165
+ **Per Node:**
166
+ - Chunk buffer: ~1-2KB
167
+ - Tracking bitmap: ~1KB (for 150 chunks)
168
+ - Total overhead: +2-5KB
169
+
170
+ **Scalability:**
171
+ - Tested: Up to 100 nodes
172
+ - Theoretical: 200+ nodes with proper rate limiting
173
+ - Recommended: 10-100 nodes for optimal performance
174
+
175
+ ### Implementation Details
176
+
177
+ The broadcast mode is implemented through a minimal change to `src/painlessmesh/ota.hpp`:
178
+
179
+ ```cpp
180
+ static Data replyTo(const DataRequest& req, TSTRING data, size_t partNo) {
181
+ Data d;
182
+ // ... initialize fields ...
183
+
184
+ // Phase 2: Set BROADCAST routing when broadcasted flag is true
185
+ if (req.broadcasted) {
186
+ d.routing = router::BROADCAST;
187
+ }
188
+ return d;
189
+ }
190
+ ```
191
+
192
+ ### Best Practices
193
+
194
+ 1. **Rate Limiting:** Don't broadcast chunks faster than nodes can process
195
+ 2. **Chunk Size:** Use 1024-2048 byte chunks for optimal balance
196
+ 3. **Network Stability:** Ensure mesh is stable before starting OTA
197
+ 4. **Monitoring:** Use progress callbacks to track update status
198
+ 5. **Fallback:** Keep unicast mode available for small deployments
199
+
200
+ ---
201
+
202
+ ## Firmware Status Reporting
203
+
204
+ ### Alteriom MQTT Schema v1 Compliance
205
+
206
+ The firmware update process can report status using the Alteriom MQTT schema `firmware_status.schema.json` v1.
207
+
208
+ #### Schema Structure
209
+
210
+ ```json
211
+ {
212
+ "schema_version": 1,
213
+ "device_id": "node-123456",
214
+ "device_type": "sensor",
215
+ "timestamp": "2024-10-11T16:30:00Z",
216
+ "firmware_version": "1.0.0",
217
+ "status": "downloading",
218
+ "from_version": "1.0.0",
219
+ "to_version": "2.0.0",
220
+ "progress_pct": 45.5,
221
+ "error": null
222
+ }
223
+ ```
224
+
225
+ #### Status Values
226
+
227
+ | Status | Description | Required Fields |
228
+ |--------|-------------|----------------|
229
+ | `pending` | Update queued, not started | None |
230
+ | `downloading` | Downloading firmware chunks | `progress_pct` recommended |
231
+ | `flashing` | Writing firmware to flash | `progress_pct` recommended |
232
+ | `verifying` | Verifying firmware integrity | None |
233
+ | `rebooting` | Rebooting into new firmware | None |
234
+ | `completed` | Update successful | `to_version` |
235
+ | `failed` | Update failed | `error` required |
236
+
237
+ #### Example Implementation
238
+
239
+ ```cpp
240
+ // Report OTA progress via MQTT
241
+ void reportOTAStatus(String status, float progress = -1, String error = "") {
242
+ DynamicJsonDocument doc(512);
243
+
244
+ // Envelope fields (required)
245
+ doc["schema_version"] = 1;
246
+ doc["device_id"] = String(mesh.getNodeId());
247
+ doc["device_type"] = "sensor";
248
+ doc["timestamp"] = getCurrentISO8601Timestamp();
249
+ doc["firmware_version"] = FIRMWARE_VERSION;
250
+
251
+ // Firmware status fields
252
+ doc["status"] = status;
253
+ doc["from_version"] = OLD_VERSION;
254
+ doc["to_version"] = NEW_VERSION;
255
+
256
+ if (progress >= 0) {
257
+ doc["progress_pct"] = progress;
258
+ }
259
+
260
+ if (error.length() > 0) {
261
+ doc["error"] = error;
262
+ } else {
263
+ doc["error"] = nullptr;
264
+ }
265
+
266
+ String payload;
267
+ serializeJson(doc, payload);
268
+ mqttClient.publish("device/firmware/status", payload.c_str());
269
+ }
270
+
271
+ // Usage in OTA progress callback
272
+ mesh.initOTAReceive("sensor", [](size_t current, size_t total) {
273
+ float progress = (current * 100.0) / total;
274
+
275
+ if (current == 0) {
276
+ reportOTAStatus("downloading", 0);
277
+ } else if (current < total) {
278
+ reportOTAStatus("downloading", progress);
279
+ } else {
280
+ reportOTAStatus("flashing", 100);
281
+ }
282
+ });
283
+ ```
284
+
285
+ ---
286
+
287
+ ## MQTT Schema Compliance
288
+
289
+ ### Gateway Metrics
290
+
291
+ The MQTT Status Bridge publishes gateway metrics in full compliance with Alteriom MQTT schema v1.
292
+
293
+ **Schema:** `gateway_metrics.schema.json` v1
294
+
295
+ **Required Fields:**
296
+ - Envelope: `schema_version`, `device_id`, `device_type`, `timestamp`, `firmware_version`
297
+ - Metrics: `uptime_s` (minimum required)
298
+
299
+ **Published Message:**
300
+ ```json
301
+ {
302
+ "schema_version": 1,
303
+ "device_id": "gateway-001",
304
+ "device_type": "gateway",
305
+ "timestamp": "2024-10-11T16:30:00Z",
306
+ "firmware_version": "2.1.0",
307
+ "metrics": {
308
+ "uptime_s": 3600,
309
+ "mesh_nodes": 12,
310
+ "memory_usage_pct": 45.2,
311
+ "connected_devices": 12
312
+ }
313
+ }
314
+ ```
315
+
316
+ ### Validation
317
+
318
+ To validate messages against the schema:
319
+
320
+ ```javascript
321
+ // Node.js validation example
322
+ const { validators } = require('@alteriom/mqtt-schema');
323
+
324
+ const message = JSON.parse(mqttPayload);
325
+ const result = validators.gatewayMetrics(message);
326
+
327
+ if (!result.valid) {
328
+ console.error('Validation errors:', result.errors);
329
+ }
330
+ ```
331
+
332
+ ---
333
+
334
+ ## Complete Examples
335
+
336
+ ### Example 1: Basic OTA Sender
337
+
338
+ ```cpp
339
+ #include <painlessMesh.h>
340
+
341
+ #define MESH_PREFIX "mesh"
342
+ #define MESH_PASSWORD "password"
343
+ #define MESH_PORT 5555
344
+
345
+ painlessMesh mesh;
346
+
347
+ void setup() {
348
+ Serial.begin(115200);
349
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, MESH_PORT);
350
+
351
+ // Calculate firmware chunks
352
+ File firmware = SD.open("/firmware.bin");
353
+ size_t fileSize = firmware.size();
354
+ size_t numChunks = (fileSize + 1023) / 1024; // 1KB chunks
355
+ String md5 = calculateMD5(firmware);
356
+
357
+ // Offer OTA with Phase 2 broadcast
358
+ auto otaTask = mesh.offerOTA(
359
+ "sensor",
360
+ "ESP32",
361
+ md5,
362
+ numChunks,
363
+ false, // not forced
364
+ true, // BROADCAST
365
+ true // compressed
366
+ );
367
+
368
+ Serial.println("Broadcasting OTA update...");
369
+ }
370
+
371
+ void loop() {
372
+ mesh.update();
373
+ }
374
+ ```
375
+
376
+ ### Example 2: OTA Receiver with Status Reporting
377
+
378
+ ```cpp
379
+ #include <painlessMesh.h>
380
+ #include <PubSubClient.h>
381
+
382
+ painlessMesh mesh;
383
+ PubSubClient mqttClient;
384
+
385
+ void reportOTAStatus(String status, float progress = -1) {
386
+ // Implementation as shown above
387
+ }
388
+
389
+ void setup() {
390
+ Serial.begin(115200);
391
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, MESH_PORT);
392
+
393
+ // Initialize OTA receiver with progress reporting
394
+ mesh.initOTAReceive(
395
+ "sensor",
396
+ [](size_t current, size_t total) {
397
+ float pct = (current * 100.0) / total;
398
+ Serial.printf("OTA: %d/%d (%.1f%%)\n", current, total, pct);
399
+
400
+ // Report via MQTT
401
+ if (current == 0) {
402
+ reportOTAStatus("downloading", 0);
403
+ } else if (current < total) {
404
+ reportOTAStatus("downloading", pct);
405
+ } else {
406
+ reportOTAStatus("flashing", 100);
407
+ }
408
+ },
409
+ true, // accept compressed
410
+ true // accept broadcast
411
+ );
412
+ }
413
+
414
+ void loop() {
415
+ mesh.update();
416
+ mqttClient.loop();
417
+ }
418
+ ```
419
+
420
+ ### Example 3: Full MQTT Bridge with Schema Compliance
421
+
422
+ ```cpp
423
+ #include <painlessMesh.h>
424
+ #include <PubSubClient.h>
425
+ #include "examples/bridge/mqtt_status_bridge.hpp"
426
+
427
+ painlessMesh mesh;
428
+ WiFiClient wifiClient;
429
+ PubSubClient mqttClient(wifiClient);
430
+ MqttStatusBridge* statusBridge;
431
+
432
+ void setup() {
433
+ Serial.begin(115200);
434
+
435
+ // Initialize mesh as bridge node
436
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, MESH_PORT, WIFI_AP_STA);
437
+ mesh.setRoot(true);
438
+ mesh.setContainsRoot(true);
439
+ mesh.stationManual(WIFI_SSID, WIFI_PASSWORD);
440
+
441
+ // Connect to MQTT broker
442
+ mqttClient.setServer(MQTT_BROKER, 1883);
443
+ mqttClient.connect("painlessMesh-bridge");
444
+
445
+ // Initialize schema-compliant MQTT status bridge
446
+ statusBridge = new MqttStatusBridge(mesh, mqttClient);
447
+ statusBridge->setDeviceId("gateway-001");
448
+ statusBridge->setFirmwareVersion("2.1.0");
449
+ statusBridge->setPublishInterval(30000); // 30 seconds
450
+ statusBridge->enableMetrics(true); // Schema v1 compliant
451
+ statusBridge->enableTopology(true);
452
+ statusBridge->enableAlerts(true);
453
+ statusBridge->begin();
454
+
455
+ Serial.println("MQTT Status Bridge started");
456
+ Serial.println("Publishing schema-compliant gateway metrics");
457
+ }
458
+
459
+ void loop() {
460
+ mesh.update();
461
+ mqttClient.loop();
462
+ }
463
+ ```
464
+
465
+ ---
466
+
467
+ ## Troubleshooting
468
+
469
+ ### Common Issues
470
+
471
+ #### 1. OTA Not Starting
472
+
473
+ **Symptom:** Nodes don't respond to OTA announcements
474
+
475
+ **Solutions:**
476
+ - Verify role matches between sender and receiver
477
+ - Check hardware type (ESP32 vs ESP8266)
478
+ - Ensure nodes have OTA initialized with `initOTAReceive()`
479
+ - Check MD5 is different from current firmware
480
+
481
+ #### 2. Broadcast OTA Slow/Failing
482
+
483
+ **Symptom:** Broadcast mode slower than expected or nodes miss chunks
484
+
485
+ **Solutions:**
486
+ - Reduce broadcast rate (add delays between chunks)
487
+ - Check mesh stability (`mesh.getNodeList()` should be stable)
488
+ - Verify sufficient memory on nodes (check `ESP.getFreeHeap()`)
489
+ - Consider smaller chunk size for congested meshes
490
+ - Reduce number of nodes or use unicast for <10 nodes
491
+
492
+ #### 3. Schema Validation Failures
493
+
494
+ **Symptom:** MQTT consumers reject messages
495
+
496
+ **Solutions:**
497
+ - Verify `schema_version` is exactly 1 (integer)
498
+ - Check `device_id` matches pattern `^[A-Za-z0-9_-]+$` (no spaces)
499
+ - Ensure `device_type` is exactly "gateway" or "sensor"
500
+ - Validate timestamp is ISO 8601: `YYYY-MM-DDTHH:MM:SSZ`
501
+ - Check `firmware_version` is not empty and ≤40 characters
502
+ - Ensure `metrics` object exists for gateway_metrics
503
+ - Verify `uptime_s` is present and non-negative integer
504
+
505
+ #### 4. Timestamp Issues
506
+
507
+ **Symptom:** Timestamps rejected or incorrect
508
+
509
+ **Solutions:**
510
+ - Use NTP time sync for accurate timestamps
511
+ - Implement RTC module for offline accuracy
512
+ - Fallback implementation uses Unix epoch + millis()
513
+ - Ensure format: `1970-01-15T12:34:56Z` (must include date and Z suffix)
514
+ - Validate with regex: `^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$`
515
+
516
+ ### Debug Commands
517
+
518
+ ```cpp
519
+ // Enable OTA debug logging
520
+ mesh.setDebugMsgTypes(ERROR | STARTUP | OTA);
521
+
522
+ // Check OTA status
523
+ Serial.printf("Accepting OTA: %s\n", mesh.isAcceptingOTA() ? "YES" : "NO");
524
+
525
+ // Monitor memory during OTA
526
+ Serial.printf("Free heap: %d bytes\n", ESP.getFreeHeap());
527
+
528
+ // Validate MQTT message locally
529
+ #include <ArduinoJson.h>
530
+ DynamicJsonDocument doc(1024);
531
+ deserializeJson(doc, mqttPayload);
532
+ // Check required fields manually
533
+ bool valid = doc.containsKey("schema_version") &&
534
+ doc["schema_version"] == 1 &&
535
+ doc.containsKey("metrics");
536
+ ```
537
+
538
+ ---
539
+
540
+ ## References
541
+
542
+ - **painlessMesh OTA Plugin:** [src/painlessmesh/ota.hpp](../src/painlessmesh/ota.hpp)
543
+ - **MQTT Status Bridge:** [examples/bridge/mqtt_status_bridge.hpp](../examples/bridge/mqtt_status_bridge.hpp)
544
+ - **Alteriom MQTT Schema:** https://www.npmjs.com/package/@alteriom/mqtt-schema
545
+ - **Phase 2 Guide:** [PHASE2_GUIDE.md](PHASE2_GUIDE.md)
546
+ - **Schema Compliance:** [MQTT_SCHEMA_COMPLIANCE.md](MQTT_SCHEMA_COMPLIANCE.md)
547
+ - **Phase 2 Implementation:** [improvements/PHASE2_IMPLEMENTATION.md](improvements/PHASE2_IMPLEMENTATION.md)
548
+
549
+ ---
550
+
551
+ **Last Updated:** October 2024
552
+ **Schema Version:** v1
553
+ **painlessMesh Version:** 1.6.1+
554
+ **Phase:** 2 (Broadcast OTA + MQTT Status Bridge)