@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.
- package/CHANGELOG.md +32 -0
- package/README.md +62 -11
- package/RELEASE_GUIDE.md +57 -16
- package/docs/ARDUINO_LIBRARY_MANAGER_SUBMISSION.md +331 -0
- package/docs/features/DIAGNOSTICS_API.md +534 -0
- package/docs/getting-started/arduino-manual-install.md +313 -0
- package/docs/implementation/BRIDGE_ARCHITECTURE_IMPLEMENTATION.md +340 -0
- package/docs/implementation/BRIDGE_HEALTH_MONITORING_IMPLEMENTATION.md +213 -0
- package/docs/implementation/BRIDGE_STATUS_FEATURE.md +635 -0
- package/docs/implementation/DIAGNOSTICS_API_IMPLEMENTATION.md +232 -0
- package/docs/implementation/IMPLEMENTATION_COMPLETE.md +228 -0
- package/docs/implementation/IMPLEMENTATION_NTP_TIME_SYNC.md +325 -0
- package/docs/implementation/IMPLEMENTATION_SUMMARY.md +316 -0
- package/docs/implementation/MESSAGE_QUEUE_IMPLEMENTATION.md +405 -0
- package/docs/implementation/MULTI_BRIDGE_IMPLEMENTATION.md +520 -0
- package/docs/implementation/NTP_TIME_SYNC_FEATURE.md +392 -0
- package/docs/internal/CUSTOM_AGENT_ANALYSIS.md +391 -0
- package/docs/internal/ISSUE_65_VERIFICATION.md +947 -0
- package/docs/internal/ISSUE_66_CLOSURE.md +249 -0
- package/docs/internal/ISSUE_66_STATUS.md +316 -0
- package/docs/internal/PR_SUMMARY.md +315 -0
- package/docs/internal/REVIEW_SUMMARY.md +332 -0
- package/docs/releases/PUBLISH_v1.8.0_INSTRUCTIONS.md +163 -0
- package/docs/releases/QUICK_START_RELEASES.md +113 -0
- package/docs/releases/RELEASE_CHECKLIST_v1.8.0.md +331 -0
- package/docs/releases/RELEASE_CHECKLIST_v1.8.2.md +309 -0
- package/docs/releases/RELEASE_NOTES_v1.8.0.md +685 -0
- package/docs/releases/RELEASE_NOTES_v1.8.1.md +221 -0
- package/docs/releases/RELEASE_NOTES_v1.8.2.md +421 -0
- package/docs/releases/RELEASE_NOTES_v1.8.3.md +292 -0
- package/docs/troubleshooting/ARDUINO_IDE_VERSION_FIX_SUMMARY.md +229 -0
- package/docs/troubleshooting/ARDUINO_LIBRARY_NAME_FIX.md +197 -0
- package/docs/troubleshooting/NPM_PUBLISHING_ISSUE_SUMMARY.md +110 -0
- package/docs/troubleshooting/station-reconnection-issues.md +172 -0
- package/examples/priority/README.md +274 -0
- package/examples/priority/priority_basic_example.ino +115 -0
- package/examples/priority/priority_with_queue.ino +249 -0
- package/examples/routing_demo/README.md +172 -0
- package/examples/routing_demo/routing_demo.ino +102 -0
- package/library.json +1 -1
- package/library.properties +3 -3
- package/package.json +1 -1
- package/src/arduino/wifi.hpp +49 -16
- package/src/painlessMesh.h +15 -0
- package/src/painlessMeshSTA.cpp +7 -1
- package/src/painlessmesh/buffer.hpp +218 -37
- package/src/painlessmesh/connection.hpp +21 -1
- package/src/painlessmesh/mesh.hpp +253 -19
- package/src/painlessmesh/router.hpp +31 -0
|
@@ -0,0 +1,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
|
+
}
|