@alteriom/painlessmesh 1.8.0 ā 1.8.1
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 +24 -0
- package/README.md +51 -11
- 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 +1 -1
- 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
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.8.1] - 2025-11-10
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **GitHub Copilot Custom Agent Support** - Custom agent configuration now discoverable by GitHub
|
|
15
|
+
- Moved `copilot-agents.json` to repository root for automatic GitHub Copilot integration
|
|
16
|
+
- Release Agent now available as `@release-agent` in GitHub Copilot Chat (Enterprise)
|
|
17
|
+
- Enhanced repository context for all GitHub Copilot users
|
|
18
|
+
- Complete agent documentation in `.github/agents/` directory
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **Documentation Updates** - Improved clarity for custom agent setup
|
|
23
|
+
- Updated `COPILOT_AGENT_SETUP.md` with root file location
|
|
24
|
+
- Enhanced `AGENTS_INDEX.md` with discovery information
|
|
25
|
+
- Added examples for using custom agents in development workflow
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- **Custom Agent Visibility** - Resolved issue where custom agent tasks were not showing in GitHub
|
|
30
|
+
- GitHub Copilot now automatically discovers the release agent configuration
|
|
31
|
+
- Agent appears in Copilot Chat suggestions when available
|
|
32
|
+
- Knowledge sources properly linked for enhanced context
|
|
33
|
+
|
|
10
34
|
## [1.8.0] - 2025-11-09
|
|
11
35
|
|
|
12
36
|
### Added
|
package/README.md
CHANGED
|
@@ -391,23 +391,29 @@ See [BRIDGE_TO_INTERNET.md](BRIDGE_TO_INTERNET.md) for complete documentation.
|
|
|
391
391
|
- **Event Coordination** - Synchronized displays, distributed processing
|
|
392
392
|
- **Bridge Networks** - Connect mesh to WiFi/Internet/MQTT - [š Bridge Guide](BRIDGE_TO_INTERNET.md)
|
|
393
393
|
|
|
394
|
-
##
|
|
394
|
+
## Latest Release: v1.8.1 (November 10, 2025)
|
|
395
395
|
|
|
396
|
-
**
|
|
396
|
+
**GitHub Copilot Integration & Developer Experience**:
|
|
397
397
|
|
|
398
|
-
|
|
398
|
+
- š¤ **GitHub Copilot Custom Agent** - AI-assisted release management with `@release-agent`
|
|
399
|
+
- š **Enhanced Developer Context** - Improved repository context for all Copilot users
|
|
400
|
+
- ā
**Release Automation** - 21+ automated validation checks for quality assurance
|
|
401
|
+
- š§ **Zero Breaking Changes** - Purely additive developer experience improvements
|
|
402
|
+
- š **Complete Documentation** - Agent setup guides and knowledge sources
|
|
399
403
|
|
|
400
|
-
|
|
404
|
+
**[š Full Release Notes](RELEASE_NOTES_v1.8.1.md)** | **[š CHANGELOG](CHANGELOG.md)**
|
|
401
405
|
|
|
402
|
-
|
|
406
|
+
## Previous Release: v1.8.0 (November 9, 2025)
|
|
403
407
|
|
|
404
|
-
-
|
|
405
|
-
- ā
**HealthCheckPackage (Type 605)** - Proactive health monitoring with problem detection
|
|
406
|
-
- ā
**Mesh Topology Packages** - Complete network visualization (Types 600-603)
|
|
407
|
-
- ā
**Enhanced MQTT Bridge** - On-demand metrics, health checks, and aggregated statistics
|
|
408
|
-
- ā
**100% Backward Compatible** - All existing code continues to work
|
|
408
|
+
**Bridge-Centric Architecture & Comprehensive Monitoring**:
|
|
409
409
|
|
|
410
|
-
|
|
410
|
+
- ā
**Bridge Auto-Detection** - One-line bridge setup with automatic channel detection
|
|
411
|
+
- š **Diagnostics API** - Comprehensive monitoring and debugging tools
|
|
412
|
+
- š **RTC Integration** - Hardware RTC support for offline timekeeping
|
|
413
|
+
- š **Bridge Failover** - Automatic bridge election and high availability
|
|
414
|
+
- ā” **Production Ready** - All features tested, documented, and backward compatible
|
|
415
|
+
|
|
416
|
+
**[š Full Release Notes](RELEASE_NOTES_v1.8.0.md)**
|
|
411
417
|
|
|
412
418
|
## Getting Help
|
|
413
419
|
|
|
@@ -418,6 +424,40 @@ See [CHANGELOG](CHANGELOG.md) for upcoming changes.
|
|
|
418
424
|
|
|
419
425
|
## Development
|
|
420
426
|
|
|
427
|
+
### GitHub Copilot Integration (v1.8.1+)
|
|
428
|
+
|
|
429
|
+
AlteriomPainlessMesh includes GitHub Copilot custom agent support for AI-assisted development:
|
|
430
|
+
|
|
431
|
+
- **š¤ Release Agent** - AI assistant for release management and quality assurance
|
|
432
|
+
- **š Enhanced Context** - Repository knowledge available to all Copilot users
|
|
433
|
+
- **šÆ Enterprise Features** - Use `@release-agent` in Copilot Chat (Enterprise)
|
|
434
|
+
|
|
435
|
+
**For GitHub Copilot Enterprise Users:**
|
|
436
|
+
```
|
|
437
|
+
@release-agent How do I prepare a release?
|
|
438
|
+
@release-agent Check version consistency
|
|
439
|
+
@release-agent Validate release readiness
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**Configuration:** The custom agent is defined in `copilot-agents.json` at the repository root.
|
|
443
|
+
|
|
444
|
+
**Documentation:** [Copilot Agent Setup](.github/COPILOT_AGENT_SETUP.md) | [Agent Index](.github/AGENTS_INDEX.md)
|
|
445
|
+
|
|
446
|
+
### Release Agent & Automation
|
|
447
|
+
|
|
448
|
+
AlteriomPainlessMesh includes a comprehensive release automation system:
|
|
449
|
+
|
|
450
|
+
- **š [Release Agent Documentation](.github/agents/release-agent.md)** - Complete release process specification
|
|
451
|
+
- **š¤ Release Validation Script**: `./scripts/release-agent.sh` - Automated pre-release checks
|
|
452
|
+
- **āļø CI/CD Integration**: Workflows validate every release automatically
|
|
453
|
+
|
|
454
|
+
**Quick Release Validation:**
|
|
455
|
+
```bash
|
|
456
|
+
./scripts/release-agent.sh # Run all pre-release checks
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
See [Release Agent Guide](.github/agents/README.md) for complete documentation.
|
|
460
|
+
|
|
421
461
|
### Building from Source
|
|
422
462
|
|
|
423
463
|
```bash
|
|
@@ -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
|
+
}
|