@alteriom/painlessmesh 1.8.0 → 1.8.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 +83 -1
- package/README.md +167 -12
- package/docs/architecture/mesh-architecture.md +20 -0
- package/docs/multi-bridge-setup.md +1025 -0
- package/examples/multi_bridge/README.md +346 -0
- package/examples/multi_bridge/primary_bridge.ino +96 -0
- package/examples/multi_bridge/regular_node.ino +141 -0
- package/examples/multi_bridge/secondary_bridge.ino +111 -0
- package/examples/queued_alarms/README.md +390 -0
- package/examples/queued_alarms/queued_alarms.ino +265 -0
- package/library.json +22 -3
- package/library.properties +1 -1
- package/package.json +1 -1
- package/src/arduino/wifi.hpp +319 -3
- package/src/painlessmesh/mesh.hpp +200 -0
- package/src/painlessmesh/message_queue.hpp +368 -0
- package/src/painlessmesh/plugin.hpp +69 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# Multi-Bridge Example
|
|
2
|
+
|
|
3
|
+
This example demonstrates advanced multi-bridge coordination for high-availability mesh networks with multiple simultaneous Internet gateways.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
In a multi-bridge deployment, multiple nodes act as bridges to the Internet simultaneously. This provides:
|
|
8
|
+
|
|
9
|
+
- **High Availability**: Zero downtime during failover
|
|
10
|
+
- **Load Balancing**: Distribute traffic across multiple uplinks
|
|
11
|
+
- **Geographic Distribution**: Bridges in different locations
|
|
12
|
+
- **Redundancy**: Multiple paths to Internet
|
|
13
|
+
|
|
14
|
+
## Architecture
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
Internet Connection A → Primary Bridge (Priority 10)
|
|
18
|
+
↓
|
|
19
|
+
Mesh Network
|
|
20
|
+
↓
|
|
21
|
+
Internet Connection B → Secondary Bridge (Priority 5)
|
|
22
|
+
↓
|
|
23
|
+
Regular Nodes
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Files
|
|
27
|
+
|
|
28
|
+
- **primary_bridge.ino** - Primary bridge with highest priority (10)
|
|
29
|
+
- **secondary_bridge.ino** - Secondary bridge for redundancy (priority 5)
|
|
30
|
+
- **regular_node.ino** - Regular mesh node that uses bridges
|
|
31
|
+
|
|
32
|
+
## How It Works
|
|
33
|
+
|
|
34
|
+
### Bridge Priority
|
|
35
|
+
|
|
36
|
+
Bridges are assigned priorities (1-10):
|
|
37
|
+
- **10 = Primary**: Handles all traffic when available
|
|
38
|
+
- **5 = Secondary**: Hot standby, takes over if primary fails
|
|
39
|
+
- **1 = Standby**: Only used if all higher priority bridges fail
|
|
40
|
+
|
|
41
|
+
### Bridge Selection Strategies
|
|
42
|
+
|
|
43
|
+
1. **PRIORITY_BASED** (default): Always use highest priority available bridge
|
|
44
|
+
2. **ROUND_ROBIN**: Distribute load evenly across all bridges
|
|
45
|
+
3. **BEST_SIGNAL**: Use bridge with best WiFi signal strength
|
|
46
|
+
|
|
47
|
+
### Coordination Protocol
|
|
48
|
+
|
|
49
|
+
Bridges exchange coordination messages (Type 613) containing:
|
|
50
|
+
- Priority level
|
|
51
|
+
- Current role (primary/secondary/standby)
|
|
52
|
+
- Load percentage
|
|
53
|
+
- List of known peer bridges
|
|
54
|
+
|
|
55
|
+
Regular nodes track all bridges and automatically select the best one based on the configured strategy.
|
|
56
|
+
|
|
57
|
+
## Setup Instructions
|
|
58
|
+
|
|
59
|
+
### Hardware Required
|
|
60
|
+
|
|
61
|
+
- 3+ ESP32 or ESP8266 devices
|
|
62
|
+
- 1-2 WiFi routers with Internet connection
|
|
63
|
+
- USB cables for programming
|
|
64
|
+
|
|
65
|
+
### Configuration
|
|
66
|
+
|
|
67
|
+
#### Primary Bridge
|
|
68
|
+
1. Flash `primary_bridge.ino` to first ESP32
|
|
69
|
+
2. Configure router credentials:
|
|
70
|
+
```cpp
|
|
71
|
+
#define ROUTER_SSID "YourPrimaryRouter"
|
|
72
|
+
#define ROUTER_PASSWORD "routerpass"
|
|
73
|
+
```
|
|
74
|
+
3. Priority is set to 10 (highest)
|
|
75
|
+
|
|
76
|
+
#### Secondary Bridge
|
|
77
|
+
1. Flash `secondary_bridge.ino` to second ESP32
|
|
78
|
+
2. Configure router credentials (can be same or different router):
|
|
79
|
+
```cpp
|
|
80
|
+
#define ROUTER_SSID "YourSecondaryRouter"
|
|
81
|
+
#define ROUTER_PASSWORD "routerpass2"
|
|
82
|
+
```
|
|
83
|
+
3. Priority is set to 5 (secondary)
|
|
84
|
+
|
|
85
|
+
#### Regular Nodes
|
|
86
|
+
1. Flash `regular_node.ino` to remaining ESP32 devices
|
|
87
|
+
2. No router credentials needed
|
|
88
|
+
3. They automatically discover and use bridges
|
|
89
|
+
|
|
90
|
+
### Testing
|
|
91
|
+
|
|
92
|
+
#### Normal Operation
|
|
93
|
+
1. Power on primary bridge - should connect to router
|
|
94
|
+
2. Power on secondary bridge - should connect to router
|
|
95
|
+
3. Power on regular nodes - should join mesh
|
|
96
|
+
4. Regular nodes should prefer primary bridge (priority 10)
|
|
97
|
+
|
|
98
|
+
#### Failover Test
|
|
99
|
+
1. Disconnect primary bridge from power
|
|
100
|
+
2. Regular nodes should detect loss within 60 seconds
|
|
101
|
+
3. Regular nodes should automatically switch to secondary bridge
|
|
102
|
+
4. No data loss or interruption
|
|
103
|
+
|
|
104
|
+
#### Load Balancing Test (Round-Robin)
|
|
105
|
+
1. On regular nodes, change strategy:
|
|
106
|
+
```cpp
|
|
107
|
+
mesh.setBridgeSelectionStrategy(painlessMesh::ROUND_ROBIN);
|
|
108
|
+
```
|
|
109
|
+
2. Messages should alternate between bridges
|
|
110
|
+
|
|
111
|
+
## Bridge Selection Strategies
|
|
112
|
+
|
|
113
|
+
### Priority-Based (Default)
|
|
114
|
+
|
|
115
|
+
Best for most deployments. Uses highest priority bridge available.
|
|
116
|
+
|
|
117
|
+
```cpp
|
|
118
|
+
mesh.setBridgeSelectionStrategy(painlessMesh::PRIORITY_BASED);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**When to use:**
|
|
122
|
+
- Production systems needing predictable routing
|
|
123
|
+
- When you have primary and backup Internet connections
|
|
124
|
+
- Clear preference for one connection over another
|
|
125
|
+
|
|
126
|
+
### Round-Robin Load Balancing
|
|
127
|
+
|
|
128
|
+
Distributes traffic evenly across all bridges.
|
|
129
|
+
|
|
130
|
+
```cpp
|
|
131
|
+
mesh.setBridgeSelectionStrategy(painlessMesh::ROUND_ROBIN);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**When to use:**
|
|
135
|
+
- High traffic scenarios
|
|
136
|
+
- Multiple equal-quality Internet connections
|
|
137
|
+
- Load distribution is important
|
|
138
|
+
|
|
139
|
+
### Best Signal
|
|
140
|
+
|
|
141
|
+
Always uses bridge with strongest WiFi signal.
|
|
142
|
+
|
|
143
|
+
```cpp
|
|
144
|
+
mesh.setBridgeSelectionStrategy(painlessMesh::BEST_SIGNAL);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**When to use:**
|
|
148
|
+
- Large mesh networks
|
|
149
|
+
- Nodes move around
|
|
150
|
+
- Signal strength affects performance significantly
|
|
151
|
+
|
|
152
|
+
## API Reference
|
|
153
|
+
|
|
154
|
+
### Multi-Bridge Configuration
|
|
155
|
+
|
|
156
|
+
```cpp
|
|
157
|
+
// Enable multi-bridge mode
|
|
158
|
+
mesh.enableMultiBridge(true);
|
|
159
|
+
|
|
160
|
+
// Set selection strategy
|
|
161
|
+
mesh.setBridgeSelectionStrategy(painlessMesh::PRIORITY_BASED);
|
|
162
|
+
mesh.setBridgeSelectionStrategy(painlessMesh::ROUND_ROBIN);
|
|
163
|
+
mesh.setBridgeSelectionStrategy(painlessMesh::BEST_SIGNAL);
|
|
164
|
+
|
|
165
|
+
// Set max concurrent bridges (default: 2, max: 5)
|
|
166
|
+
mesh.setMaxBridges(3);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Bridge Initialization
|
|
170
|
+
|
|
171
|
+
```cpp
|
|
172
|
+
// Initialize as bridge with priority
|
|
173
|
+
mesh.initAsBridge(meshSSID, meshPassword,
|
|
174
|
+
routerSSID, routerPassword,
|
|
175
|
+
&scheduler, port, priority);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Bridge Discovery
|
|
179
|
+
|
|
180
|
+
```cpp
|
|
181
|
+
// Get list of active bridge node IDs
|
|
182
|
+
std::vector<uint32_t> bridges = mesh.getActiveBridges();
|
|
183
|
+
|
|
184
|
+
// Get recommended bridge for next message
|
|
185
|
+
uint32_t bridgeId = mesh.getRecommendedBridge();
|
|
186
|
+
|
|
187
|
+
// Manually select bridge for next transmission
|
|
188
|
+
mesh.selectBridge(bridgeId);
|
|
189
|
+
|
|
190
|
+
// Check if multi-bridge is enabled
|
|
191
|
+
bool enabled = mesh.isMultiBridgeEnabled();
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Expected Output
|
|
195
|
+
|
|
196
|
+
### Primary Bridge
|
|
197
|
+
```
|
|
198
|
+
=== Multi-Bridge: PRIMARY BRIDGE ===
|
|
199
|
+
|
|
200
|
+
=== Bridge Mode Initialization (Priority: 10, Role: primary) ===
|
|
201
|
+
✓ Router connected on channel 6
|
|
202
|
+
✓ Router IP: 192.168.1.100
|
|
203
|
+
Bridge coordination enabled (priority: 10, role: primary)
|
|
204
|
+
|
|
205
|
+
=== Primary Bridge Status ===
|
|
206
|
+
Node ID: 123456
|
|
207
|
+
Connected Nodes: 3
|
|
208
|
+
Active Bridges: 2
|
|
209
|
+
- Bridge: 123456 (ME)
|
|
210
|
+
- Bridge: 789012
|
|
211
|
+
Recommended Bridge: 123456
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Secondary Bridge
|
|
215
|
+
```
|
|
216
|
+
=== Multi-Bridge: SECONDARY BRIDGE ===
|
|
217
|
+
|
|
218
|
+
=== Bridge Mode Initialization (Priority: 5, Role: secondary) ===
|
|
219
|
+
✓ Router connected on channel 6
|
|
220
|
+
✓ Router IP: 192.168.1.101
|
|
221
|
+
Bridge coordination enabled (priority: 5, role: secondary)
|
|
222
|
+
|
|
223
|
+
=== Secondary Bridge Status ===
|
|
224
|
+
Node ID: 789012
|
|
225
|
+
Connected Nodes: 3
|
|
226
|
+
Active Bridges: 2
|
|
227
|
+
- Bridge: 123456
|
|
228
|
+
- Bridge: 789012 (ME)
|
|
229
|
+
Recommended Bridge: 123456
|
|
230
|
+
✓ Standby mode - primary bridge is active
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Regular Node
|
|
234
|
+
```
|
|
235
|
+
=== Multi-Bridge: REGULAR NODE ===
|
|
236
|
+
|
|
237
|
+
=== Network Status ===
|
|
238
|
+
Node ID: 456789
|
|
239
|
+
Connected Nodes: 4
|
|
240
|
+
Active Bridges: 2
|
|
241
|
+
- Bridge: 123456
|
|
242
|
+
- Bridge: 789012
|
|
243
|
+
Internet Available: YES
|
|
244
|
+
|
|
245
|
+
--- Sending Sensor Data ---
|
|
246
|
+
Recommended Bridge: 123456
|
|
247
|
+
Message: Temperature: 22.3°C, Humidity: 45.2%
|
|
248
|
+
✓ Sent to bridge
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Troubleshooting
|
|
252
|
+
|
|
253
|
+
### No Bridges Found
|
|
254
|
+
|
|
255
|
+
**Symptoms**: `Active Bridges: 0`
|
|
256
|
+
|
|
257
|
+
**Solutions**:
|
|
258
|
+
- Verify bridge nodes are powered on
|
|
259
|
+
- Check router credentials are correct
|
|
260
|
+
- Ensure bridges successfully connected to router
|
|
261
|
+
- Check all devices use same MESH_PREFIX and MESH_PASSWORD
|
|
262
|
+
|
|
263
|
+
### Bridges Not Coordinating
|
|
264
|
+
|
|
265
|
+
**Symptoms**: Bridges don't see each other
|
|
266
|
+
|
|
267
|
+
**Solutions**:
|
|
268
|
+
- Verify `enableMultiBridge(true)` is called on all bridges
|
|
269
|
+
- Check mesh connectivity between bridges
|
|
270
|
+
- Look for "Bridge coordination" messages in logs
|
|
271
|
+
- Ensure bridges are on same mesh network
|
|
272
|
+
|
|
273
|
+
### Failover Not Working
|
|
274
|
+
|
|
275
|
+
**Symptoms**: No automatic switch to secondary
|
|
276
|
+
|
|
277
|
+
**Solutions**:
|
|
278
|
+
- Check `mesh.onBridgeStatusChanged()` callback is registered
|
|
279
|
+
- Verify secondary bridge has Internet connection
|
|
280
|
+
- Ensure bridge status broadcasts are enabled
|
|
281
|
+
- Check 60-second timeout hasn't been exceeded
|
|
282
|
+
|
|
283
|
+
### Wrong Bridge Selected
|
|
284
|
+
|
|
285
|
+
**Symptoms**: Secondary used instead of primary
|
|
286
|
+
|
|
287
|
+
**Solutions**:
|
|
288
|
+
- Verify priorities are correct (primary=10, secondary=5)
|
|
289
|
+
- Check strategy is PRIORITY_BASED
|
|
290
|
+
- Ensure primary bridge has Internet connection
|
|
291
|
+
- Look for priority values in coordination messages
|
|
292
|
+
|
|
293
|
+
## Advanced Configuration
|
|
294
|
+
|
|
295
|
+
### Three or More Bridges
|
|
296
|
+
|
|
297
|
+
```cpp
|
|
298
|
+
// Bridge 1: Primary (priority 10)
|
|
299
|
+
mesh.initAsBridge(ssid, pass, router1, pass1, &sched, port, 10);
|
|
300
|
+
|
|
301
|
+
// Bridge 2: Secondary (priority 7)
|
|
302
|
+
mesh.initAsBridge(ssid, pass, router2, pass2, &sched, port, 7);
|
|
303
|
+
|
|
304
|
+
// Bridge 3: Tertiary (priority 3)
|
|
305
|
+
mesh.initAsBridge(ssid, pass, router3, pass3, &sched, port, 3);
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Geographic Distribution
|
|
309
|
+
|
|
310
|
+
Use when mesh spans multiple buildings:
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
Building A: Bridge1 (priority 10) → Internet A
|
|
314
|
+
Building B: Bridge2 (priority 10) → Internet B
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Both bridges have same priority, nodes use closest one (BEST_SIGNAL strategy).
|
|
318
|
+
|
|
319
|
+
### Traffic Shaping (Future)
|
|
320
|
+
|
|
321
|
+
Route different message types to different bridges:
|
|
322
|
+
|
|
323
|
+
```cpp
|
|
324
|
+
// Coming in future release
|
|
325
|
+
mesh.setBridgeSelectionStrategy(mesh.TRAFFIC_TYPE);
|
|
326
|
+
mesh.routeTrafficType(ALARM_MESSAGE, bridge1);
|
|
327
|
+
mesh.routeTrafficType(SENSOR_DATA, bridge2);
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Dependencies
|
|
331
|
+
|
|
332
|
+
- Issue #63: Bridge Status Broadcast ✅ (IMPLEMENTED)
|
|
333
|
+
- Issue #64: Bridge Failover ✅ (IMPLEMENTED)
|
|
334
|
+
- Issue #65: Multi-Bridge Coordination ✅ (THIS FEATURE)
|
|
335
|
+
|
|
336
|
+
## Related Examples
|
|
337
|
+
|
|
338
|
+
- `examples/bridge/` - Basic single bridge setup
|
|
339
|
+
- `examples/bridge_failover/` - Single bridge with automatic failover
|
|
340
|
+
- `examples/bridgeAwareSensorNode/` - Node that checks bridge status
|
|
341
|
+
|
|
342
|
+
## Further Reading
|
|
343
|
+
|
|
344
|
+
- [Bridge Architecture Documentation](../../BRIDGE_TO_INTERNET.md)
|
|
345
|
+
- [Bridge Health Monitoring](../../BRIDGE_HEALTH_MONITORING_IMPLEMENTATION.md)
|
|
346
|
+
- [painlessMesh Wiki](https://gitlab.com/painlessMesh/painlessMesh/-/wikis/home)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
//************************************************************
|
|
2
|
+
// Multi-Bridge Example: Primary Bridge Node
|
|
3
|
+
//
|
|
4
|
+
// This example demonstrates a primary bridge (priority 10) in a
|
|
5
|
+
// multi-bridge deployment. Use with secondary_bridge.ino for
|
|
6
|
+
// redundancy and load balancing.
|
|
7
|
+
//
|
|
8
|
+
// Features demonstrated:
|
|
9
|
+
// - Primary bridge with highest priority
|
|
10
|
+
// - Multi-bridge coordination
|
|
11
|
+
// - Load reporting and bridge discovery
|
|
12
|
+
// - Automatic role management
|
|
13
|
+
//************************************************************
|
|
14
|
+
|
|
15
|
+
#include "painlessMesh.h"
|
|
16
|
+
|
|
17
|
+
#define MESH_PREFIX "MultiBridgeMesh"
|
|
18
|
+
#define MESH_PASSWORD "meshpassword"
|
|
19
|
+
#define MESH_PORT 5555
|
|
20
|
+
|
|
21
|
+
// Primary router connection (high-speed Internet)
|
|
22
|
+
#define ROUTER_SSID "PrimaryRouter"
|
|
23
|
+
#define ROUTER_PASSWORD "routerpass"
|
|
24
|
+
|
|
25
|
+
Scheduler userScheduler;
|
|
26
|
+
painlessMesh mesh;
|
|
27
|
+
|
|
28
|
+
// Task to display bridge coordination status
|
|
29
|
+
Task taskBridgeStatus(10000, TASK_FOREVER, [](){
|
|
30
|
+
Serial.println("\n=== Primary Bridge Status ===");
|
|
31
|
+
Serial.printf("Node ID: %u\n", mesh.getNodeId());
|
|
32
|
+
Serial.printf("Connected Nodes: %d\n", mesh.getNodeList().size());
|
|
33
|
+
|
|
34
|
+
// Show all active bridges in the mesh
|
|
35
|
+
auto activeBridges = mesh.getActiveBridges();
|
|
36
|
+
Serial.printf("Active Bridges: %d\n", activeBridges.size());
|
|
37
|
+
for (auto bridgeId : activeBridges) {
|
|
38
|
+
Serial.printf(" - Bridge: %u%s\n", bridgeId,
|
|
39
|
+
(bridgeId == mesh.getNodeId()) ? " (ME)" : "");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Show recommended bridge for next message
|
|
43
|
+
uint32_t recommended = mesh.getRecommendedBridge();
|
|
44
|
+
Serial.printf("Recommended Bridge: %u\n", recommended);
|
|
45
|
+
Serial.println("=============================\n");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
void receivedCallback(uint32_t from, String& msg) {
|
|
49
|
+
Serial.printf("Received from %u: %s\n", from, msg.c_str());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void newConnectionCallback(uint32_t nodeId) {
|
|
53
|
+
Serial.printf("New Connection, nodeId = %u\n", nodeId);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
void changedConnectionCallback() {
|
|
57
|
+
Serial.printf("Changed connections. Node count: %d\n", mesh.getNodeList().size());
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
void setup() {
|
|
61
|
+
Serial.begin(115200);
|
|
62
|
+
delay(2000);
|
|
63
|
+
|
|
64
|
+
Serial.println("\n\n=== Multi-Bridge: PRIMARY BRIDGE ===\n");
|
|
65
|
+
|
|
66
|
+
// Initialize mesh as primary bridge with priority 10 (highest)
|
|
67
|
+
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
68
|
+
|
|
69
|
+
// Enable multi-bridge coordination mode
|
|
70
|
+
mesh.enableMultiBridge(true);
|
|
71
|
+
|
|
72
|
+
// Set bridge selection strategy (PRIORITY_BASED is default)
|
|
73
|
+
mesh.setBridgeSelectionStrategy(painlessMesh::PRIORITY_BASED);
|
|
74
|
+
|
|
75
|
+
// Initialize as bridge with priority 10 (primary)
|
|
76
|
+
mesh.initAsBridge(MESH_PREFIX, MESH_PASSWORD,
|
|
77
|
+
ROUTER_SSID, ROUTER_PASSWORD,
|
|
78
|
+
&userScheduler, MESH_PORT, 10); // Priority 10 = Primary
|
|
79
|
+
|
|
80
|
+
mesh.onReceive(&receivedCallback);
|
|
81
|
+
mesh.onNewConnection(&newConnectionCallback);
|
|
82
|
+
mesh.onChangedConnections(&changedConnectionCallback);
|
|
83
|
+
|
|
84
|
+
// Add status reporting task
|
|
85
|
+
userScheduler.addTask(taskBridgeStatus);
|
|
86
|
+
taskBridgeStatus.enable();
|
|
87
|
+
|
|
88
|
+
Serial.println("\n=== Primary Bridge Ready ===");
|
|
89
|
+
Serial.println("This node is the PRIMARY bridge (Priority 10)");
|
|
90
|
+
Serial.println("It will be preferred for all mesh traffic");
|
|
91
|
+
Serial.println("If it fails, the secondary bridge will take over automatically\n");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
void loop() {
|
|
95
|
+
mesh.update();
|
|
96
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
//************************************************************
|
|
2
|
+
// Multi-Bridge Example: Regular Node
|
|
3
|
+
//
|
|
4
|
+
// This example demonstrates a regular mesh node in a multi-bridge
|
|
5
|
+
// network. The node automatically discovers and uses available bridges
|
|
6
|
+
// for Internet connectivity.
|
|
7
|
+
//
|
|
8
|
+
// Features demonstrated:
|
|
9
|
+
// - Automatic bridge discovery
|
|
10
|
+
// - Bridge selection awareness
|
|
11
|
+
// - Message routing to best available bridge
|
|
12
|
+
// - Failover handling
|
|
13
|
+
//************************************************************
|
|
14
|
+
|
|
15
|
+
#include "painlessMesh.h"
|
|
16
|
+
|
|
17
|
+
#define MESH_PREFIX "MultiBridgeMesh"
|
|
18
|
+
#define MESH_PASSWORD "meshpassword"
|
|
19
|
+
#define MESH_PORT 5555
|
|
20
|
+
|
|
21
|
+
Scheduler userScheduler;
|
|
22
|
+
painlessMesh mesh;
|
|
23
|
+
|
|
24
|
+
// Simulated sensor data
|
|
25
|
+
float temperature = 22.5;
|
|
26
|
+
float humidity = 45.0;
|
|
27
|
+
|
|
28
|
+
// Task to send sensor data
|
|
29
|
+
Task taskSendMessage(5000, TASK_FOREVER, [](){
|
|
30
|
+
// Simulate sensor readings
|
|
31
|
+
temperature += (random(-10, 10) / 10.0);
|
|
32
|
+
humidity += (random(-50, 50) / 10.0);
|
|
33
|
+
|
|
34
|
+
String msg = "Temperature: " + String(temperature, 1) + "°C, Humidity: " + String(humidity, 1) + "%";
|
|
35
|
+
|
|
36
|
+
Serial.println("\n--- Sending Sensor Data ---");
|
|
37
|
+
|
|
38
|
+
// Get recommended bridge
|
|
39
|
+
uint32_t recommendedBridge = mesh.getRecommendedBridge();
|
|
40
|
+
|
|
41
|
+
if (recommendedBridge != 0) {
|
|
42
|
+
Serial.printf("Recommended Bridge: %u\n", recommendedBridge);
|
|
43
|
+
Serial.printf("Message: %s\n", msg.c_str());
|
|
44
|
+
|
|
45
|
+
// Send to specific bridge
|
|
46
|
+
mesh.sendSingle(recommendedBridge, msg);
|
|
47
|
+
Serial.println("✓ Sent to bridge");
|
|
48
|
+
} else {
|
|
49
|
+
Serial.println("⚠️ No bridge available!");
|
|
50
|
+
Serial.println("Message queued for later delivery");
|
|
51
|
+
// In production, you would queue this message
|
|
52
|
+
}
|
|
53
|
+
Serial.println("---------------------------\n");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Task to display network status
|
|
57
|
+
Task taskNetworkStatus(15000, TASK_FOREVER, [](){
|
|
58
|
+
Serial.println("\n=== Network Status ===");
|
|
59
|
+
Serial.printf("Node ID: %u\n", mesh.getNodeId());
|
|
60
|
+
Serial.printf("Connected Nodes: %d\n", mesh.getNodeList().size());
|
|
61
|
+
|
|
62
|
+
// Show all active bridges
|
|
63
|
+
auto activeBridges = mesh.getActiveBridges();
|
|
64
|
+
Serial.printf("Active Bridges: %d\n", activeBridges.size());
|
|
65
|
+
|
|
66
|
+
if (activeBridges.empty()) {
|
|
67
|
+
Serial.println(" ⚠️ NO BRIDGES AVAILABLE");
|
|
68
|
+
} else {
|
|
69
|
+
for (auto bridgeId : activeBridges) {
|
|
70
|
+
Serial.printf(" - Bridge: %u\n", bridgeId);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Check Internet connectivity
|
|
75
|
+
bool hasInternet = mesh.hasInternetConnection();
|
|
76
|
+
Serial.printf("Internet Available: %s\n", hasInternet ? "YES" : "NO");
|
|
77
|
+
|
|
78
|
+
Serial.println("======================\n");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
void receivedCallback(uint32_t from, String& msg) {
|
|
82
|
+
Serial.printf("📨 Received from %u: %s\n", from, msg.c_str());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
void newConnectionCallback(uint32_t nodeId) {
|
|
86
|
+
Serial.printf("🔗 New Connection: %u\n", nodeId);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
void changedConnectionCallback() {
|
|
90
|
+
Serial.printf("🔄 Connections changed. Total nodes: %d\n", mesh.getNodeList().size());
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
void bridgeStatusCallback(uint32_t bridgeNodeId, bool hasInternet) {
|
|
94
|
+
Serial.printf("\n🌉 Bridge Status Update: Bridge %u - Internet %s\n",
|
|
95
|
+
bridgeNodeId, hasInternet ? "CONNECTED" : "OFFLINE");
|
|
96
|
+
|
|
97
|
+
if (hasInternet) {
|
|
98
|
+
Serial.println("✓ Internet connection available");
|
|
99
|
+
} else {
|
|
100
|
+
Serial.println("⚠️ Bridge lost Internet - checking for alternatives...");
|
|
101
|
+
|
|
102
|
+
auto activeBridges = mesh.getActiveBridges();
|
|
103
|
+
if (activeBridges.empty()) {
|
|
104
|
+
Serial.println("⚠️ No alternative bridges available!");
|
|
105
|
+
} else {
|
|
106
|
+
Serial.printf("✓ %d alternative bridge(s) available\n", activeBridges.size());
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
void setup() {
|
|
112
|
+
Serial.begin(115200);
|
|
113
|
+
delay(2000);
|
|
114
|
+
|
|
115
|
+
Serial.println("\n\n=== Multi-Bridge: REGULAR NODE ===\n");
|
|
116
|
+
|
|
117
|
+
// Initialize as regular mesh node
|
|
118
|
+
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
119
|
+
|
|
120
|
+
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
|
|
121
|
+
|
|
122
|
+
mesh.onReceive(&receivedCallback);
|
|
123
|
+
mesh.onNewConnection(&newConnectionCallback);
|
|
124
|
+
mesh.onChangedConnections(&changedConnectionCallback);
|
|
125
|
+
mesh.onBridgeStatusChanged(&bridgeStatusCallback);
|
|
126
|
+
|
|
127
|
+
// Add tasks
|
|
128
|
+
userScheduler.addTask(taskSendMessage);
|
|
129
|
+
userScheduler.addTask(taskNetworkStatus);
|
|
130
|
+
taskSendMessage.enable();
|
|
131
|
+
taskNetworkStatus.enable();
|
|
132
|
+
|
|
133
|
+
Serial.println("\n=== Regular Node Ready ===");
|
|
134
|
+
Serial.println("This node will automatically discover and use available bridges");
|
|
135
|
+
Serial.println("In multi-bridge mode, it will use the highest priority bridge");
|
|
136
|
+
Serial.println("If primary fails, it automatically switches to secondary\n");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
void loop() {
|
|
140
|
+
mesh.update();
|
|
141
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
//************************************************************
|
|
2
|
+
// Multi-Bridge Example: Secondary Bridge Node
|
|
3
|
+
//
|
|
4
|
+
// This example demonstrates a secondary bridge (priority 5) in a
|
|
5
|
+
// multi-bridge deployment. This provides hot standby redundancy
|
|
6
|
+
// and can handle load if the primary bridge is busy.
|
|
7
|
+
//
|
|
8
|
+
// Features demonstrated:
|
|
9
|
+
// - Secondary bridge with medium priority
|
|
10
|
+
// - Hot standby mode (always ready)
|
|
11
|
+
// - Automatic failover if primary fails
|
|
12
|
+
// - Load balancing support
|
|
13
|
+
//************************************************************
|
|
14
|
+
|
|
15
|
+
#include "painlessMesh.h"
|
|
16
|
+
|
|
17
|
+
#define MESH_PREFIX "MultiBridgeMesh"
|
|
18
|
+
#define MESH_PASSWORD "meshpassword"
|
|
19
|
+
#define MESH_PORT 5555
|
|
20
|
+
|
|
21
|
+
// Secondary router connection (backup Internet or different ISP)
|
|
22
|
+
#define ROUTER_SSID "SecondaryRouter"
|
|
23
|
+
#define ROUTER_PASSWORD "routerpass2"
|
|
24
|
+
|
|
25
|
+
Scheduler userScheduler;
|
|
26
|
+
painlessMesh mesh;
|
|
27
|
+
|
|
28
|
+
// Task to display bridge coordination status
|
|
29
|
+
Task taskBridgeStatus(10000, TASK_FOREVER, [](){
|
|
30
|
+
Serial.println("\n=== Secondary Bridge Status ===");
|
|
31
|
+
Serial.printf("Node ID: %u\n", mesh.getNodeId());
|
|
32
|
+
Serial.printf("Connected Nodes: %d\n", mesh.getNodeList().size());
|
|
33
|
+
|
|
34
|
+
// Show all active bridges in the mesh
|
|
35
|
+
auto activeBridges = mesh.getActiveBridges();
|
|
36
|
+
Serial.printf("Active Bridges: %d\n", activeBridges.size());
|
|
37
|
+
for (auto bridgeId : activeBridges) {
|
|
38
|
+
Serial.printf(" - Bridge: %u%s\n", bridgeId,
|
|
39
|
+
(bridgeId == mesh.getNodeId()) ? " (ME)" : "");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Show recommended bridge for next message
|
|
43
|
+
uint32_t recommended = mesh.getRecommendedBridge();
|
|
44
|
+
Serial.printf("Recommended Bridge: %u\n", recommended);
|
|
45
|
+
|
|
46
|
+
if (recommended == mesh.getNodeId()) {
|
|
47
|
+
Serial.println("⚠️ I AM THE ACTIVE BRIDGE (primary likely failed!)");
|
|
48
|
+
} else {
|
|
49
|
+
Serial.println("✓ Standby mode - primary bridge is active");
|
|
50
|
+
}
|
|
51
|
+
Serial.println("=============================\n");
|
|
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, nodeId = %u\n", nodeId);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
void changedConnectionCallback() {
|
|
63
|
+
Serial.printf("Changed connections. Node count: %d\n", mesh.getNodeList().size());
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void bridgeStatusCallback(uint32_t bridgeNodeId, bool hasInternet) {
|
|
67
|
+
if (hasInternet) {
|
|
68
|
+
Serial.printf("✓ Bridge %u: Internet connected\n", bridgeNodeId);
|
|
69
|
+
} else {
|
|
70
|
+
Serial.printf("⚠️ Bridge %u: Internet OFFLINE\n", bridgeNodeId);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
void setup() {
|
|
75
|
+
Serial.begin(115200);
|
|
76
|
+
delay(2000);
|
|
77
|
+
|
|
78
|
+
Serial.println("\n\n=== Multi-Bridge: SECONDARY BRIDGE ===\n");
|
|
79
|
+
|
|
80
|
+
// Initialize mesh as secondary bridge with priority 5
|
|
81
|
+
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
82
|
+
|
|
83
|
+
// Enable multi-bridge coordination mode
|
|
84
|
+
mesh.enableMultiBridge(true);
|
|
85
|
+
|
|
86
|
+
// Set bridge selection strategy (PRIORITY_BASED is default)
|
|
87
|
+
mesh.setBridgeSelectionStrategy(painlessMesh::PRIORITY_BASED);
|
|
88
|
+
|
|
89
|
+
// Initialize as bridge with priority 5 (secondary)
|
|
90
|
+
mesh.initAsBridge(MESH_PREFIX, MESH_PASSWORD,
|
|
91
|
+
ROUTER_SSID, ROUTER_PASSWORD,
|
|
92
|
+
&userScheduler, MESH_PORT, 5); // Priority 5 = Secondary
|
|
93
|
+
|
|
94
|
+
mesh.onReceive(&receivedCallback);
|
|
95
|
+
mesh.onNewConnection(&newConnectionCallback);
|
|
96
|
+
mesh.onChangedConnections(&changedConnectionCallback);
|
|
97
|
+
mesh.onBridgeStatusChanged(&bridgeStatusCallback);
|
|
98
|
+
|
|
99
|
+
// Add status reporting task
|
|
100
|
+
userScheduler.addTask(taskBridgeStatus);
|
|
101
|
+
taskBridgeStatus.enable();
|
|
102
|
+
|
|
103
|
+
Serial.println("\n=== Secondary Bridge Ready ===");
|
|
104
|
+
Serial.println("This node is the SECONDARY bridge (Priority 5)");
|
|
105
|
+
Serial.println("It operates in hot standby mode");
|
|
106
|
+
Serial.println("Will take over if primary bridge fails\n");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
void loop() {
|
|
110
|
+
mesh.update();
|
|
111
|
+
}
|