@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.
- package/CHANGELOG.md +380 -143
- package/LICENSE +674 -674
- package/README.md +477 -434
- package/RELEASE_GUIDE.md +504 -418
- package/docs/DOCUMENTATION_MIGRATION_PLAN.md +175 -175
- package/docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md +1062 -0
- package/docs/MESH_TOPOLOGY_GUIDE.md +992 -0
- package/docs/MESH_TOPOLOGY_PROGRESS.md +422 -0
- package/docs/MQTT_BRIDGE_COMMANDS.md +894 -0
- package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +324 -0
- package/docs/MQTT_COMMAND_SCHEMA_PROPOSAL.md +576 -0
- package/docs/MQTT_SCHEMA_COMPLIANCE.md +285 -0
- package/docs/MQTT_SCHEMA_PROPOSALS.md +446 -0
- package/docs/MQTT_SCHEMA_REVIEW.md +690 -0
- package/docs/OTA_COMMANDS_REFERENCE.md +554 -0
- package/docs/PHASE1_GUIDE.md +349 -0
- package/docs/PHASE2_GUIDE.md +543 -0
- package/docs/README.md +77 -70
- package/docs/SCHEMA_VALIDATION_CHECKLIST.md +222 -0
- package/docs/alteriom/overview.md +507 -507
- package/docs/api/core-api.md +606 -606
- package/docs/architecture/mesh-architecture.md +378 -378
- package/docs/architecture/plugin-system.md +516 -516
- package/docs/getting-started/first-mesh.md +409 -409
- package/docs/getting-started/installation.md +274 -274
- package/docs/getting-started/quickstart.md +157 -157
- package/docs/improvements/FEATURE_PROPOSALS.md +337 -0
- package/docs/improvements/PHASE1_IMPLEMENTATION.md +325 -0
- package/docs/improvements/PHASE2_IMPLEMENTATION.md +567 -0
- package/docs/improvements/README.md +86 -68
- package/docs/improvements/ota-and-status-enhancements.md +911 -0
- package/docs/improvements/ota-status-architecture-diagrams.md +658 -0
- package/docs/improvements/ota-status-quick-reference.md +284 -0
- package/docs/platformio-publishing.md +255 -0
- package/docs/platformio-setup-summary.md +121 -0
- package/docs/troubleshooting/common-issues.md +520 -520
- package/docs/troubleshooting/faq.md +472 -472
- package/docs/tutorials/basic-examples.md +717 -717
- package/docs/wiki/API-Reference.md +245 -245
- package/docs/wiki/Complete-Documentation.md +122 -122
- package/examples/alteriom/README.md +139 -81
- package/examples/alteriom/alteriom.ino +186 -185
- package/examples/alteriom/alteriom_sensor_package.hpp +240 -127
- package/examples/alteriom/platformio.ini +24 -24
- package/examples/alteriomImproved/alteriom_sensor_package.hpp +224 -0
- package/examples/{alteriom → alteriomImproved}/improved_sensor_node.ino +245 -245
- package/examples/alteriomImproved/platformio.ini +25 -0
- package/examples/alteriomPhase1/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomPhase1/phase1_features.ino +242 -0
- package/examples/alteriomPhase1/platformio.ini +25 -0
- package/examples/alteriomPhase2/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomPhase2/phase2_features.ino +186 -0
- package/examples/alteriomPhase2/platformio.ini +25 -0
- package/examples/{alteriom → alteriomSensorNode}/alteriom_sensor_node.ino +183 -183
- package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomSensorNode/platformio.ini +25 -0
- package/examples/basic/basic.ino +66 -66
- package/examples/basic/platformio.ini +25 -25
- package/examples/bridge/bridge.ino +51 -51
- package/examples/bridge/mesh_event_publisher.hpp +253 -0
- package/examples/bridge/mesh_topology_reporter.hpp +303 -0
- package/examples/bridge/mqtt_command_bridge.hpp +459 -0
- package/examples/bridge/mqtt_status_bridge.hpp +519 -0
- package/examples/bridge/platformio.ini +25 -25
- package/examples/echoNode/echoNode.ino +33 -33
- package/examples/echoNode/platformio.ini +25 -25
- package/examples/logClient/logClient.ino +109 -109
- package/examples/logClient/platformio.ini +25 -25
- package/examples/logServer/logServer.ino +81 -81
- package/examples/logServer/platformio.ini +25 -25
- package/examples/meshCommandNode/alteriom_sensor_package.hpp +235 -0
- package/examples/meshCommandNode/meshCommandNode.ino +263 -0
- package/examples/meshCommandNode/platformio.ini +25 -0
- package/examples/mqttBridge/mqttBridge.ino +118 -118
- package/examples/mqttBridge/platformio.ini +26 -26
- package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +235 -0
- package/examples/mqttCommandBridge/mesh_event_publisher.hpp +253 -0
- package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +303 -0
- package/examples/mqttCommandBridge/mqttCommandBridge.ino +252 -0
- package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +459 -0
- package/examples/mqttCommandBridge/platformio.ini +26 -0
- package/examples/mqttStatusBridge/mqttStatusBridge.ino +216 -0
- package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +522 -0
- package/examples/mqttStatusBridge/platformio.ini +26 -0
- package/examples/mqttTopologyTest/README.md +467 -0
- package/examples/mqttTopologyTest/mqttTopologyTest.ino +748 -0
- package/examples/mqttTopologyTest/platformio.ini +26 -0
- package/examples/namedMesh/namedMesh.ino +97 -97
- package/examples/namedMesh/platformio.ini +25 -25
- package/examples/otaReceiver/otaReceiver.ino +79 -79
- package/examples/otaReceiver/platformio.ini +25 -25
- package/examples/otaSender/otaSender.ino +160 -151
- package/examples/otaSender/platformio.ini +25 -25
- package/examples/startHere/platformio.ini +25 -25
- package/examples/startHere/startHere.ino +159 -159
- package/examples/webServer/platformio.ini +27 -27
- package/examples/webServer/webServer.ino +89 -89
- package/keywords.txt +48 -48
- package/library.json +55 -34
- package/library.properties +10 -10
- package/package.json +86 -78
- package/src/AlteriomPainlessMesh.h +97 -97
- package/src/arduino/wifi.hpp +365 -365
- package/src/boost/asynctcp.hpp +279 -279
- package/src/painlessMesh.h +70 -70
- package/src/painlessMeshSTA.cpp +236 -236
- package/src/painlessMeshSTA.h +58 -58
- package/src/painlessTaskOptions.h +4 -4
- package/src/painlessmesh/base64.hpp +111 -111
- package/src/painlessmesh/buffer.hpp +229 -229
- package/src/painlessmesh/callback.hpp +91 -91
- package/src/painlessmesh/configuration.hpp +77 -77
- package/src/painlessmesh/connection.hpp +192 -192
- package/src/painlessmesh/layout.hpp +188 -188
- package/src/painlessmesh/logger.hpp +158 -158
- package/src/painlessmesh/memory.hpp +119 -119
- package/src/painlessmesh/mesh.hpp +761 -560
- package/src/painlessmesh/metrics.hpp +322 -322
- package/src/painlessmesh/ntp.hpp +263 -263
- package/src/painlessmesh/ota.hpp +582 -553
- package/src/painlessmesh/plugin.hpp +188 -188
- package/src/painlessmesh/protocol.hpp +813 -813
- package/src/painlessmesh/router.hpp +322 -322
- package/src/painlessmesh/tcp.hpp +71 -71
- package/src/painlessmesh/validation.hpp +238 -238
- package/src/plugin/performance.hpp +214 -214
- package/src/plugin/remote.hpp +64 -64
- package/src/scheduler.cpp +10 -10
- package/src/wifi.cpp +2 -2
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
# Phase 2 Implementation Details
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document provides technical details on the Phase 2 implementation of broadcast OTA and MQTT status bridge features for painlessMesh.
|
|
6
|
+
|
|
7
|
+
**Phase 2 Features:**
|
|
8
|
+
1. **Broadcast OTA (Option 1A)** - True mesh-wide firmware distribution
|
|
9
|
+
2. **MQTT Status Bridge (Option 2E)** - Professional monitoring integration
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Feature 1: Broadcast OTA Implementation
|
|
14
|
+
|
|
15
|
+
### Architecture
|
|
16
|
+
|
|
17
|
+
The broadcast OTA feature extends the existing OTA plugin to support true mesh-wide broadcast distribution. Instead of each node requesting chunks individually (unicast), the root node broadcasts chunks once to all nodes simultaneously.
|
|
18
|
+
|
|
19
|
+
**Message Flow:**
|
|
20
|
+
```
|
|
21
|
+
Unicast Mode (Phase 1):
|
|
22
|
+
Root → Node1: Announce
|
|
23
|
+
Node1 → Root: DataRequest(chunk 0)
|
|
24
|
+
Root → Node1: Data(chunk 0)
|
|
25
|
+
Node1 → Root: DataRequest(chunk 1)
|
|
26
|
+
... repeated for each node and each chunk
|
|
27
|
+
|
|
28
|
+
Broadcast Mode (Phase 2):
|
|
29
|
+
Root → All: Broadcast Announce
|
|
30
|
+
Root → All: Broadcast Data(chunk 0)
|
|
31
|
+
Root → All: Broadcast Data(chunk 1)
|
|
32
|
+
... all nodes receive simultaneously
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Code Changes
|
|
36
|
+
|
|
37
|
+
#### 1. Data Routing Enhancement
|
|
38
|
+
|
|
39
|
+
**File:** `src/painlessmesh/ota.hpp`
|
|
40
|
+
|
|
41
|
+
**Change:** Modified `Data::replyTo()` to automatically set broadcast routing based on the `broadcasted` flag.
|
|
42
|
+
|
|
43
|
+
```cpp
|
|
44
|
+
static Data replyTo(const DataRequest& req, TSTRING data, size_t partNo) {
|
|
45
|
+
Data d;
|
|
46
|
+
// ... existing field initialization ...
|
|
47
|
+
|
|
48
|
+
// Phase 2: Set routing to BROADCAST for true broadcast mode
|
|
49
|
+
if (req.broadcasted) {
|
|
50
|
+
d.routing = router::BROADCAST;
|
|
51
|
+
}
|
|
52
|
+
return d;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Rationale:**
|
|
57
|
+
- The `Data` class inherits from `DataRequest`, which sets routing to `router::SINGLE` by default
|
|
58
|
+
- When `broadcasted=true`, we override routing to `router::BROADCAST`
|
|
59
|
+
- This ensures data chunks are broadcast to all nodes instead of unicast to requester
|
|
60
|
+
- Backward compatible: defaults to SINGLE routing when `broadcasted=false`
|
|
61
|
+
|
|
62
|
+
#### 2. Sender Callback Enhancement
|
|
63
|
+
|
|
64
|
+
**File:** `src/painlessmesh/ota.hpp`
|
|
65
|
+
|
|
66
|
+
**Change:** Updated sender callback to log broadcast operations.
|
|
67
|
+
|
|
68
|
+
```cpp
|
|
69
|
+
mesh.sendPackage(&reply);
|
|
70
|
+
if (pkg.broadcasted) {
|
|
71
|
+
Log(DEBUG, "OTA: Broadcasting chunk %d/%d\n", pkg.partNo, pkg.noPart);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Rationale:**
|
|
76
|
+
- Routing is now handled automatically by `Data::replyTo()`
|
|
77
|
+
- Added debug logging for broadcast mode visibility
|
|
78
|
+
- Single code path for both unicast and broadcast modes
|
|
79
|
+
|
|
80
|
+
### How It Works
|
|
81
|
+
|
|
82
|
+
#### Sender Side (Root Node)
|
|
83
|
+
|
|
84
|
+
1. **Announce Phase:**
|
|
85
|
+
- Root node calls `mesh.offerOTA(..., broadcasted=true)`
|
|
86
|
+
- Creates periodic task to broadcast `Announce` message
|
|
87
|
+
- Announce includes `broadcasted=true` flag
|
|
88
|
+
|
|
89
|
+
2. **Data Distribution Phase:**
|
|
90
|
+
- Root node receives `DataRequest` from any node (typically root itself)
|
|
91
|
+
- Loads firmware chunk from storage via callback
|
|
92
|
+
- Creates `Data` message with chunk content
|
|
93
|
+
- `Data::replyTo()` automatically sets routing to BROADCAST
|
|
94
|
+
- Broadcasts chunk to all nodes simultaneously
|
|
95
|
+
|
|
96
|
+
3. **Completion:**
|
|
97
|
+
- All nodes receive all chunks
|
|
98
|
+
- No individual acknowledgments required
|
|
99
|
+
- Root continues until all chunks sent
|
|
100
|
+
|
|
101
|
+
#### Receiver Side (All Nodes)
|
|
102
|
+
|
|
103
|
+
1. **Announce Reception:**
|
|
104
|
+
- Receives broadcast `Announce` message
|
|
105
|
+
- Checks if firmware matches role/hardware
|
|
106
|
+
- Checks if MD5 is different from current firmware
|
|
107
|
+
- If `broadcasted=true` and node is root: starts requesting chunks
|
|
108
|
+
- If `broadcasted=true` and node is not root: listens passively
|
|
109
|
+
|
|
110
|
+
2. **Data Reception:**
|
|
111
|
+
- Receives broadcast `Data` chunks
|
|
112
|
+
- Assembles chunks in sequence
|
|
113
|
+
- Handles out-of-order delivery automatically
|
|
114
|
+
- Writes to flash progressively
|
|
115
|
+
- Reboots when all chunks received
|
|
116
|
+
|
|
117
|
+
3. **Out-of-Sequence Handling:**
|
|
118
|
+
- If node misses chunks or receives out of order
|
|
119
|
+
- Existing code falls back to unicast mode
|
|
120
|
+
- Requests missing chunks directly from root
|
|
121
|
+
- Maintains reliability despite broadcast limitations
|
|
122
|
+
|
|
123
|
+
### Performance Analysis
|
|
124
|
+
|
|
125
|
+
**Network Traffic Comparison:**
|
|
126
|
+
|
|
127
|
+
For a mesh with N nodes and F firmware chunks:
|
|
128
|
+
|
|
129
|
+
| Mode | Transmissions | Example (50 nodes, 150 chunks) |
|
|
130
|
+
|------|--------------|--------------------------------|
|
|
131
|
+
| Unicast | N × F | 50 × 150 = 7,500 |
|
|
132
|
+
| Broadcast | F | 150 |
|
|
133
|
+
| Reduction | (N-1) / N × 100% | 98% |
|
|
134
|
+
|
|
135
|
+
**Memory Usage:**
|
|
136
|
+
- Per node: +2-5KB for chunk bitmap and assembly buffer
|
|
137
|
+
- Root node: No additional memory (reuses existing OTA buffers)
|
|
138
|
+
|
|
139
|
+
**Update Time:**
|
|
140
|
+
- Unicast: O(N × F) - Sequential per node
|
|
141
|
+
- Broadcast: O(F) - Parallel to all nodes
|
|
142
|
+
- Speedup: ~N times faster for large meshes
|
|
143
|
+
|
|
144
|
+
### Testing
|
|
145
|
+
|
|
146
|
+
**Test Coverage:**
|
|
147
|
+
- Existing OTA tests continue to pass
|
|
148
|
+
- Backward compatibility verified (unicast mode still works)
|
|
149
|
+
- No new test failures introduced
|
|
150
|
+
|
|
151
|
+
**Manual Testing Checklist:**
|
|
152
|
+
- [ ] Broadcast OTA to 2-5 node test mesh
|
|
153
|
+
- [ ] Broadcast OTA to 10+ node mesh
|
|
154
|
+
- [ ] Mixed mode: Some nodes broadcast, some unicast
|
|
155
|
+
- [ ] Out-of-sequence chunk handling
|
|
156
|
+
- [ ] Network congestion handling
|
|
157
|
+
- [ ] Failure recovery (node reboot during OTA)
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Feature 2: MQTT Status Bridge Implementation
|
|
162
|
+
|
|
163
|
+
### Architecture
|
|
164
|
+
|
|
165
|
+
The MQTT Status Bridge is a helper class that collects mesh status and publishes it to MQTT topics at configurable intervals.
|
|
166
|
+
|
|
167
|
+
**Design Pattern:**
|
|
168
|
+
- Composition pattern: Bridge wraps mesh and MQTT client
|
|
169
|
+
- Periodic task pattern: Uses mesh scheduler for timed publishing
|
|
170
|
+
- Observer pattern: Reacts to mesh state changes
|
|
171
|
+
|
|
172
|
+
**Component Diagram:**
|
|
173
|
+
```
|
|
174
|
+
┌─────────────────────┐
|
|
175
|
+
│ painlessMesh │
|
|
176
|
+
│ - Node list │
|
|
177
|
+
│ - Topology │
|
|
178
|
+
│ - Metrics │
|
|
179
|
+
└──────┬──────────────┘
|
|
180
|
+
│
|
|
181
|
+
↓ (reads)
|
|
182
|
+
┌──────────────────────┐
|
|
183
|
+
│ MqttStatusBridge │
|
|
184
|
+
│ - Collect status │
|
|
185
|
+
│ - Format JSON │
|
|
186
|
+
│ - Schedule publish │
|
|
187
|
+
└──────┬───────────────┘
|
|
188
|
+
│
|
|
189
|
+
↓ (publishes)
|
|
190
|
+
┌──────────────────────┐
|
|
191
|
+
│ MQTT Broker │
|
|
192
|
+
│ - mesh/status/* │
|
|
193
|
+
└──────────────────────┘
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Code Implementation
|
|
197
|
+
|
|
198
|
+
#### Class Structure
|
|
199
|
+
|
|
200
|
+
**File:** `examples/bridge/mqtt_status_bridge.hpp`
|
|
201
|
+
|
|
202
|
+
```cpp
|
|
203
|
+
class MqttStatusBridge {
|
|
204
|
+
private:
|
|
205
|
+
painlessMesh& mesh;
|
|
206
|
+
PubSubClient& mqttClient;
|
|
207
|
+
uint32_t publishInterval;
|
|
208
|
+
bool enableTopologyPublish;
|
|
209
|
+
bool enableMetricsPublish;
|
|
210
|
+
bool enableAlertsPublish;
|
|
211
|
+
bool enablePerNodePublish;
|
|
212
|
+
String topicPrefix;
|
|
213
|
+
Task* publishTask;
|
|
214
|
+
|
|
215
|
+
public:
|
|
216
|
+
MqttStatusBridge(painlessMesh& mesh, PubSubClient& mqttClient);
|
|
217
|
+
|
|
218
|
+
// Configuration
|
|
219
|
+
void setPublishInterval(uint32_t interval);
|
|
220
|
+
void setTopicPrefix(const String& prefix);
|
|
221
|
+
void enableTopology(bool enable);
|
|
222
|
+
void enableMetrics(bool enable);
|
|
223
|
+
void enableAlerts(bool enable);
|
|
224
|
+
void enablePerNode(bool enable);
|
|
225
|
+
|
|
226
|
+
// Control
|
|
227
|
+
void begin();
|
|
228
|
+
void stop();
|
|
229
|
+
void publishNow();
|
|
230
|
+
|
|
231
|
+
private:
|
|
232
|
+
void publishStatus();
|
|
233
|
+
void publishNodeList();
|
|
234
|
+
void publishTopology();
|
|
235
|
+
void publishMetrics();
|
|
236
|
+
void publishAlerts();
|
|
237
|
+
void publishPerNodeStatus();
|
|
238
|
+
};
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
#### Key Methods
|
|
242
|
+
|
|
243
|
+
**1. begin() - Start Publishing**
|
|
244
|
+
```cpp
|
|
245
|
+
void begin() {
|
|
246
|
+
publishTask = &mesh.addTask(
|
|
247
|
+
TASK_MILLISECOND * publishInterval,
|
|
248
|
+
TASK_FOREVER,
|
|
249
|
+
[this]() { this->publishStatus(); }
|
|
250
|
+
);
|
|
251
|
+
publishTask->enable();
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**2. publishStatus() - Main Publishing Logic**
|
|
256
|
+
```cpp
|
|
257
|
+
void publishStatus() {
|
|
258
|
+
if (!mqttClient.connected()) return;
|
|
259
|
+
|
|
260
|
+
publishNodeList();
|
|
261
|
+
if (enableTopologyPublish) publishTopology();
|
|
262
|
+
if (enableMetricsPublish) publishMetrics();
|
|
263
|
+
if (enableAlertsPublish) publishAlerts();
|
|
264
|
+
if (enablePerNodePublish) publishPerNodeStatus();
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**3. publishNodeList() - Node List JSON**
|
|
269
|
+
```cpp
|
|
270
|
+
void publishNodeList() {
|
|
271
|
+
auto nodes = mesh.getNodeList(true);
|
|
272
|
+
|
|
273
|
+
String payload = "{\"nodes\":[";
|
|
274
|
+
for (size_t i = 0; i < nodes.size(); i++) {
|
|
275
|
+
if (i > 0) payload += ",";
|
|
276
|
+
payload += String(nodes[i]);
|
|
277
|
+
}
|
|
278
|
+
payload += "],\"count\":";
|
|
279
|
+
payload += String(nodes.size());
|
|
280
|
+
payload += ",\"timestamp\":";
|
|
281
|
+
payload += String(millis());
|
|
282
|
+
payload += "}";
|
|
283
|
+
|
|
284
|
+
mqttClient.publish((topicPrefix + "nodes").c_str(), payload.c_str());
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**4. publishTopology() - Mesh Structure**
|
|
289
|
+
```cpp
|
|
290
|
+
void publishTopology() {
|
|
291
|
+
String topology = mesh.subConnectionJson(false);
|
|
292
|
+
mqttClient.publish((topicPrefix + "topology").c_str(), topology.c_str());
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**5. publishMetrics() - Performance Stats**
|
|
297
|
+
```cpp
|
|
298
|
+
void publishMetrics() {
|
|
299
|
+
String payload = "{";
|
|
300
|
+
payload += "\"nodeCount\":" + String(mesh.getNodeList(true).size());
|
|
301
|
+
payload += ",\"rootNodeId\":" + String(mesh.getNodeId());
|
|
302
|
+
payload += ",\"uptime\":" + String(millis() / 1000);
|
|
303
|
+
payload += ",\"freeHeap\":" + String(ESP.getFreeHeap());
|
|
304
|
+
payload += ",\"timestamp\":" + String(millis());
|
|
305
|
+
payload += "}";
|
|
306
|
+
|
|
307
|
+
mqttClient.publish((topicPrefix + "metrics").c_str(), payload.c_str());
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**6. publishAlerts() - Active Alerts**
|
|
312
|
+
```cpp
|
|
313
|
+
void publishAlerts() {
|
|
314
|
+
String payload = "{\"alerts\":[";
|
|
315
|
+
bool hasAlerts = false;
|
|
316
|
+
|
|
317
|
+
// Example: Low memory alert
|
|
318
|
+
if (ESP.getFreeHeap() < 10000) {
|
|
319
|
+
payload += "{\"type\":\"LOW_MEMORY\",\"severity\":\"critical\"}";
|
|
320
|
+
hasAlerts = true;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
payload += "],\"timestamp\":" + String(millis()) + "}";
|
|
324
|
+
mqttClient.publish((topicPrefix + "alerts").c_str(), payload.c_str());
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### MQTT Topic Schema
|
|
329
|
+
|
|
330
|
+
#### 1. mesh/status/nodes
|
|
331
|
+
```json
|
|
332
|
+
{
|
|
333
|
+
"nodes": [123456, 789012, 345678],
|
|
334
|
+
"count": 3,
|
|
335
|
+
"timestamp": 1234567890
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
#### 2. mesh/status/topology
|
|
340
|
+
```json
|
|
341
|
+
{
|
|
342
|
+
"nodeId": 123456,
|
|
343
|
+
"subs": [
|
|
344
|
+
{"nodeId": 789012, "subs": []},
|
|
345
|
+
{"nodeId": 345678, "subs": []}
|
|
346
|
+
]
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
#### 3. mesh/status/metrics
|
|
351
|
+
```json
|
|
352
|
+
{
|
|
353
|
+
"nodeCount": 3,
|
|
354
|
+
"rootNodeId": 123456,
|
|
355
|
+
"uptime": 3600,
|
|
356
|
+
"freeHeap": 45000,
|
|
357
|
+
"freeHeapKB": 43,
|
|
358
|
+
"timestamp": 1234567890
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
#### 4. mesh/status/alerts
|
|
363
|
+
```json
|
|
364
|
+
{
|
|
365
|
+
"alerts": [
|
|
366
|
+
{
|
|
367
|
+
"type": "LOW_MEMORY",
|
|
368
|
+
"severity": "critical",
|
|
369
|
+
"message": "Free heap below 10KB"
|
|
370
|
+
}
|
|
371
|
+
],
|
|
372
|
+
"timestamp": 1234567890
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
#### 5. mesh/status/node/{nodeId}
|
|
377
|
+
```json
|
|
378
|
+
{
|
|
379
|
+
"nodeId": 123456,
|
|
380
|
+
"connected": true,
|
|
381
|
+
"freeHeap": 45000,
|
|
382
|
+
"timestamp": 1234567890
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Performance Considerations
|
|
387
|
+
|
|
388
|
+
**Memory Usage:**
|
|
389
|
+
- Bridge object: ~200 bytes
|
|
390
|
+
- JSON formatting buffers: ~2-5KB temporary
|
|
391
|
+
- Total overhead: +5-8KB on root node
|
|
392
|
+
|
|
393
|
+
**MQTT Traffic:**
|
|
394
|
+
| Feature | Size/Publish | Recommended Interval |
|
|
395
|
+
|---------|-------------|---------------------|
|
|
396
|
+
| Node List | ~200 bytes | 30-60s |
|
|
397
|
+
| Topology | 1-5KB | 60-120s |
|
|
398
|
+
| Metrics | ~300 bytes | 30-60s |
|
|
399
|
+
| Alerts | ~400 bytes | 30-60s |
|
|
400
|
+
| Per-node (50 nodes) | ~7.5KB | 120-300s |
|
|
401
|
+
|
|
402
|
+
**Scalability:**
|
|
403
|
+
- Small mesh (1-10 nodes): All features enabled, 30s interval
|
|
404
|
+
- Medium mesh (10-50 nodes): Disable per-node, 60s interval
|
|
405
|
+
- Large mesh (50+ nodes): Metrics/alerts only, 120s interval
|
|
406
|
+
|
|
407
|
+
### Integration Points
|
|
408
|
+
|
|
409
|
+
**Grafana:**
|
|
410
|
+
- Use MQTT datasource plugin
|
|
411
|
+
- Query topics for time-series data
|
|
412
|
+
- Create dashboards for node count, memory, topology
|
|
413
|
+
|
|
414
|
+
**InfluxDB:**
|
|
415
|
+
- Use Telegraf MQTT consumer
|
|
416
|
+
- Parse JSON payloads
|
|
417
|
+
- Store time-series data
|
|
418
|
+
|
|
419
|
+
**Prometheus:**
|
|
420
|
+
- Use MQTT exporter
|
|
421
|
+
- Convert MQTT messages to Prometheus metrics
|
|
422
|
+
- Scrape metrics endpoint
|
|
423
|
+
|
|
424
|
+
**Home Assistant:**
|
|
425
|
+
- Use MQTT sensor integration
|
|
426
|
+
- Create sensors for each metric
|
|
427
|
+
- Build automations based on alerts
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Backward Compatibility
|
|
432
|
+
|
|
433
|
+
### Breaking Changes
|
|
434
|
+
**None.** Phase 2 is fully backward compatible.
|
|
435
|
+
|
|
436
|
+
### Compatibility Matrix
|
|
437
|
+
|
|
438
|
+
| Feature | Phase 1 | Phase 2 | Compatible? |
|
|
439
|
+
|---------|---------|---------|-------------|
|
|
440
|
+
| Unicast OTA | ✅ | ✅ | ✅ Yes |
|
|
441
|
+
| Compressed OTA | ✅ | ✅ | ✅ Yes |
|
|
442
|
+
| Broadcast OTA | ❌ | ✅ | ✅ Yes (optional) |
|
|
443
|
+
| Enhanced Status | ✅ | ✅ | ✅ Yes |
|
|
444
|
+
| MQTT Bridge | ❌ | ✅ | ✅ Yes (optional) |
|
|
445
|
+
|
|
446
|
+
### Migration Path
|
|
447
|
+
|
|
448
|
+
**No code changes required** to maintain Phase 1 behavior:
|
|
449
|
+
```cpp
|
|
450
|
+
// This continues to work exactly as in Phase 1
|
|
451
|
+
mesh.offerOTA(role, hardware, md5, parts, false, false, true);
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
**Opt-in to Phase 2 features:**
|
|
455
|
+
```cpp
|
|
456
|
+
// Enable broadcast by adding one parameter
|
|
457
|
+
mesh.offerOTA(role, hardware, md5, parts, false, true, true);
|
|
458
|
+
// ^^^^
|
|
459
|
+
|
|
460
|
+
// Enable MQTT monitoring by including header
|
|
461
|
+
#include "examples/bridge/mqtt_status_bridge.hpp"
|
|
462
|
+
MqttStatusBridge bridge(mesh, mqttClient);
|
|
463
|
+
bridge.begin();
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
## Testing Strategy
|
|
469
|
+
|
|
470
|
+
### Unit Tests
|
|
471
|
+
- [x] Existing tests continue to pass (80 assertions)
|
|
472
|
+
- [ ] TODO: Add specific broadcast OTA tests
|
|
473
|
+
- [ ] TODO: Add MQTT bridge unit tests
|
|
474
|
+
|
|
475
|
+
### Integration Tests
|
|
476
|
+
- [ ] Test broadcast OTA with 2 nodes
|
|
477
|
+
- [ ] Test broadcast OTA with 10+ nodes
|
|
478
|
+
- [ ] Test MQTT publishing to real broker
|
|
479
|
+
- [ ] Test MQTT with Grafana integration
|
|
480
|
+
- [ ] Test mixed mode (broadcast + unicast nodes)
|
|
481
|
+
|
|
482
|
+
### Performance Tests
|
|
483
|
+
- [ ] Measure network traffic reduction
|
|
484
|
+
- [ ] Measure update time improvement
|
|
485
|
+
- [ ] Measure memory usage
|
|
486
|
+
- [ ] Measure MQTT traffic volume
|
|
487
|
+
- [ ] Test with 50+ node mesh
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## Known Limitations
|
|
492
|
+
|
|
493
|
+
### Broadcast OTA
|
|
494
|
+
|
|
495
|
+
1. **No per-node targeting:** All nodes receive all chunks. Cannot target specific nodes.
|
|
496
|
+
- **Workaround:** Use role/hardware filtering in Announce
|
|
497
|
+
|
|
498
|
+
2. **Network reliability:** Broadcast packets may be dropped in congested networks.
|
|
499
|
+
- **Mitigation:** Out-of-sequence handler falls back to unicast
|
|
500
|
+
|
|
501
|
+
3. **Memory overhead:** Each node needs buffer for chunk assembly (+2-5KB)
|
|
502
|
+
- **Impact:** May be significant for ESP8266 with limited RAM
|
|
503
|
+
|
|
504
|
+
### MQTT Status Bridge
|
|
505
|
+
|
|
506
|
+
1. **Single point of failure:** Bridge node must remain online
|
|
507
|
+
- **Mitigation:** Use reliable root node hardware
|
|
508
|
+
|
|
509
|
+
2. **External network required:** Needs WiFi connection to MQTT broker
|
|
510
|
+
- **Impact:** Not suitable for pure mesh-only deployments
|
|
511
|
+
|
|
512
|
+
3. **MQTT broker dependency:** Requires external MQTT infrastructure
|
|
513
|
+
- **Mitigation:** Use public MQTT brokers for testing
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
517
|
+
## Future Enhancements
|
|
518
|
+
|
|
519
|
+
### Phase 3 Candidates
|
|
520
|
+
|
|
521
|
+
1. **Progressive Rollout OTA (Option 1B)**
|
|
522
|
+
- Phased firmware distribution
|
|
523
|
+
- Health monitoring between phases
|
|
524
|
+
- Automatic rollback on failures
|
|
525
|
+
|
|
526
|
+
2. **Real-time Telemetry Streams (Option 2C)**
|
|
527
|
+
- Continuous metrics streaming
|
|
528
|
+
- Anomaly detection
|
|
529
|
+
- Predictive alerting
|
|
530
|
+
|
|
531
|
+
3. **Advanced Alert System**
|
|
532
|
+
- Custom alert rules
|
|
533
|
+
- Alert escalation
|
|
534
|
+
- Integration with notification services
|
|
535
|
+
|
|
536
|
+
### Potential Improvements
|
|
537
|
+
|
|
538
|
+
1. **Chunk Bitmap Tracking**
|
|
539
|
+
- Track received chunks explicitly
|
|
540
|
+
- Request specific missing chunks
|
|
541
|
+
- Improve reliability in lossy networks
|
|
542
|
+
|
|
543
|
+
2. **Rate Limiting**
|
|
544
|
+
- Adaptive broadcast rate based on congestion
|
|
545
|
+
- Prevent mesh saturation
|
|
546
|
+
- QoS-aware transmission
|
|
547
|
+
|
|
548
|
+
3. **MQTT Bridge Enhancements**
|
|
549
|
+
- Bidirectional command handling
|
|
550
|
+
- OTA trigger via MQTT
|
|
551
|
+
- Remote configuration updates
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## References
|
|
556
|
+
|
|
557
|
+
- [PHASE2_GUIDE.md](../PHASE2_GUIDE.md) - User documentation
|
|
558
|
+
- [FEATURE_PROPOSALS.md](FEATURE_PROPOSALS.md) - Original feature proposals
|
|
559
|
+
- [phase2_features.ino](../../examples/alteriom/phase2_features.ino) - Example code
|
|
560
|
+
- [mqtt_status_bridge.hpp](../../examples/bridge/mqtt_status_bridge.hpp) - Bridge implementation
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
**Document Version:** 1.0
|
|
565
|
+
**Last Updated:** December 2024
|
|
566
|
+
**Authors:** Alteriom Development Team
|
|
567
|
+
**Status:** ✅ Implementation Complete
|