@alteriom/painlessmesh 1.8.2 → 1.8.3

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 (49) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +62 -11
  3. package/RELEASE_GUIDE.md +57 -16
  4. package/docs/ARDUINO_LIBRARY_MANAGER_SUBMISSION.md +331 -0
  5. package/docs/features/DIAGNOSTICS_API.md +534 -0
  6. package/docs/getting-started/arduino-manual-install.md +313 -0
  7. package/docs/implementation/BRIDGE_ARCHITECTURE_IMPLEMENTATION.md +340 -0
  8. package/docs/implementation/BRIDGE_HEALTH_MONITORING_IMPLEMENTATION.md +213 -0
  9. package/docs/implementation/BRIDGE_STATUS_FEATURE.md +635 -0
  10. package/docs/implementation/DIAGNOSTICS_API_IMPLEMENTATION.md +232 -0
  11. package/docs/implementation/IMPLEMENTATION_COMPLETE.md +228 -0
  12. package/docs/implementation/IMPLEMENTATION_NTP_TIME_SYNC.md +325 -0
  13. package/docs/implementation/IMPLEMENTATION_SUMMARY.md +316 -0
  14. package/docs/implementation/MESSAGE_QUEUE_IMPLEMENTATION.md +405 -0
  15. package/docs/implementation/MULTI_BRIDGE_IMPLEMENTATION.md +520 -0
  16. package/docs/implementation/NTP_TIME_SYNC_FEATURE.md +392 -0
  17. package/docs/internal/CUSTOM_AGENT_ANALYSIS.md +391 -0
  18. package/docs/internal/ISSUE_65_VERIFICATION.md +947 -0
  19. package/docs/internal/ISSUE_66_CLOSURE.md +249 -0
  20. package/docs/internal/ISSUE_66_STATUS.md +316 -0
  21. package/docs/internal/PR_SUMMARY.md +315 -0
  22. package/docs/internal/REVIEW_SUMMARY.md +332 -0
  23. package/docs/releases/PUBLISH_v1.8.0_INSTRUCTIONS.md +163 -0
  24. package/docs/releases/QUICK_START_RELEASES.md +113 -0
  25. package/docs/releases/RELEASE_CHECKLIST_v1.8.0.md +331 -0
  26. package/docs/releases/RELEASE_CHECKLIST_v1.8.2.md +309 -0
  27. package/docs/releases/RELEASE_NOTES_v1.8.0.md +685 -0
  28. package/docs/releases/RELEASE_NOTES_v1.8.1.md +221 -0
  29. package/docs/releases/RELEASE_NOTES_v1.8.2.md +421 -0
  30. package/docs/releases/RELEASE_NOTES_v1.8.3.md +292 -0
  31. package/docs/troubleshooting/ARDUINO_IDE_VERSION_FIX_SUMMARY.md +229 -0
  32. package/docs/troubleshooting/ARDUINO_LIBRARY_NAME_FIX.md +197 -0
  33. package/docs/troubleshooting/NPM_PUBLISHING_ISSUE_SUMMARY.md +110 -0
  34. package/docs/troubleshooting/station-reconnection-issues.md +172 -0
  35. package/examples/priority/README.md +274 -0
  36. package/examples/priority/priority_basic_example.ino +115 -0
  37. package/examples/priority/priority_with_queue.ino +249 -0
  38. package/examples/routing_demo/README.md +172 -0
  39. package/examples/routing_demo/routing_demo.ino +102 -0
  40. package/library.json +1 -1
  41. package/library.properties +3 -3
  42. package/package.json +1 -1
  43. package/src/arduino/wifi.hpp +49 -16
  44. package/src/painlessMesh.h +15 -0
  45. package/src/painlessMeshSTA.cpp +7 -1
  46. package/src/painlessmesh/buffer.hpp +218 -37
  47. package/src/painlessmesh/connection.hpp +21 -1
  48. package/src/painlessmesh/mesh.hpp +253 -19
  49. package/src/painlessmesh/router.hpp +31 -0
@@ -0,0 +1,274 @@
1
+ # Priority-Based Message Sending
2
+
3
+ ## Overview
4
+
5
+ painlessMesh now supports priority-based message sending with 4 distinct priority levels. This ensures that critical messages (alarms, commands) are delivered before less important messages (logs, routine sensor data), even under high network load.
6
+
7
+ ## Priority Levels
8
+
9
+ | Priority | Value | Use Case | Examples |
10
+ |----------|-------|----------|----------|
11
+ | **CRITICAL** | 0 | Life/safety critical messages | Fire alarms, oxygen level warnings, emergency shutdowns |
12
+ | **HIGH** | 1 | Important commands and urgent status | Device commands, critical status requests, immediate alerts |
13
+ | **NORMAL** | 2 | Regular operational data (default) | Sensor readings, routine updates, telemetry |
14
+ | **LOW** | 3 | Non-essential information | Debug logs, verbose telemetry, statistics |
15
+
16
+ ## API Reference
17
+
18
+ ### Broadcast Messages with Priority
19
+
20
+ ```cpp
21
+ // Send with default NORMAL priority (backward compatible)
22
+ mesh.sendBroadcast(message);
23
+
24
+ // Send with explicit priority level (0-3)
25
+ mesh.sendBroadcast(message, priorityLevel);
26
+
27
+ // Examples
28
+ mesh.sendBroadcast(alarmData, 0); // CRITICAL priority
29
+ mesh.sendBroadcast(command, 1); // HIGH priority
30
+ mesh.sendBroadcast(sensorData, 2); // NORMAL priority
31
+ mesh.sendBroadcast(debugLog, 3); // LOW priority
32
+ ```
33
+
34
+ ### Direct Messages with Priority
35
+
36
+ ```cpp
37
+ // Send to specific node with default NORMAL priority
38
+ mesh.sendSingle(destinationNodeId, message);
39
+
40
+ // Send to specific node with explicit priority
41
+ mesh.sendSingle(destinationNodeId, message, priorityLevel);
42
+
43
+ // Examples
44
+ mesh.sendSingle(123456, alarmMsg, 0); // CRITICAL
45
+ mesh.sendSingle(123456, cmdMsg, 1); // HIGH
46
+ mesh.sendSingle(123456, dataMsg, 2); // NORMAL
47
+ mesh.sendSingle(123456, logMsg, 3); // LOW
48
+ ```
49
+
50
+ ## How It Works
51
+
52
+ ### Priority Scheduling
53
+
54
+ 1. **Queue Management**: Messages are queued by priority level
55
+ 2. **Send Order**: Higher priority messages (lower numbers) are sent first
56
+ 3. **TCP Push**: CRITICAL (0) and HIGH (1) messages trigger immediate TCP push for faster delivery
57
+ 4. **Fairness**: Within the same priority level, messages maintain FIFO order
58
+
59
+ ### Performance Characteristics
60
+
61
+ - **Memory Overhead**: Minimal - adds ~8 bytes per queued message
62
+ - **CPU Overhead**: O(n) scan to find highest priority (typically negligible with small queues)
63
+ - **Network Impact**:
64
+ - CRITICAL/HIGH messages call `client->send()` for immediate transmission
65
+ - NORMAL/LOW messages use standard TCP buffering
66
+
67
+ ## Best Practices
68
+
69
+ ### 1. Choose Appropriate Priority Levels
70
+
71
+ ```cpp
72
+ // ✅ GOOD: Reserve CRITICAL for actual emergencies
73
+ if (oxygenLevel < CRITICAL_THRESHOLD) {
74
+ mesh.sendBroadcast(alarmData, 0); // CRITICAL
75
+ }
76
+
77
+ // ❌ BAD: Don't overuse CRITICAL priority
78
+ mesh.sendBroadcast(routineSensorData, 0); // Wrong!
79
+ ```
80
+
81
+ ### 2. Use Priority Consistently
82
+
83
+ ```cpp
84
+ // Define constants for clarity
85
+ const uint8_t PRIORITY_ALARM = 0;
86
+ const uint8_t PRIORITY_COMMAND = 1;
87
+ const uint8_t PRIORITY_SENSOR = 2;
88
+ const uint8_t PRIORITY_DEBUG = 3;
89
+
90
+ // Use throughout your code
91
+ mesh.sendBroadcast(alarmMsg, PRIORITY_ALARM);
92
+ mesh.sendBroadcast(sensorMsg, PRIORITY_SENSOR);
93
+ ```
94
+
95
+ ### 3. Consider Message Frequency
96
+
97
+ ```cpp
98
+ // High-frequency messages should use NORMAL or LOW priority
99
+ void loop() {
100
+ if (millis() - lastSensorRead > 1000) {
101
+ // Sensor data every second - use NORMAL
102
+ mesh.sendBroadcast(sensorData, 2);
103
+ }
104
+ }
105
+
106
+ // Low-frequency critical events use CRITICAL/HIGH
107
+ void onAlarmDetected() {
108
+ // Rare but critical event
109
+ mesh.sendBroadcast(alarmData, 0);
110
+ }
111
+ ```
112
+
113
+ ### 4. Test Under Load
114
+
115
+ Always test your priority assignments under realistic network load:
116
+
117
+ ```cpp
118
+ // Simulate high load
119
+ for (int i = 0; i < 100; i++) {
120
+ mesh.sendBroadcast(normalData, 2); // Many NORMAL messages
121
+ }
122
+
123
+ // Verify CRITICAL messages still get through quickly
124
+ mesh.sendBroadcast(criticalAlarm, 0);
125
+ ```
126
+
127
+ ## Examples
128
+
129
+ ### Example 1: Safety Monitoring System
130
+
131
+ ```cpp
132
+ void monitorSafety() {
133
+ // Read oxygen sensor
134
+ float oxygenLevel = readOxygenSensor();
135
+
136
+ if (oxygenLevel < CRITICAL_LEVEL) {
137
+ // CRITICAL: Life-threatening situation
138
+ String alarm = "{\"type\":\"alarm\",\"sensor\":\"oxygen\",\"level\":" +
139
+ String(oxygenLevel) + ",\"severity\":\"critical\"}";
140
+ mesh.sendBroadcast(alarm, 0);
141
+
142
+ } else if (oxygenLevel < WARNING_LEVEL) {
143
+ // HIGH: Concerning but not immediate danger
144
+ String warning = "{\"type\":\"warning\",\"sensor\":\"oxygen\",\"level\":" +
145
+ String(oxygenLevel) + "}";
146
+ mesh.sendBroadcast(warning, 1);
147
+
148
+ } else {
149
+ // NORMAL: Regular monitoring data
150
+ String data = "{\"type\":\"sensor\",\"oxygen\":" + String(oxygenLevel) + "}";
151
+ mesh.sendBroadcast(data, 2);
152
+ }
153
+ }
154
+ ```
155
+
156
+ ### Example 2: Industrial Control System
157
+
158
+ ```cpp
159
+ void sendControlCommand(uint32_t targetNode, String command) {
160
+ // Control commands are HIGH priority
161
+ String cmdMsg = "{\"type\":\"control\",\"command\":\"" + command + "\"}";
162
+ mesh.sendSingle(targetNode, cmdMsg, 1);
163
+ }
164
+
165
+ void sendSensorData() {
166
+ // Regular sensor data is NORMAL priority
167
+ String data = "{\"type\":\"telemetry\",\"temp\":" + String(getTemp()) + "}";
168
+ mesh.sendBroadcast(data, 2);
169
+ }
170
+
171
+ void sendDebugInfo() {
172
+ // Debug logs are LOW priority
173
+ String debug = "{\"type\":\"debug\",\"heap\":" + String(ESP.getFreeHeap()) + "}";
174
+ mesh.sendBroadcast(debug, 3);
175
+ }
176
+ ```
177
+
178
+ ### Example 3: Smart Building Automation
179
+
180
+ ```cpp
181
+ void handleFireAlarm() {
182
+ // CRITICAL: Fire detected
183
+ String alarm = "{\"type\":\"fire_alarm\",\"location\":\"Building A\",\"floor\":3}";
184
+ mesh.sendBroadcast(alarm, 0);
185
+
186
+ // Also send HIGH priority evacuation command to all displays
187
+ String evacCmd = "{\"type\":\"command\",\"action\":\"evacuate\"}";
188
+ mesh.sendBroadcast(evacCmd, 1);
189
+ }
190
+
191
+ void updateLighting() {
192
+ // NORMAL: Regular lighting adjustments
193
+ String lightingData = "{\"type\":\"lighting\",\"brightness\":75}";
194
+ mesh.sendBroadcast(lightingData, 2);
195
+ }
196
+
197
+ void logActivity() {
198
+ // LOW: Activity logs
199
+ String log = "{\"type\":\"log\",\"activity\":\"motion_detected\",\"room\":\"Conference A\"}";
200
+ mesh.sendBroadcast(log, 3);
201
+ }
202
+ ```
203
+
204
+ ## Statistics and Monitoring
205
+
206
+ The priority system tracks statistics for monitoring:
207
+
208
+ ```cpp
209
+ // Note: Statistics API is internal to SentBuffer
210
+ // Access through connection stats if needed for debugging
211
+ ```
212
+
213
+ ## Backward Compatibility
214
+
215
+ The priority system is **100% backward compatible**:
216
+
217
+ ```cpp
218
+ // Old code continues to work (uses NORMAL priority)
219
+ mesh.sendBroadcast(message);
220
+ mesh.sendSingle(nodeId, message);
221
+
222
+ // Legacy bool priority flag still works (false=NORMAL, true=HIGH)
223
+ mesh.sendBroadcast(message, true); // Maps to HIGH priority
224
+ ```
225
+
226
+ ## Performance Considerations
227
+
228
+ ### Memory Usage
229
+
230
+ - **Per Message**: +8 bytes (priority field + iterator overhead)
231
+ - **Total Overhead**: Minimal, typically <1KB for 100 queued messages
232
+
233
+ ### ESP8266 vs ESP32
234
+
235
+ Both platforms support all 4 priority levels. On ESP8266 with limited memory:
236
+ - Monitor queue sizes
237
+ - Use LOW priority for verbose/debug messages
238
+ - Consider message frequency when assigning priorities
239
+
240
+ ### Network Load
241
+
242
+ Under high load:
243
+ - CRITICAL messages bypass most queuing
244
+ - HIGH messages get priority scheduling
245
+ - NORMAL messages may experience slight delays
246
+ - LOW messages may be delayed significantly
247
+
248
+ This is by design - it ensures critical messages get through when you need them most.
249
+
250
+ ## Troubleshooting
251
+
252
+ ### Issue: CRITICAL messages still delayed
253
+
254
+ **Cause**: Network congestion at lower layers (WiFi, TCP)
255
+
256
+ **Solution**:
257
+ - Reduce overall message volume
258
+ - Increase message send intervals for LOW priority messages
259
+ - Consider mesh topology (reduce hops)
260
+
261
+ ### Issue: LOW priority messages never sent
262
+
263
+ **Cause**: Continuous stream of HIGH priority messages
264
+
265
+ **Solution**:
266
+ - Review HIGH priority message frequency
267
+ - Ensure proper priority assignment
268
+ - Implement rate limiting on HIGH priority sources
269
+
270
+ ## See Also
271
+
272
+ - [Message Queue](../queued_alarms/README.md) - For offline message queueing
273
+ - [Basic Example](../basic/basic.ino) - Getting started with painlessMesh
274
+ - [Bridge Examples](../bridge/) - Internet connectivity patterns
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Basic Priority Messaging Example for painlessMesh
3
+ *
4
+ * Demonstrates how to send messages with different priority levels.
5
+ *
6
+ * Priority levels:
7
+ * - PRIORITY_CRITICAL (0): Life/safety critical messages (alarms, emergencies)
8
+ * - PRIORITY_HIGH (1): Important commands and status requests
9
+ * - PRIORITY_NORMAL (2): Regular sensor data and routine updates (default)
10
+ * - PRIORITY_LOW (3): Non-essential telemetry and debug logs
11
+ *
12
+ * Hardware: ESP32 or ESP8266
13
+ */
14
+
15
+ #include "painlessMesh.h"
16
+
17
+ #define MESH_PREFIX "PriorityMeshDemo"
18
+ #define MESH_PASSWORD "somethingSneaky"
19
+ #define MESH_PORT 5555
20
+
21
+ Scheduler userScheduler;
22
+ painlessMesh mesh;
23
+
24
+ // Task to send regular sensor data (NORMAL priority)
25
+ Task taskSensorData(5000, TASK_FOREVER, []() {
26
+ String sensorData = "{\"type\":\"sensor\",\"temp\":23.5,\"humidity\":45}";
27
+
28
+ // Send with NORMAL priority (default)
29
+ mesh.sendBroadcast(sensorData, 2); // Priority level 2 = NORMAL
30
+
31
+ Serial.println("Sent sensor data (NORMAL priority)");
32
+ });
33
+
34
+ // Task to send status updates (HIGH priority)
35
+ Task taskStatusUpdate(10000, TASK_FOREVER, []() {
36
+ String status = "{\"type\":\"status\",\"online\":true,\"uptime\":" + String(millis()) + "}";
37
+
38
+ // Send with HIGH priority
39
+ mesh.sendBroadcast(status, 1); // Priority level 1 = HIGH
40
+
41
+ Serial.println("Sent status update (HIGH priority)");
42
+ });
43
+
44
+ // Task to send low-priority debug logs
45
+ Task taskDebugLog(15000, TASK_FOREVER, []() {
46
+ String debug = "{\"type\":\"debug\",\"freeHeap\":" + String(ESP.getFreeHeap()) + "}";
47
+
48
+ // Send with LOW priority
49
+ mesh.sendBroadcast(debug, 3); // Priority level 3 = LOW
50
+
51
+ Serial.println("Sent debug log (LOW priority)");
52
+ });
53
+
54
+ void receivedCallback(uint32_t from, String& msg) {
55
+ Serial.printf("Received from %u: %s\n", from, msg.c_str());
56
+ }
57
+
58
+ void newConnectionCallback(uint32_t nodeId) {
59
+ Serial.printf("New connection: %u\n", nodeId);
60
+ }
61
+
62
+ void changedConnectionCallback() {
63
+ Serial.printf("Connections changed\n");
64
+ }
65
+
66
+ void setup() {
67
+ Serial.begin(115200);
68
+
69
+ mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
70
+
71
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
72
+ mesh.onReceive(&receivedCallback);
73
+ mesh.onNewConnection(&newConnectionCallback);
74
+ mesh.onChangedConnections(&changedConnectionCallback);
75
+
76
+ // Add periodic tasks
77
+ userScheduler.addTask(taskSensorData);
78
+ userScheduler.addTask(taskStatusUpdate);
79
+ userScheduler.addTask(taskDebugLog);
80
+
81
+ taskSensorData.enable();
82
+ taskStatusUpdate.enable();
83
+ taskDebugLog.enable();
84
+
85
+ Serial.println("Priority messaging demo started");
86
+ Serial.println("Messages sent with different priorities:");
87
+ Serial.println(" CRITICAL (0): Emergency alarms");
88
+ Serial.println(" HIGH (1): Status updates");
89
+ Serial.println(" NORMAL (2): Sensor data");
90
+ Serial.println(" LOW (3): Debug logs");
91
+ }
92
+
93
+ void loop() {
94
+ mesh.update();
95
+ }
96
+
97
+ // Example: Sending a CRITICAL alarm message
98
+ void sendCriticalAlarm(String alarmType, String message) {
99
+ String criticalMsg = "{\"type\":\"alarm\",\"alarm\":\"" + alarmType + "\",\"msg\":\"" + message + "\"}";
100
+
101
+ // Send with CRITICAL priority - will be sent immediately, bypassing queue
102
+ mesh.sendBroadcast(criticalMsg, 0); // Priority level 0 = CRITICAL
103
+
104
+ Serial.printf("CRITICAL ALARM SENT: %s - %s\n", alarmType.c_str(), message.c_str());
105
+ }
106
+
107
+ // Example: Sending a direct message with priority
108
+ void sendCommandToNode(uint32_t destNode, String command) {
109
+ String cmdMsg = "{\"type\":\"command\",\"cmd\":\"" + command + "\"}";
110
+
111
+ // Send to specific node with HIGH priority
112
+ mesh.sendSingle(destNode, cmdMsg, 1); // Priority level 1 = HIGH
113
+
114
+ Serial.printf("Command sent to node %u with HIGH priority\n", destNode);
115
+ }
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Advanced Priority Example with Message Queue Integration
3
+ *
4
+ * Demonstrates how to use priority messaging with the message queue
5
+ * for offline/Internet-unavailable scenarios.
6
+ *
7
+ * This example shows:
8
+ * - Priority-based message sending
9
+ * - Message queueing when Internet is unavailable
10
+ * - Automatic queue flushing when Internet becomes available
11
+ * - Priority ordering during queue flush
12
+ *
13
+ * Hardware: ESP32 or ESP8266
14
+ */
15
+
16
+ #include "painlessMesh.h"
17
+
18
+ #define MESH_PREFIX "PriorityQueueMesh"
19
+ #define MESH_PASSWORD "somethingSneaky"
20
+ #define MESH_PORT 5555
21
+
22
+ Scheduler userScheduler;
23
+ painlessMesh mesh;
24
+
25
+ bool internetAvailable = false;
26
+ uint32_t bridgeNodeId = 0;
27
+
28
+ // Task to check bridge status
29
+ Task taskCheckBridge(5000, TASK_FOREVER, []() {
30
+ bool hasInternet = mesh.hasInternetConnection();
31
+
32
+ if (hasInternet != internetAvailable) {
33
+ internetAvailable = hasInternet;
34
+ Serial.printf("Internet status changed: %s\n", hasInternet ? "ONLINE" : "OFFLINE");
35
+
36
+ if (hasInternet) {
37
+ // Internet came back online - flush queued messages by priority
38
+ flushQueuedMessages();
39
+ }
40
+ }
41
+ });
42
+
43
+ // Task to generate sensor data
44
+ Task taskSensorData(10000, TASK_FOREVER, []() {
45
+ String sensorData = "{\"type\":\"sensor\",\"temp\":" + String(random(15, 30)) +
46
+ ",\"humidity\":" + String(random(30, 70)) + "}";
47
+
48
+ sendMessage(sensorData, 2); // NORMAL priority
49
+ });
50
+
51
+ // Task to generate status updates
52
+ Task taskStatusUpdate(30000, TASK_FOREVER, []() {
53
+ String status = "{\"type\":\"status\",\"uptime\":" + String(millis() / 1000) +
54
+ ",\"heap\":" + String(ESP.getFreeHeap()) + "}";
55
+
56
+ sendMessage(status, 1); // HIGH priority
57
+ });
58
+
59
+ void setup() {
60
+ Serial.begin(115200);
61
+
62
+ // Enable message queue with 500 message capacity
63
+ mesh.enableMessageQueue(true, 500);
64
+
65
+ mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
66
+
67
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
68
+ mesh.onReceive(&receivedCallback);
69
+ mesh.onNewConnection(&newConnectionCallback);
70
+ mesh.onBridgeStatusChanged(&bridgeStatusChanged);
71
+ mesh.onQueueStateChanged(&queueStateChanged);
72
+
73
+ // Add tasks
74
+ userScheduler.addTask(taskCheckBridge);
75
+ userScheduler.addTask(taskSensorData);
76
+ userScheduler.addTask(taskStatusUpdate);
77
+
78
+ taskCheckBridge.enable();
79
+ taskSensorData.enable();
80
+ taskStatusUpdate.enable();
81
+
82
+ Serial.println("Priority + Queue demo started");
83
+ Serial.println("Messages will be queued when Internet is unavailable");
84
+ Serial.println("Queue will be flushed by priority when Internet returns");
85
+ }
86
+
87
+ void loop() {
88
+ mesh.update();
89
+ }
90
+
91
+ /**
92
+ * Send a message with priority
93
+ * - If Internet available: send immediately via mesh with priority
94
+ * - If Internet unavailable: queue for later with priority
95
+ */
96
+ void sendMessage(String message, uint8_t priority) {
97
+ if (internetAvailable && bridgeNodeId != 0) {
98
+ // Internet available - send with priority
99
+ mesh.sendSingle(bridgeNodeId, message, priority);
100
+ Serial.printf("Sent message with priority %u\n", priority);
101
+
102
+ } else {
103
+ // Internet unavailable - queue with priority
104
+ // Map our priority levels to MessageQueue priorities
105
+ MessagePriority queuePriority;
106
+ switch(priority) {
107
+ case 0: queuePriority = PRIORITY_CRITICAL; break;
108
+ case 1: queuePriority = PRIORITY_HIGH; break;
109
+ case 2: queuePriority = PRIORITY_NORMAL; break;
110
+ case 3: queuePriority = PRIORITY_LOW; break;
111
+ default: queuePriority = PRIORITY_NORMAL; break;
112
+ }
113
+
114
+ uint32_t msgId = mesh.queueMessage(message, "mqtt://cloud", queuePriority);
115
+ if (msgId > 0) {
116
+ Serial.printf("Queued message #%u with priority %u (offline mode)\n", msgId, priority);
117
+ } else {
118
+ Serial.println("Failed to queue message - queue full!");
119
+ }
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Send a critical alarm - always gets through
125
+ */
126
+ void sendCriticalAlarm(String alarmType, String alarmMessage) {
127
+ String criticalMsg = "{\"type\":\"alarm\",\"alarm\":\"" + alarmType +
128
+ "\",\"msg\":\"" + alarmMessage + "\",\"time\":" +
129
+ String(millis()) + "}";
130
+
131
+ // CRITICAL priority - send immediately even if queued
132
+ sendMessage(criticalMsg, 0);
133
+
134
+ Serial.printf("CRITICAL ALARM: %s - %s\n", alarmType.c_str(), alarmMessage.c_str());
135
+ }
136
+
137
+ /**
138
+ * Flush queued messages by priority when Internet returns
139
+ */
140
+ void flushQueuedMessages() {
141
+ Serial.println("Flushing queued messages by priority...");
142
+
143
+ // Get all queued messages (already sorted by priority in MessageQueue)
144
+ auto messages = mesh.flushMessageQueue();
145
+
146
+ Serial.printf("Found %d queued messages to send\n", messages.size());
147
+
148
+ // Send each message with its original priority
149
+ for (auto& msg : messages) {
150
+ // Convert MessagePriority back to send priority (0-3)
151
+ uint8_t sendPriority;
152
+ switch(msg.priority) {
153
+ case PRIORITY_CRITICAL: sendPriority = 0; break;
154
+ case PRIORITY_HIGH: sendPriority = 1; break;
155
+ case PRIORITY_NORMAL: sendPriority = 2; break;
156
+ case PRIORITY_LOW: sendPriority = 3; break;
157
+ default: sendPriority = 2; break;
158
+ }
159
+
160
+ // Send with original priority
161
+ if (bridgeNodeId != 0) {
162
+ bool sent = mesh.sendSingle(bridgeNodeId, msg.payload, sendPriority);
163
+
164
+ if (sent) {
165
+ // Remove from queue on success
166
+ mesh.removeQueuedMessage(msg.id);
167
+ Serial.printf("Sent queued message #%u (priority %u)\n", msg.id, sendPriority);
168
+ } else {
169
+ // Failed to send - increment attempts
170
+ uint32_t attempts = mesh.incrementQueuedMessageAttempts(msg.id);
171
+ Serial.printf("Failed to send queued message #%u (attempt %u)\n", msg.id, attempts);
172
+
173
+ // If too many attempts, remove it
174
+ if (attempts > 5) {
175
+ mesh.removeQueuedMessage(msg.id);
176
+ Serial.printf("Dropped message #%u after 5 attempts\n", msg.id);
177
+ }
178
+ }
179
+ }
180
+
181
+ // Small delay between sends to avoid overwhelming the network
182
+ delay(10);
183
+ }
184
+
185
+ Serial.printf("Queue flush complete. Remaining: %u messages\n",
186
+ mesh.getQueuedMessageCount());
187
+ }
188
+
189
+ void receivedCallback(uint32_t from, String& msg) {
190
+ Serial.printf("Received from %u: %s\n", from, msg.c_str());
191
+ }
192
+
193
+ void newConnectionCallback(uint32_t nodeId) {
194
+ Serial.printf("New connection: %u\n", nodeId);
195
+ }
196
+
197
+ void bridgeStatusChanged(uint32_t nodeId, bool hasInternet) {
198
+ Serial.printf("Bridge %u status: Internet %s\n",
199
+ nodeId, hasInternet ? "ONLINE" : "OFFLINE");
200
+
201
+ if (hasInternet) {
202
+ bridgeNodeId = nodeId;
203
+ internetAvailable = true;
204
+
205
+ // Flush queued messages with priority
206
+ flushQueuedMessages();
207
+ } else {
208
+ internetAvailable = false;
209
+ }
210
+ }
211
+
212
+ void queueStateChanged(QueueState state, uint32_t count) {
213
+ switch(state) {
214
+ case QUEUE_EMPTY:
215
+ Serial.println("Queue is empty");
216
+ break;
217
+ case QUEUE_NORMAL:
218
+ Serial.printf("Queue normal: %u messages\n", count);
219
+ break;
220
+ case QUEUE_75_PERCENT:
221
+ Serial.printf("WARNING: Queue 75%% full (%u messages)\n", count);
222
+ break;
223
+ case QUEUE_FULL:
224
+ Serial.printf("ALERT: Queue is FULL (%u messages)\n", count);
225
+ break;
226
+ }
227
+ }
228
+
229
+ // Example: Simulate a critical event
230
+ void simulateCriticalEvent() {
231
+ sendCriticalAlarm("FIRE", "Fire detected in Building A, Floor 3");
232
+ }
233
+
234
+ // Example: Monitor queue statistics
235
+ void printQueueStats() {
236
+ auto stats = mesh.getQueueStats();
237
+
238
+ Serial.println("=== Queue Statistics ===");
239
+ Serial.printf("Total queued: %u\n", stats.totalQueued);
240
+ Serial.printf("Total sent: %u\n", stats.totalSent);
241
+ Serial.printf("Total dropped: %u\n", stats.totalDropped);
242
+ Serial.printf("Current size: %u / %u\n", stats.currentSize, stats.maxSize);
243
+ Serial.println();
244
+ Serial.printf("CRITICAL queued: %u\n", stats.criticalQueued);
245
+ Serial.printf("HIGH queued: %u\n", stats.highQueued);
246
+ Serial.printf("NORMAL queued: %u\n", stats.normalQueued);
247
+ Serial.printf("LOW queued: %u\n", stats.lowQueued);
248
+ Serial.println("=======================");
249
+ }