@alteriom/painlessmesh 1.7.8 → 1.8.0

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 (59) hide show
  1. package/CHANGELOG.md +139 -3
  2. package/README.md +114 -4
  3. package/RELEASE_GUIDE.md +57 -8
  4. package/docs/BRIDGE_FAILOVER.md +512 -0
  5. package/docs/BRIDGE_HEALTH_MONITORING.md +293 -0
  6. package/docs/CREATE_MISSING_RELEASES.md +321 -0
  7. package/docs/README.md +2 -1
  8. package/docs/RELEASE_AGENT_SUMMARY.md +386 -0
  9. package/docs/releases/RELEASE_SUMMARY_v1.7.8.md +523 -0
  10. package/docs/releases/RELEASE_SUMMARY_v1.7.9.md +542 -0
  11. package/docs/troubleshooting/ESP32_C6_COMPATIBILITY.md +157 -0
  12. package/docs/troubleshooting/common-issues.md +28 -0
  13. package/examples/alteriom/alteriom_sensor_package.hpp +233 -1
  14. package/examples/alteriom/platformio.ini +1 -1
  15. package/examples/alteriomImproved/platformio.ini +1 -1
  16. package/examples/alteriomMetricsHealth/metrics_health_node.ino +18 -7
  17. package/examples/alteriomMetricsHealth/platformio.ini +1 -1
  18. package/examples/alteriomPhase1/platformio.ini +1 -1
  19. package/examples/alteriomPhase2/platformio.ini +1 -1
  20. package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +1014 -11
  21. package/examples/alteriomSensorNode/platformio.ini +1 -1
  22. package/examples/basic/basic.ino +6 -2
  23. package/examples/basic/platformio.ini +1 -1
  24. package/examples/bridge/alteriom_sensor_package.hpp +1170 -0
  25. package/examples/bridge/bridge.ino +44 -23
  26. package/examples/bridge/bridge_health_monitoring_example.ino +188 -0
  27. package/examples/bridge/enhanced_mqtt_bridge.hpp +1 -1
  28. package/examples/bridge/mqtt_command_bridge.hpp +2 -2
  29. package/examples/bridge/platformio.ini +2 -1
  30. package/examples/bridgeAwareSensorNode/alteriom_sensor_package.hpp +1227 -0
  31. package/examples/bridgeAwareSensorNode/bridgeAwareSensorNode.ino +343 -0
  32. package/examples/bridgeAwareSensorNode/platformio.ini +26 -0
  33. package/examples/bridge_failover/README.md +358 -0
  34. package/examples/bridge_failover/bridge_failover.ino +180 -0
  35. package/examples/bridge_failover/platformio.ini +27 -0
  36. package/examples/diagnosticsExample/diagnosticsExample.ino +171 -0
  37. package/examples/diagnosticsExample/platformio.ini +26 -0
  38. package/examples/echoNode/platformio.ini +1 -1
  39. package/examples/logClient/platformio.ini +1 -1
  40. package/examples/logServer/platformio.ini +1 -1
  41. package/examples/mqttStatusBridge/platformio.ini +1 -1
  42. package/examples/namedMesh/platformio.ini +1 -1
  43. package/examples/ntpTimeSyncBridge/alteriom_sensor_package.hpp +1383 -0
  44. package/examples/ntpTimeSyncBridge/ntpTimeSyncBridge.ino +81 -0
  45. package/examples/ntpTimeSyncNode/alteriom_sensor_package.hpp +1383 -0
  46. package/examples/ntpTimeSyncNode/ntpTimeSyncNode.ino +109 -0
  47. package/examples/otaReceiver/platformio.ini +1 -1
  48. package/examples/rtcIntegration/README.md +235 -0
  49. package/examples/rtcIntegration/rtcIntegration.ino +196 -0
  50. package/examples/startHere/platformio.ini +1 -1
  51. package/examples/webServer/platformio.ini +1 -1
  52. package/library.json +93 -53
  53. package/library.properties +1 -1
  54. package/package.json +2 -2
  55. package/src/arduino/wifi.hpp +581 -0
  56. package/src/painlessMeshSTA.cpp +68 -0
  57. package/src/painlessMeshSTA.h +3 -0
  58. package/src/painlessmesh/mesh.hpp +1127 -4
  59. package/src/painlessmesh/rtc.hpp +203 -0
@@ -0,0 +1,343 @@
1
+ //************************************************************
2
+ // Bridge-Aware Sensor Node Example
3
+ //
4
+ // This example demonstrates how to use the bridge status
5
+ // callback feature to implement intelligent message queueing.
6
+ //
7
+ // Features:
8
+ // - Monitors bridge Internet connectivity status
9
+ // - Queues critical messages when Internet is unavailable
10
+ // - Automatically sends queued messages when Internet returns
11
+ // - Implements failover logic for multiple bridges
12
+ //
13
+ // Use case: Fish farm monitoring system that needs to ensure
14
+ // critical alarms are delivered even during Internet outages
15
+ //************************************************************
16
+
17
+ #include "painlessTaskOptions.h" // Must be first to configure TaskScheduler
18
+ #include <TaskScheduler.h> // Required for LDF to find TaskScheduler dependency
19
+ #include "alteriom_sensor_package.hpp"
20
+ #include "painlessMesh.h"
21
+
22
+ #define MESH_PREFIX "AlteriomMesh"
23
+ #define MESH_PASSWORD "somethingSneaky"
24
+ #define MESH_PORT 5555
25
+
26
+ Scheduler userScheduler;
27
+ painlessMesh mesh;
28
+
29
+ // Alteriom package handlers
30
+ using namespace alteriom;
31
+
32
+ // Message queue for offline mode
33
+ struct QueuedMessage {
34
+ uint32_t timestamp;
35
+ bool isCritical;
36
+ SensorPackage data;
37
+ };
38
+
39
+ std::vector<QueuedMessage> messageQueue;
40
+ const size_t MAX_QUEUE_SIZE = 100; // Prevent memory overflow
41
+
42
+ // Bridge connectivity tracking
43
+ bool internetAvailable = false;
44
+ uint32_t primaryBridgeId = 0;
45
+
46
+ // Simulation variables
47
+ float currentTemperature = 25.0;
48
+ float currentOxygenLevel = 7.5; // mg/L - critical threshold is 5.0
49
+
50
+ // Function prototypes
51
+ void sendSensorData();
52
+ void handleIncomingPackage(uint32_t from, String& msg);
53
+ void bridgeStatusCallback(uint32_t bridgeNodeId, bool hasInternet);
54
+ void checkCriticalConditions();
55
+ void flushMessageQueue();
56
+ void queueMessage(const SensorPackage& data, bool isCritical);
57
+
58
+ Task taskSendSensorData(30000, TASK_FOREVER, &sendSensorData);
59
+ Task taskCheckCritical(5000, TASK_FOREVER, &checkCriticalConditions);
60
+
61
+ void setup() {
62
+ Serial.begin(115200);
63
+
64
+ // Initialize mesh
65
+ mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
66
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
67
+
68
+ // Setup callbacks
69
+ mesh.onReceive(&handleIncomingPackage);
70
+ mesh.onBridgeStatusChanged(&bridgeStatusCallback);
71
+
72
+ mesh.onNewConnection([](uint32_t nodeId) {
73
+ Serial.printf("āœ“ New connection: %u\n", nodeId);
74
+ });
75
+
76
+ mesh.onChangedConnections([]() {
77
+ Serial.println("ℹ Mesh connections changed");
78
+
79
+ // Check if we have a primary bridge
80
+ auto primaryBridge = mesh.getPrimaryBridge();
81
+ if (primaryBridge) {
82
+ Serial.printf(" Primary bridge: %u (RSSI: %d dBm, Internet: %s)\n",
83
+ primaryBridge->nodeId,
84
+ primaryBridge->routerRSSI,
85
+ primaryBridge->internetConnected ? "Yes" : "No");
86
+ } else {
87
+ Serial.println(" ⚠ No healthy bridges available");
88
+ }
89
+ });
90
+
91
+ // Add tasks
92
+ userScheduler.addTask(taskSendSensorData);
93
+ taskSendSensorData.enable();
94
+
95
+ userScheduler.addTask(taskCheckCritical);
96
+ taskCheckCritical.enable();
97
+
98
+ Serial.println("═══════════════════════════════════════════");
99
+ Serial.println(" Bridge-Aware Sensor Node");
100
+ Serial.println(" Fish Farm Monitoring System");
101
+ Serial.println("═══════════════════════════════════════════");
102
+ Serial.printf(" Node ID: %u\n", mesh.getNodeId());
103
+ Serial.println(" Monitoring: Temperature, Dissolved Oxygen");
104
+ Serial.println(" Critical Oā‚‚ threshold: 5.0 mg/L");
105
+ Serial.println("═══════════════════════════════════════════\n");
106
+ }
107
+
108
+ void loop() {
109
+ mesh.update();
110
+
111
+ // Simulate sensor drift
112
+ static uint32_t lastSimUpdate = 0;
113
+ if (millis() - lastSimUpdate > 10000) {
114
+ // Randomly vary oxygen level (can go critical)
115
+ currentOxygenLevel += random(-20, 15) / 10.0;
116
+ currentOxygenLevel = constrain(currentOxygenLevel, 3.0, 9.0);
117
+
118
+ currentTemperature += random(-10, 10) / 10.0;
119
+ currentTemperature = constrain(currentTemperature, 20.0, 30.0);
120
+
121
+ lastSimUpdate = millis();
122
+ }
123
+ }
124
+
125
+ void sendSensorData() {
126
+ // Create sensor package
127
+ SensorPackage sensorData;
128
+ sensorData.from = mesh.getNodeId();
129
+ sensorData.sensorId = mesh.getNodeId();
130
+ sensorData.timestamp = mesh.getNodeTime();
131
+ sensorData.temperature = currentTemperature;
132
+ sensorData.humidity = 65.0 + random(-50, 50) / 10.0; // Not critical for fish farm
133
+ sensorData.pressure = currentOxygenLevel; // Abuse pressure field for Oā‚‚ level
134
+ sensorData.batteryLevel = 85 + random(-10, 5);
135
+
136
+ // Determine if this is critical data (low oxygen)
137
+ bool isCritical = (currentOxygenLevel < 5.5); // Early warning threshold
138
+
139
+ if (internetAvailable) {
140
+ // Internet available - send immediately
141
+ JsonDocument doc;
142
+ JsonObject obj = doc.to<JsonObject>();
143
+ sensorData.addTo(std::move(obj));
144
+
145
+ String msg;
146
+ serializeJson(doc, msg);
147
+ mesh.sendBroadcast(msg);
148
+
149
+ Serial.printf("šŸ“¤ Sent: T=%.1f°C, Oā‚‚=%.1f mg/L, Bat=%d%% %s\n",
150
+ sensorData.temperature,
151
+ currentOxygenLevel,
152
+ sensorData.batteryLevel,
153
+ isCritical ? "⚠ CRITICAL" : "");
154
+ } else {
155
+ // Internet offline - queue message
156
+ queueMessage(sensorData, isCritical);
157
+
158
+ Serial.printf("šŸ’¾ Queued: T=%.1f°C, Oā‚‚=%.1f mg/L %s [Queue: %d/%d]\n",
159
+ sensorData.temperature,
160
+ currentOxygenLevel,
161
+ isCritical ? "⚠ CRITICAL" : "",
162
+ messageQueue.size(),
163
+ MAX_QUEUE_SIZE);
164
+ }
165
+ }
166
+
167
+ void checkCriticalConditions() {
168
+ // Check for critical low oxygen
169
+ if (currentOxygenLevel < 5.0) {
170
+ Serial.printf("🚨 CRITICAL ALARM: Low Oxygen = %.1f mg/L!\n", currentOxygenLevel);
171
+
172
+ // Create critical alarm package
173
+ SensorPackage alarm;
174
+ alarm.from = mesh.getNodeId();
175
+ alarm.sensorId = mesh.getNodeId();
176
+ alarm.timestamp = mesh.getNodeTime();
177
+ alarm.temperature = currentTemperature;
178
+ alarm.pressure = currentOxygenLevel;
179
+ alarm.deviceStatus = 0xFF; // Critical alarm flag
180
+ alarm.batteryLevel = 85;
181
+
182
+ if (internetAvailable) {
183
+ // Send immediately
184
+ JsonDocument doc;
185
+ JsonObject obj = doc.to<JsonObject>();
186
+ alarm.addTo(std::move(obj));
187
+
188
+ String msg;
189
+ serializeJson(doc, msg);
190
+ mesh.sendBroadcast(msg);
191
+ Serial.println(" ↪ Critical alarm sent immediately");
192
+ } else {
193
+ // Queue with high priority
194
+ queueMessage(alarm, true);
195
+ Serial.printf(" ↪ Critical alarm queued [Queue: %d/%d]\n",
196
+ messageQueue.size(), MAX_QUEUE_SIZE);
197
+ }
198
+ }
199
+ }
200
+
201
+ void queueMessage(const SensorPackage& data, bool isCritical) {
202
+ if (messageQueue.size() >= MAX_QUEUE_SIZE) {
203
+ Serial.println("⚠ Queue full - dropping oldest message");
204
+ messageQueue.erase(messageQueue.begin());
205
+ }
206
+
207
+ QueuedMessage qMsg;
208
+ qMsg.timestamp = millis();
209
+ qMsg.isCritical = isCritical;
210
+ qMsg.data = data;
211
+
212
+ messageQueue.push_back(qMsg);
213
+ }
214
+
215
+ void flushMessageQueue() {
216
+ if (messageQueue.empty()) {
217
+ return;
218
+ }
219
+
220
+ Serial.printf("\nšŸ“¤ Flushing message queue (%d messages)...\n", messageQueue.size());
221
+
222
+ size_t sentCount = 0;
223
+ size_t criticalCount = 0;
224
+
225
+ for (const auto& qMsg : messageQueue) {
226
+ JsonDocument doc;
227
+ JsonObject obj = doc.to<JsonObject>();
228
+ qMsg.data.addTo(std::move(obj));
229
+
230
+ String msg;
231
+ serializeJson(doc, msg);
232
+ mesh.sendBroadcast(msg);
233
+
234
+ sentCount++;
235
+ if (qMsg.isCritical) criticalCount++;
236
+
237
+ delay(100); // Small delay to avoid flooding
238
+ }
239
+
240
+ messageQueue.clear();
241
+
242
+ Serial.printf("āœ“ Queue flushed: %d messages (%d critical)\n\n",
243
+ sentCount, criticalCount);
244
+ }
245
+
246
+ void bridgeStatusCallback(uint32_t bridgeNodeId, bool hasInternet) {
247
+ bool wasAvailable = internetAvailable;
248
+ internetAvailable = hasInternet;
249
+ primaryBridgeId = bridgeNodeId;
250
+
251
+ Serial.println("\n════════════════════════════════════════════");
252
+ if (hasInternet) {
253
+ Serial.printf("āœ“ Bridge %u: Internet CONNECTED\n", bridgeNodeId);
254
+
255
+ // Get bridge details
256
+ auto bridges = mesh.getBridges();
257
+ for (const auto& bridge : bridges) {
258
+ if (bridge.nodeId == bridgeNodeId) {
259
+ Serial.printf(" Router: %s (RSSI: %d dBm, Ch: %d)\n",
260
+ bridge.gatewayIP.c_str(),
261
+ bridge.routerRSSI,
262
+ bridge.routerChannel);
263
+ Serial.printf(" Bridge uptime: %u seconds\n", bridge.uptime / 1000);
264
+ }
265
+ }
266
+
267
+ // If Internet was restored, flush queued messages
268
+ if (!wasAvailable) {
269
+ Serial.println(" → Internet restored - processing queue");
270
+ flushMessageQueue();
271
+ }
272
+ } else {
273
+ Serial.printf("⚠ Bridge %u: Internet OFFLINE\n", bridgeNodeId);
274
+ Serial.println(" → Entering offline mode");
275
+ Serial.println(" → Critical alarms will be queued");
276
+ }
277
+ Serial.println("════════════════════════════════════════════\n");
278
+
279
+ // Show overall mesh status
280
+ if (mesh.hasInternetConnection()) {
281
+ Serial.println("āœ“ Mesh has Internet connectivity");
282
+ } else {
283
+ Serial.println("⚠ No Internet connectivity in mesh");
284
+ }
285
+
286
+ // Show all known bridges
287
+ auto bridges = mesh.getBridges();
288
+ if (!bridges.empty()) {
289
+ Serial.printf("Known bridges: %d\n", bridges.size());
290
+ for (const auto& bridge : bridges) {
291
+ Serial.printf(" - Bridge %u: %s (RSSI: %d dBm)\n",
292
+ bridge.nodeId,
293
+ bridge.internetConnected ? "Online" : "Offline",
294
+ bridge.routerRSSI);
295
+ }
296
+ }
297
+ Serial.println();
298
+ }
299
+
300
+ void handleIncomingPackage(uint32_t from, String& msg) {
301
+ // Parse the JSON message
302
+ JsonDocument doc;
303
+ deserializeJson(doc, msg);
304
+ JsonObject obj = doc.as<JsonObject>();
305
+
306
+ // Check message type
307
+ uint8_t msgType = obj["type"];
308
+
309
+ switch (msgType) {
310
+ case 200: // SensorPackage
311
+ {
312
+ SensorPackage receivedSensor(obj);
313
+ Serial.printf("šŸ“„ Sensor from %u: T=%.1f°C, Oā‚‚=%.1f mg/L\n",
314
+ receivedSensor.from,
315
+ receivedSensor.temperature,
316
+ receivedSensor.pressure); // Using pressure for Oā‚‚
317
+ } break;
318
+
319
+ case 400: // CommandPackage
320
+ {
321
+ CommandPackage receivedCmd(obj);
322
+ if (receivedCmd.dest == mesh.getNodeId()) {
323
+ Serial.printf("šŸ“„ Command %d received\n", receivedCmd.command);
324
+
325
+ // Handle commands (e.g., request status, change thresholds)
326
+ if (receivedCmd.command == 3) {
327
+ // Data request - send immediately even if offline
328
+ sendSensorData();
329
+ }
330
+ }
331
+ } break;
332
+
333
+ case 610: // BridgeStatusPackage
334
+ // Handled automatically by mesh's internal callback
335
+ // But we can log that we received it
336
+ Serial.printf("šŸ“” Bridge status update from %u\n", from);
337
+ break;
338
+
339
+ default:
340
+ // Unknown message type
341
+ break;
342
+ }
343
+ }
@@ -0,0 +1,26 @@
1
+ [platformio]
2
+ src_dir = .
3
+
4
+ [env]
5
+ lib_ldf_mode = deep+
6
+ lib_deps =
7
+ bblanchon/ArduinoJson
8
+ arkhipenko/TaskScheduler
9
+
10
+ [env:esp8266]
11
+ platform = espressif8266
12
+ board = nodemcuv2
13
+ framework = arduino
14
+ lib_extra_dirs = ../../ ; Load the local copy of painlessmesh. For your own example add painlessmesh to the lib_deps
15
+ lib_deps =
16
+ ${env.lib_deps} ; Inherit common dependencies
17
+ esp32async/ESPAsyncTCP@^2.0.0 ; Only for ESP8266
18
+
19
+ [env:esp32]
20
+ platform = espressif32
21
+ board = esp32dev
22
+ framework = arduino
23
+ lib_extra_dirs = ../../ ; Load the local copy of painlessmesh. For your own example add painlessmesh to the lib_deps
24
+ lib_deps =
25
+ ${env.lib_deps} ; Inherit common dependencies
26
+ esp32async/AsyncTCP