@alteriom/painlessmesh 1.8.14 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BRIDGE_TO_INTERNET.md +229 -0
- package/CHANGELOG.md +89 -1
- package/CONTRIBUTING.md +79 -0
- package/README.md +70 -143
- package/docs/README.md +1 -0
- package/docs/api/shared-gateway.md +1207 -0
- package/docs/troubleshooting/common-issues.md +28 -0
- package/docs/troubleshooting/faq.md +113 -12
- package/examples/basic/test/simulator/CMakeLists.txt +40 -0
- package/examples/basic/test/simulator/README.md +149 -0
- package/examples/basic/test/simulator/firmware/basic_firmware.hpp +117 -0
- package/examples/basic/test/simulator/scenarios/basic_mesh_test.yaml +81 -0
- package/examples/bridge/bridge.ino +17 -4
- package/examples/bridge_failover/README.md +81 -0
- package/examples/bridge_failover/bridge_failover.ino +51 -6
- package/examples/sharedGateway/README.md +235 -0
- package/examples/{meshCommandNode → sharedGateway}/platformio.ini +3 -2
- package/examples/sharedGateway/sharedGateway.ino +303 -0
- package/library.json +3 -22
- package/library.properties +1 -1
- package/package.json +3 -3
- package/src/arduino/wifi.hpp +380 -13
- package/src/painlessmesh/gateway.hpp +2120 -0
- package/src/painlessmesh/mesh.hpp +1034 -6
- package/src/painlessmesh/message_tracker.hpp +311 -0
- package/src/painlessmesh/protocol.hpp +6 -0
- package/DOCUMENTATION_INDEX.md +0 -146
- package/docs/API_DESIGN_GUIDELINES.md +0 -414
- package/docs/ARDUINO_LIBRARY_MANAGER_SUBMISSION.md +0 -331
- package/docs/BOOLEAN_NAMING_CONVENTION.md +0 -235
- package/docs/BRIDGE_FAILOVER.md +0 -512
- package/docs/BRIDGE_HEALTH_MONITORING.md +0 -293
- package/docs/CHANNEL_SYNCHRONIZATION.md +0 -209
- package/docs/CREATE_MISSING_RELEASES.md +0 -321
- package/docs/DOCUMENTATION_MIGRATION_PLAN.md +0 -176
- package/docs/FAQ_VERSION_NUMBERS.md +0 -152
- package/docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md +0 -1062
- package/docs/MESH_TOPOLOGY_GUIDE.md +0 -992
- package/docs/MESH_TOPOLOGY_PROGRESS.md +0 -422
- package/docs/MQTT_BRIDGE_COMMANDS.md +0 -894
- package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +0 -324
- package/docs/MQTT_COMMAND_SCHEMA_PROPOSAL.md +0 -576
- package/docs/MQTT_SCHEMA_COMPLIANCE.md +0 -340
- package/docs/MQTT_SCHEMA_PROPOSALS.md +0 -446
- package/docs/MQTT_SCHEMA_REVIEW.md +0 -690
- package/docs/OTA_COMMANDS_REFERENCE.md +0 -554
- package/docs/PHASE1_GUIDE.md +0 -349
- package/docs/PHASE2_GUIDE.md +0 -543
- package/docs/QUICK_REFERENCE_VERSIONING.md +0 -127
- package/docs/RELEASE_AGENT_SUMMARY.md +0 -386
- package/docs/SCHEMA_VALIDATION_CHECKLIST.md +0 -222
- package/docs/VERSION_MANAGEMENT.md +0 -213
- package/docs/archive/DOCUSAURUS_DEPLOYMENT.md +0 -166
- package/docs/archive/FEATURE_PROPOSALS.md +0 -337
- package/docs/archive/LIBRARY_JSON_FIX.md +0 -98
- package/docs/archive/LIBRARY_STRUCTURE_FIX.md +0 -215
- package/docs/archive/PHASE1_IMPLEMENTATION.md +0 -325
- package/docs/archive/PHASE2_IMPLEMENTATION.md +0 -567
- package/docs/archive/RELEASE_SUMMARY.md +0 -173
- package/docs/archive/SCONS_BUILD_FIX.md +0 -313
- package/docs/archive/TRIGGER_RELEASE.md +0 -280
- package/docs/archive/VECTOR_INCLUDE_FIX.md +0 -129
- package/docs/archive/ota-and-status-enhancements.md +0 -911
- package/docs/archive/ota-status-architecture-diagrams.md +0 -658
- package/docs/archive/ota-status-quick-reference.md +0 -284
- package/docs/design/.gitkeep +0 -1
- package/docs/design/STATION_CREDENTIALS_DESIGN.md +0 -182
- package/docs/development/ARDUINO_COMPLIANCE_SUMMARY.md +0 -71
- package/docs/development/CODE_REFACTORING_RECOMMENDATIONS.md +0 -1011
- package/docs/development/DOCKER_TESTING.md +0 -196
- package/docs/development/PLATFORMIO_USAGE.md +0 -180
- package/docs/development/TESTING_SUMMARY.md +0 -126
- package/docs/development/contributing.md +0 -301
- package/docs/development/documentation.md +0 -583
- package/docs/features/DIAGNOSTICS_API.md +0 -534
- package/docs/implementation/BRIDGE_ARCHITECTURE_IMPLEMENTATION.md +0 -340
- package/docs/implementation/BRIDGE_HEALTH_MONITORING_IMPLEMENTATION.md +0 -213
- package/docs/implementation/BRIDGE_STATUS_FEATURE.md +0 -635
- package/docs/implementation/DIAGNOSTICS_API_IMPLEMENTATION.md +0 -232
- package/docs/implementation/IMPLEMENTATION_COMPLETE.md +0 -228
- package/docs/implementation/IMPLEMENTATION_NTP_TIME_SYNC.md +0 -325
- package/docs/implementation/IMPLEMENTATION_SUMMARY.md +0 -316
- package/docs/implementation/MESSAGE_QUEUE_IMPLEMENTATION.md +0 -405
- package/docs/implementation/MULTI_BRIDGE_IMPLEMENTATION.md +0 -520
- package/docs/implementation/NTP_TIME_SYNC_FEATURE.md +0 -392
- package/docs/improvements/FUTURE_PROPOSALS.md +0 -1016
- package/docs/improvements/IMPLEMENTATION_HISTORY.md +0 -1091
- package/docs/improvements/OTA_STATUS_ENHANCEMENTS.md +0 -709
- package/docs/improvements/README.md +0 -212
- package/docs/internal/CUSTOM_AGENT_ANALYSIS.md +0 -391
- package/docs/internal/ISSUE_65_VERIFICATION.md +0 -947
- package/docs/internal/ISSUE_66_CLOSURE.md +0 -249
- package/docs/internal/ISSUE_66_STATUS.md +0 -316
- package/docs/internal/PR_SUMMARY.md +0 -315
- package/docs/internal/REVIEW_SUMMARY.md +0 -332
- package/docs/multi-bridge-setup.md +0 -1025
- package/docs/platformio-publishing.md +0 -255
- package/docs/platformio-setup-summary.md +0 -121
- package/docs/releases/ANNOUNCEMENT_v1.8.6.md +0 -63
- package/docs/releases/ANNOUNCEMENT_v1.8.7.md +0 -113
- package/docs/releases/BRIDGE_STATUS_SELF_REGISTRATION_FIX.md +0 -221
- package/docs/releases/FEATURE_HISTORY.md +0 -543
- package/docs/releases/GITHUB_RELEASE_v1.8.6.md +0 -71
- package/docs/releases/GITHUB_RELEASE_v1.8.7.md +0 -90
- package/docs/releases/PATCH_v1.7.2.md +0 -262
- package/docs/releases/PATCH_v1.7.3.md +0 -262
- package/docs/releases/PATCH_v1.7.4.md +0 -219
- package/docs/releases/PHASE1_SUMMARY.md +0 -246
- package/docs/releases/PHASE2_SUMMARY.md +0 -499
- package/docs/releases/PUBLISH_v1.8.0_INSTRUCTIONS.md +0 -163
- package/docs/releases/QUICK_START_RELEASES.md +0 -113
- package/docs/releases/RELEASE_CHECKLIST_1.8.10.md +0 -331
- package/docs/releases/RELEASE_CHECKLIST_1.8.9.md +0 -207
- package/docs/releases/RELEASE_CHECKLIST_v1.7.4.md +0 -253
- package/docs/releases/RELEASE_CHECKLIST_v1.7.5.md +0 -315
- package/docs/releases/RELEASE_CHECKLIST_v1.7.6.md +0 -389
- package/docs/releases/RELEASE_CHECKLIST_v1.8.0.md +0 -331
- package/docs/releases/RELEASE_CHECKLIST_v1.8.2.md +0 -309
- package/docs/releases/RELEASE_NOTES_1.7.0.md +0 -539
- package/docs/releases/RELEASE_NOTES_1.8.10.md +0 -239
- package/docs/releases/RELEASE_NOTES_1.8.9.md +0 -213
- package/docs/releases/RELEASE_NOTES_v1.8.0.md +0 -685
- package/docs/releases/RELEASE_NOTES_v1.8.1.md +0 -221
- package/docs/releases/RELEASE_NOTES_v1.8.2.md +0 -421
- package/docs/releases/RELEASE_NOTES_v1.8.3.md +0 -292
- package/docs/releases/RELEASE_NOTES_v1.8.4.md +0 -277
- package/docs/releases/RELEASE_NOTES_v1.8.6.md +0 -205
- package/docs/releases/RELEASE_NOTES_v1.8.7.md +0 -184
- package/docs/releases/RELEASE_PLAN_v1.7.6.md +0 -816
- package/docs/releases/RELEASE_SUMMARY_1.8.10.md +0 -193
- package/docs/releases/RELEASE_SUMMARY_v1.7.4.md +0 -276
- package/docs/releases/RELEASE_SUMMARY_v1.7.5.md +0 -322
- package/docs/releases/RELEASE_SUMMARY_v1.7.6.md +0 -436
- package/docs/releases/RELEASE_SUMMARY_v1.7.7.md +0 -391
- package/docs/releases/RELEASE_SUMMARY_v1.7.8.md +0 -523
- package/docs/releases/RELEASE_SUMMARY_v1.7.9.md +0 -542
- package/docs/troubleshooting/ARDUINO_IDE_VERSION_FIX_SUMMARY.md +0 -229
- package/docs/troubleshooting/ARDUINO_LIBRARY_NAME_FIX.md +0 -197
- package/docs/troubleshooting/CRASH_QUICK_REF.md +0 -93
- package/docs/troubleshooting/ESP32_C6_COMPATIBILITY.md +0 -157
- package/docs/troubleshooting/FREERTOS_ASSERTION_FAILURE.md +0 -288
- package/docs/troubleshooting/FREERTOS_FIX_IMPLEMENTATION.md +0 -267
- package/docs/troubleshooting/NPM_PUBLISHING_ISSUE_SUMMARY.md +0 -110
- package/docs/troubleshooting/PAINLESSMESH_V1.7.4_COMPILATION_ISSUES.md +0 -547
- package/docs/troubleshooting/QUICK_FIX_FREERTOS.md +0 -164
- package/docs/troubleshooting/SENSOR_NODE_CONNECTION_CRASH.md +0 -264
- package/docs/troubleshooting/station-reconnection-issues.md +0 -172
- package/docs/v1.7.7_MQTT_IMPROVEMENTS.md +0 -794
- package/docs/wiki/API-Reference.md +0 -246
- package/docs/wiki/Complete-Documentation.md +0 -123
- package/examples/alteriomImproved/alteriom_sensor_package.hpp +0 -224
- package/examples/alteriomImproved/improved_sensor_node.ino +0 -248
- package/examples/alteriomImproved/platformio.ini +0 -32
- package/examples/alteriomMetricsHealth/alteriom_sensor_package.hpp +0 -796
- package/examples/alteriomMetricsHealth/metrics_health_node.ino +0 -429
- package/examples/alteriomMetricsHealth/platformio.ini +0 -26
- package/examples/alteriomPhase1/alteriom_sensor_package.hpp +0 -224
- package/examples/alteriomPhase1/phase1_features.ino +0 -242
- package/examples/alteriomPhase1/platformio.ini +0 -26
- package/examples/alteriomPhase2/alteriom_sensor_package.hpp +0 -224
- package/examples/alteriomPhase2/phase2_features.ino +0 -186
- package/examples/alteriomPhase2/platformio.ini +0 -26
- package/examples/alteriomSensorNode/alteriom_sensor_node.ino +0 -186
- package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +0 -1227
- package/examples/alteriomSensorNode/platformio.ini +0 -26
- package/examples/bridge/alteriom_sensor_package.hpp +0 -1170
- package/examples/bridge/bridge_health_monitoring_example.ino +0 -188
- package/examples/bridge/enhanced_mqtt_bridge.hpp +0 -610
- package/examples/bridge/enhanced_mqtt_bridge_example.ino +0 -226
- package/examples/bridge/mesh_event_publisher.hpp +0 -253
- package/examples/bridge/mesh_topology_reporter.hpp +0 -303
- package/examples/bridge/mqtt_command_bridge.hpp +0 -459
- package/examples/bridge/mqtt_status_bridge.hpp +0 -519
- package/examples/bridgeAwareSensorNode/alteriom_sensor_package.hpp +0 -1227
- package/examples/bridgeAwareSensorNode/bridgeAwareSensorNode.ino +0 -342
- package/examples/bridgeAwareSensorNode/platformio.ini +0 -26
- package/examples/diagnosticsExample/diagnosticsExample.ino +0 -171
- package/examples/diagnosticsExample/platformio.ini +0 -26
- package/examples/echoNode/echoNode.ino +0 -33
- package/examples/echoNode/platformio.ini +0 -26
- package/examples/meshCommandNode/alteriom_sensor_package.hpp +0 -235
- package/examples/meshCommandNode/meshCommandNode.ino +0 -265
- package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +0 -235
- package/examples/mqttCommandBridge/mesh_event_publisher.hpp +0 -253
- package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +0 -303
- package/examples/mqttCommandBridge/mqttCommandBridge.ino +0 -254
- package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +0 -462
- package/examples/mqttCommandBridge/platformio.ini +0 -27
- package/examples/mqttStatusBridge/mqttStatusBridge.ino +0 -218
- package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +0 -522
- package/examples/mqttStatusBridge/platformio.ini +0 -27
- package/examples/mqttTopologyTest/README.md +0 -467
- package/examples/mqttTopologyTest/mqttTopologyTest.ino +0 -754
- package/examples/mqttTopologyTest/platformio.ini +0 -27
- package/examples/multi_bridge/README.md +0 -346
- package/examples/multi_bridge/primary_bridge.ino +0 -96
- package/examples/multi_bridge/regular_node.ino +0 -141
- package/examples/multi_bridge/secondary_bridge.ino +0 -111
- package/examples/ntpTimeSyncBridge/alteriom_sensor_package.hpp +0 -1383
- package/examples/ntpTimeSyncBridge/ntpTimeSyncBridge.ino +0 -86
- package/examples/ntpTimeSyncNode/alteriom_sensor_package.hpp +0 -1383
- package/examples/ntpTimeSyncNode/ntpTimeSyncNode.ino +0 -109
- package/examples/queued_alarms/README.md +0 -390
- package/examples/queued_alarms/queued_alarms.ino +0 -265
- package/examples/routing_demo/README.md +0 -172
- package/examples/routing_demo/routing_demo.ino +0 -102
- package/examples/rtcIntegration/README.md +0 -294
- package/examples/rtcIntegration/rtcIntegration.ino +0 -210
|
@@ -0,0 +1,1207 @@
|
|
|
1
|
+
# Shared Gateway Mode API Reference
|
|
2
|
+
|
|
3
|
+
> **Version:** v1.9.0+
|
|
4
|
+
> **Status:** Implemented
|
|
5
|
+
> **Author:** AlteriomPainlessMesh Team
|
|
6
|
+
|
|
7
|
+
This document provides comprehensive API reference for the Shared Gateway Mode feature in painlessMesh.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
1. [Overview](#overview)
|
|
14
|
+
2. [Quick Start](#quick-start)
|
|
15
|
+
3. [API Reference](#api-reference)
|
|
16
|
+
4. [Configuration](#configuration)
|
|
17
|
+
5. [Package Types](#package-types)
|
|
18
|
+
6. [Advanced Usage](#advanced-usage)
|
|
19
|
+
7. [Troubleshooting](#troubleshooting)
|
|
20
|
+
8. [Performance](#performance)
|
|
21
|
+
9. [Migration](#migration)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Overview
|
|
26
|
+
|
|
27
|
+
### What is Shared Gateway Mode?
|
|
28
|
+
|
|
29
|
+
Shared Gateway Mode is a painlessMesh feature that enables **all nodes** in a mesh network to connect to the same WiFi router while maintaining mesh connectivity. Unlike Bridge Mode where only one dedicated node connects to the router, Shared Gateway Mode allows every node to potentially send data directly to the Internet.
|
|
30
|
+
|
|
31
|
+
### Architecture Diagram
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
Internet
|
|
35
|
+
│
|
|
36
|
+
Router (shared SSID)
|
|
37
|
+
┌─────────────┼─────────────┐
|
|
38
|
+
│ │ │
|
|
39
|
+
Node A Node B Node C
|
|
40
|
+
(STA+AP) (STA+AP) (STA+AP)
|
|
41
|
+
[Primary] [Backup] [Backup]
|
|
42
|
+
│ │ │
|
|
43
|
+
└─────────────┼─────────────┘
|
|
44
|
+
Mesh Network
|
|
45
|
+
|
|
46
|
+
Legend:
|
|
47
|
+
- STA: Station connection to router (Internet access)
|
|
48
|
+
- AP: Access point for mesh network
|
|
49
|
+
- [Primary]: Elected primary gateway for relayed messages
|
|
50
|
+
- [Backup]: Backup gateway, can relay if primary fails
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Key Benefits
|
|
54
|
+
|
|
55
|
+
| Benefit | Description |
|
|
56
|
+
|---------|-------------|
|
|
57
|
+
| **Redundant Internet Access** | All nodes can send data to the Internet, eliminating single points of failure |
|
|
58
|
+
| **Automatic Failover** | If a node's Internet connection fails, data routes through the mesh to find a working gateway |
|
|
59
|
+
| **Simplified Deployment** | No dedicated bridge node required; any node can serve as gateway |
|
|
60
|
+
| **Load Distribution** | Internet traffic can be distributed across multiple nodes |
|
|
61
|
+
| **Resilient Architecture** | Mesh continues to function even if individual router connections fail |
|
|
62
|
+
|
|
63
|
+
### Use Cases
|
|
64
|
+
|
|
65
|
+
- **Fish Farm Monitoring**: Critical O₂ alarms can reach the cloud through any available path
|
|
66
|
+
- **Industrial Sensor Networks**: Sensor data reliably uploaded even during partial network outages
|
|
67
|
+
- **Smart Building Systems**: HVAC and security data maintains connectivity through redundant paths
|
|
68
|
+
- **Remote Monitoring**: Environmental stations with spotty Internet can relay through nearby nodes
|
|
69
|
+
|
|
70
|
+
### Comparison: Bridge Mode vs Shared Gateway Mode
|
|
71
|
+
|
|
72
|
+
| Aspect | Bridge Mode | Shared Gateway Mode |
|
|
73
|
+
|--------|-------------|---------------------|
|
|
74
|
+
| Internet Access | Bridge node only | All nodes |
|
|
75
|
+
| Router Connection | Bridge node only | All nodes |
|
|
76
|
+
| WiFi Mode | AP+STA (bridge only) | AP+STA (all nodes) |
|
|
77
|
+
| Failover Time | 60-70 seconds (election) | Near-instant relay |
|
|
78
|
+
| Primary Gateway | Fixed (bridge) | Elected dynamically |
|
|
79
|
+
| Duplicate Prevention | Not required | Built-in |
|
|
80
|
+
| Single Point of Failure | Yes (bridge node) | No |
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Quick Start
|
|
85
|
+
|
|
86
|
+
### Basic Setup Example
|
|
87
|
+
|
|
88
|
+
```cpp
|
|
89
|
+
#include "painlessMesh.h"
|
|
90
|
+
|
|
91
|
+
// Mesh network configuration
|
|
92
|
+
#define MESH_PREFIX "SharedGatewayMesh"
|
|
93
|
+
#define MESH_PASSWORD "meshPassword123"
|
|
94
|
+
#define MESH_PORT 5555
|
|
95
|
+
|
|
96
|
+
// Router configuration (all nodes connect to same router)
|
|
97
|
+
#define ROUTER_SSID "YourRouterSSID"
|
|
98
|
+
#define ROUTER_PASSWORD "YourRouterPassword"
|
|
99
|
+
|
|
100
|
+
Scheduler userScheduler;
|
|
101
|
+
painlessMesh mesh;
|
|
102
|
+
|
|
103
|
+
void setup() {
|
|
104
|
+
Serial.begin(115200);
|
|
105
|
+
|
|
106
|
+
// Set debug level
|
|
107
|
+
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
108
|
+
|
|
109
|
+
// Initialize as Shared Gateway
|
|
110
|
+
bool success = mesh.initAsSharedGateway(
|
|
111
|
+
MESH_PREFIX, // Mesh network name
|
|
112
|
+
MESH_PASSWORD, // Mesh network password
|
|
113
|
+
ROUTER_SSID, // Router SSID
|
|
114
|
+
ROUTER_PASSWORD, // Router password
|
|
115
|
+
&userScheduler, // Task scheduler
|
|
116
|
+
MESH_PORT // Mesh TCP port
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
if (success) {
|
|
120
|
+
Serial.println("Shared Gateway Mode initialized!");
|
|
121
|
+
Serial.printf("Node ID: %u\n", mesh.getNodeId());
|
|
122
|
+
Serial.printf("Router IP: %s\n", WiFi.localIP().toString().c_str());
|
|
123
|
+
} else {
|
|
124
|
+
Serial.println("Failed to initialize - falling back to mesh only");
|
|
125
|
+
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Register callbacks
|
|
129
|
+
mesh.onReceive(&receivedCallback);
|
|
130
|
+
mesh.onNewConnection(&newConnectionCallback);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
void loop() {
|
|
134
|
+
mesh.update();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
void receivedCallback(uint32_t from, String& msg) {
|
|
138
|
+
Serial.printf("Received from %u: %s\n", from, msg.c_str());
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
void newConnectionCallback(uint32_t nodeId) {
|
|
142
|
+
Serial.printf("New connection: %u\n", nodeId);
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## API Reference
|
|
149
|
+
|
|
150
|
+
### Initialization Methods
|
|
151
|
+
|
|
152
|
+
#### `initAsSharedGateway()`
|
|
153
|
+
|
|
154
|
+
Initialize the mesh in Shared Gateway Mode, connecting to both the mesh network and an external WiFi router.
|
|
155
|
+
|
|
156
|
+
```cpp
|
|
157
|
+
bool initAsSharedGateway(
|
|
158
|
+
TSTRING meshPrefix,
|
|
159
|
+
TSTRING meshPassword,
|
|
160
|
+
TSTRING routerSSID,
|
|
161
|
+
TSTRING routerPassword,
|
|
162
|
+
Scheduler* userScheduler,
|
|
163
|
+
uint16_t port = 5555,
|
|
164
|
+
painlessmesh::gateway::SharedGatewayConfig config = SharedGatewayConfig()
|
|
165
|
+
);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Parameters:**
|
|
169
|
+
|
|
170
|
+
| Parameter | Type | Description |
|
|
171
|
+
|-----------|------|-------------|
|
|
172
|
+
| `meshPrefix` | TSTRING | Mesh network name (SSID prefix) |
|
|
173
|
+
| `meshPassword` | TSTRING | Mesh network password |
|
|
174
|
+
| `routerSSID` | TSTRING | External WiFi router SSID |
|
|
175
|
+
| `routerPassword` | TSTRING | External WiFi router password |
|
|
176
|
+
| `userScheduler` | Scheduler* | TaskScheduler instance for mesh operations |
|
|
177
|
+
| `port` | uint16_t | TCP port for mesh communication (default: 5555) |
|
|
178
|
+
| `config` | SharedGatewayConfig | Optional advanced configuration |
|
|
179
|
+
|
|
180
|
+
**Returns:** `true` if initialization succeeded, `false` otherwise
|
|
181
|
+
|
|
182
|
+
**Behavior:**
|
|
183
|
+
|
|
184
|
+
1. Connects to the router to detect its WiFi channel
|
|
185
|
+
2. Initializes the mesh network on the same channel
|
|
186
|
+
3. Re-establishes the router connection using `stationManual()`
|
|
187
|
+
4. Sets up automatic router reconnection monitoring
|
|
188
|
+
|
|
189
|
+
**Example:**
|
|
190
|
+
|
|
191
|
+
```cpp
|
|
192
|
+
// Basic initialization
|
|
193
|
+
bool success = mesh.initAsSharedGateway(
|
|
194
|
+
"MyMesh", "meshPass",
|
|
195
|
+
"HomeRouter", "routerPass",
|
|
196
|
+
&userScheduler
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
// With custom configuration
|
|
200
|
+
painlessmesh::gateway::SharedGatewayConfig config;
|
|
201
|
+
config.internetCheckInterval = 15000; // Check every 15 seconds
|
|
202
|
+
config.gatewayHeartbeatInterval = 10000;
|
|
203
|
+
|
|
204
|
+
bool success = mesh.initAsSharedGateway(
|
|
205
|
+
"MyMesh", "meshPass",
|
|
206
|
+
"HomeRouter", "routerPass",
|
|
207
|
+
&userScheduler, 5555, config
|
|
208
|
+
);
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
### Internet Connectivity Methods
|
|
214
|
+
|
|
215
|
+
#### `sendToInternet()`
|
|
216
|
+
|
|
217
|
+
Send data to an Internet destination. Automatically handles failover through the mesh if local Internet is unavailable.
|
|
218
|
+
|
|
219
|
+
```cpp
|
|
220
|
+
uint32_t sendToInternet(
|
|
221
|
+
TSTRING destination,
|
|
222
|
+
TSTRING payload,
|
|
223
|
+
std::function<void(bool success, uint16_t httpStatus, TSTRING error)> callback,
|
|
224
|
+
uint8_t priority = static_cast<uint8_t>(GatewayPriority::PRIORITY_NORMAL)
|
|
225
|
+
);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Parameters:**
|
|
229
|
+
|
|
230
|
+
| Parameter | Type | Description |
|
|
231
|
+
|-----------|------|-------------|
|
|
232
|
+
| `destination` | TSTRING | URL or endpoint (e.g., "https://api.example.com/data") |
|
|
233
|
+
| `payload` | TSTRING | Data to send (typically JSON) |
|
|
234
|
+
| `callback` | function | Callback for delivery result |
|
|
235
|
+
| `priority` | uint8_t | Message priority (0=CRITICAL to 3=LOW) |
|
|
236
|
+
|
|
237
|
+
**Returns:** Unique message ID for tracking
|
|
238
|
+
|
|
239
|
+
**Priority Levels:**
|
|
240
|
+
|
|
241
|
+
| Value | Enum | Description |
|
|
242
|
+
|-------|------|-------------|
|
|
243
|
+
| 0 | `PRIORITY_CRITICAL` | Immediate processing, alarms |
|
|
244
|
+
| 1 | `PRIORITY_HIGH` | High priority data |
|
|
245
|
+
| 2 | `PRIORITY_NORMAL` | Standard data (default) |
|
|
246
|
+
| 3 | `PRIORITY_LOW` | Background/bulk data |
|
|
247
|
+
|
|
248
|
+
**Example:**
|
|
249
|
+
|
|
250
|
+
```cpp
|
|
251
|
+
// Send sensor data to cloud
|
|
252
|
+
String sensorData = "{\"temperature\": 25.5, \"humidity\": 60}";
|
|
253
|
+
|
|
254
|
+
uint32_t msgId = mesh.sendToInternet(
|
|
255
|
+
"https://api.example.com/sensors",
|
|
256
|
+
sensorData,
|
|
257
|
+
[](bool success, uint16_t httpStatus, String error) {
|
|
258
|
+
if (success) {
|
|
259
|
+
Serial.printf("Delivered! HTTP %d\n", httpStatus);
|
|
260
|
+
} else {
|
|
261
|
+
Serial.printf("Failed: %s\n", error.c_str());
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
static_cast<uint8_t>(painlessmesh::gateway::GatewayPriority::PRIORITY_HIGH)
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
Serial.printf("Message queued with ID: %u\n", msgId);
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
#### `hasLocalInternet()`
|
|
273
|
+
|
|
274
|
+
Check if this node has direct Internet connectivity.
|
|
275
|
+
|
|
276
|
+
```cpp
|
|
277
|
+
bool hasLocalInternet();
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Returns:** `true` if this node can reach the Internet directly
|
|
281
|
+
|
|
282
|
+
**Example:**
|
|
283
|
+
|
|
284
|
+
```cpp
|
|
285
|
+
if (mesh.hasLocalInternet()) {
|
|
286
|
+
Serial.println("Local Internet available");
|
|
287
|
+
// Send directly
|
|
288
|
+
} else {
|
|
289
|
+
Serial.println("No local Internet - will route through mesh");
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
#### `getInternetStatus()`
|
|
296
|
+
|
|
297
|
+
Get detailed information about Internet connectivity status.
|
|
298
|
+
|
|
299
|
+
```cpp
|
|
300
|
+
painlessmesh::gateway::InternetStatus getInternetStatus();
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Returns:** `InternetStatus` structure with detailed connectivity information
|
|
304
|
+
|
|
305
|
+
**InternetStatus Structure:**
|
|
306
|
+
|
|
307
|
+
| Field | Type | Description |
|
|
308
|
+
|-------|------|-------------|
|
|
309
|
+
| `available` | bool | Whether Internet is currently available |
|
|
310
|
+
| `lastCheckTime` | uint32_t | Timestamp of last check (millis) |
|
|
311
|
+
| `lastSuccessTime` | uint32_t | Timestamp of last successful check |
|
|
312
|
+
| `checkCount` | uint32_t | Total number of checks performed |
|
|
313
|
+
| `successCount` | uint32_t | Number of successful checks |
|
|
314
|
+
| `failureCount` | uint32_t | Number of failed checks |
|
|
315
|
+
| `lastLatencyMs` | uint32_t | Latency of last successful check |
|
|
316
|
+
| `lastError` | TSTRING | Error message from last failed check |
|
|
317
|
+
| `checkHost` | TSTRING | Host used for connectivity check |
|
|
318
|
+
| `checkPort` | uint16_t | Port used for connectivity check |
|
|
319
|
+
|
|
320
|
+
**InternetStatus Methods:**
|
|
321
|
+
|
|
322
|
+
```cpp
|
|
323
|
+
// Get uptime percentage (0-100)
|
|
324
|
+
uint8_t getUptimePercent() const;
|
|
325
|
+
|
|
326
|
+
// Get time since last successful check
|
|
327
|
+
uint32_t getTimeSinceLastSuccess() const;
|
|
328
|
+
|
|
329
|
+
// Check if status is stale (no recent check)
|
|
330
|
+
bool isStale(uint32_t maxAgeMs = 60000) const;
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Example:**
|
|
334
|
+
|
|
335
|
+
```cpp
|
|
336
|
+
auto status = mesh.getInternetStatus();
|
|
337
|
+
|
|
338
|
+
Serial.printf("Internet: %s\n", status.available ? "Available" : "Unavailable");
|
|
339
|
+
Serial.printf("Uptime: %d%%\n", status.getUptimePercent());
|
|
340
|
+
Serial.printf("Last latency: %u ms\n", status.lastLatencyMs);
|
|
341
|
+
Serial.printf("Checks: %u success / %u total\n",
|
|
342
|
+
status.successCount, status.checkCount);
|
|
343
|
+
|
|
344
|
+
if (!status.lastError.empty()) {
|
|
345
|
+
Serial.printf("Last error: %s\n", status.lastError.c_str());
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
### Gateway Status Methods
|
|
352
|
+
|
|
353
|
+
#### `isPrimaryGateway()`
|
|
354
|
+
|
|
355
|
+
Check if this node is the elected primary gateway.
|
|
356
|
+
|
|
357
|
+
```cpp
|
|
358
|
+
bool isPrimaryGateway();
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Returns:** `true` if this node is the primary gateway
|
|
362
|
+
|
|
363
|
+
**Example:**
|
|
364
|
+
|
|
365
|
+
```cpp
|
|
366
|
+
if (mesh.isPrimaryGateway()) {
|
|
367
|
+
Serial.println("This node is the PRIMARY gateway");
|
|
368
|
+
// Handle relayed messages from other nodes
|
|
369
|
+
} else {
|
|
370
|
+
Serial.println("This node is a backup gateway");
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
#### `getPrimaryGateway()`
|
|
377
|
+
|
|
378
|
+
Get the node ID of the current primary gateway.
|
|
379
|
+
|
|
380
|
+
```cpp
|
|
381
|
+
uint32_t getPrimaryGateway();
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**Returns:** Node ID of the primary gateway, or 0 if none elected
|
|
385
|
+
|
|
386
|
+
**Example:**
|
|
387
|
+
|
|
388
|
+
```cpp
|
|
389
|
+
uint32_t primaryId = mesh.getPrimaryGateway();
|
|
390
|
+
|
|
391
|
+
if (primaryId != 0) {
|
|
392
|
+
Serial.printf("Primary gateway: %u\n", primaryId);
|
|
393
|
+
|
|
394
|
+
if (primaryId == mesh.getNodeId()) {
|
|
395
|
+
Serial.println("(That's me!)");
|
|
396
|
+
}
|
|
397
|
+
} else {
|
|
398
|
+
Serial.println("No primary gateway elected yet");
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
#### `getGateways()`
|
|
405
|
+
|
|
406
|
+
Get a list of all nodes with Internet connectivity.
|
|
407
|
+
|
|
408
|
+
```cpp
|
|
409
|
+
std::vector<uint32_t> getGateways();
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
**Returns:** Vector of node IDs that have Internet access
|
|
413
|
+
|
|
414
|
+
**Example:**
|
|
415
|
+
|
|
416
|
+
```cpp
|
|
417
|
+
auto gateways = mesh.getGateways();
|
|
418
|
+
|
|
419
|
+
Serial.printf("Available gateways: %d\n", gateways.size());
|
|
420
|
+
for (auto nodeId : gateways) {
|
|
421
|
+
Serial.printf(" - Node %u", nodeId);
|
|
422
|
+
if (nodeId == mesh.getPrimaryGateway()) {
|
|
423
|
+
Serial.print(" [PRIMARY]");
|
|
424
|
+
}
|
|
425
|
+
Serial.println();
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
#### `isSharedGatewayMode()`
|
|
432
|
+
|
|
433
|
+
Check if the mesh is operating in Shared Gateway Mode.
|
|
434
|
+
|
|
435
|
+
```cpp
|
|
436
|
+
bool isSharedGatewayMode();
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Returns:** `true` if initialized with `initAsSharedGateway()`
|
|
440
|
+
|
|
441
|
+
**Example:**
|
|
442
|
+
|
|
443
|
+
```cpp
|
|
444
|
+
if (mesh.isSharedGatewayMode()) {
|
|
445
|
+
Serial.println("Running in Shared Gateway Mode");
|
|
446
|
+
Serial.printf("Router connected: %s\n",
|
|
447
|
+
WiFi.status() == WL_CONNECTED ? "Yes" : "No");
|
|
448
|
+
} else {
|
|
449
|
+
Serial.println("Running in standard mesh mode");
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
### Callbacks
|
|
456
|
+
|
|
457
|
+
#### `onLocalInternetChanged()`
|
|
458
|
+
|
|
459
|
+
Register a callback for Internet connectivity changes.
|
|
460
|
+
|
|
461
|
+
```cpp
|
|
462
|
+
void onLocalInternetChanged(std::function<void(bool available)> callback);
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
**Parameters:**
|
|
466
|
+
|
|
467
|
+
| Parameter | Type | Description |
|
|
468
|
+
|-----------|------|-------------|
|
|
469
|
+
| `callback` | function | Function called when Internet status changes |
|
|
470
|
+
|
|
471
|
+
**Example:**
|
|
472
|
+
|
|
473
|
+
```cpp
|
|
474
|
+
mesh.onLocalInternetChanged([](bool available) {
|
|
475
|
+
if (available) {
|
|
476
|
+
Serial.println("✓ Internet connection restored");
|
|
477
|
+
// Resume direct sending
|
|
478
|
+
} else {
|
|
479
|
+
Serial.println("✗ Internet connection lost");
|
|
480
|
+
// Data will be routed through mesh
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
#### `onGatewayChanged()`
|
|
488
|
+
|
|
489
|
+
Register a callback for primary gateway changes.
|
|
490
|
+
|
|
491
|
+
```cpp
|
|
492
|
+
void onGatewayChanged(std::function<void(uint32_t newGatewayId)> callback);
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
**Parameters:**
|
|
496
|
+
|
|
497
|
+
| Parameter | Type | Description |
|
|
498
|
+
|-----------|------|-------------|
|
|
499
|
+
| `callback` | function | Function called when primary gateway changes |
|
|
500
|
+
|
|
501
|
+
**Example:**
|
|
502
|
+
|
|
503
|
+
```cpp
|
|
504
|
+
mesh.onGatewayChanged([](uint32_t newGatewayId) {
|
|
505
|
+
Serial.printf("Primary gateway changed to: %u\n", newGatewayId);
|
|
506
|
+
|
|
507
|
+
if (newGatewayId == mesh.getNodeId()) {
|
|
508
|
+
Serial.println("This node is now the primary gateway!");
|
|
509
|
+
// Start handling relayed messages
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## Configuration
|
|
517
|
+
|
|
518
|
+
### SharedGatewayConfig Structure
|
|
519
|
+
|
|
520
|
+
The `SharedGatewayConfig` structure provides fine-grained control over Shared Gateway Mode behavior.
|
|
521
|
+
|
|
522
|
+
```cpp
|
|
523
|
+
#include "painlessmesh/gateway.hpp"
|
|
524
|
+
|
|
525
|
+
painlessmesh::gateway::SharedGatewayConfig config;
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### Configuration Options
|
|
529
|
+
|
|
530
|
+
| Option | Type | Default | Description |
|
|
531
|
+
|--------|------|---------|-------------|
|
|
532
|
+
| `enabled` | bool | false | Enable shared gateway functionality |
|
|
533
|
+
| `routerSSID` | TSTRING | "" | Router SSID (set automatically by initAsSharedGateway) |
|
|
534
|
+
| `routerPassword` | TSTRING | "" | Router password |
|
|
535
|
+
| `internetCheckInterval` | uint32_t | 30000 | Interval between Internet checks (ms) |
|
|
536
|
+
| `internetCheckHost` | TSTRING | "8.8.8.8" | Host to ping for connectivity check |
|
|
537
|
+
| `internetCheckPort` | uint16_t | 53 | Port for connectivity check |
|
|
538
|
+
| `internetCheckTimeout` | uint32_t | 5000 | Timeout for connectivity check (ms) |
|
|
539
|
+
| `messageRetryCount` | uint8_t | 3 | Retries before failover |
|
|
540
|
+
| `retryInterval` | uint32_t | 1000 | Interval between retries (ms) |
|
|
541
|
+
| `duplicateTrackingTimeout` | uint32_t | 60000 | How long to track message IDs (ms) |
|
|
542
|
+
| `maxTrackedMessages` | uint16_t | 500 | Maximum messages to track |
|
|
543
|
+
| `gatewayHeartbeatInterval` | uint32_t | 15000 | Primary gateway heartbeat interval (ms) |
|
|
544
|
+
| `gatewayFailureTimeout` | uint32_t | 45000 | Time to consider gateway failed (ms) |
|
|
545
|
+
| `participateInElection` | bool | true | Whether node can become primary |
|
|
546
|
+
| `relayedMessagePriority` | uint8_t | 0 | Priority for relayed messages (0=highest) |
|
|
547
|
+
| `maintainPermanentConnection` | bool | true | Keep router connection active |
|
|
548
|
+
|
|
549
|
+
### Configuration Examples
|
|
550
|
+
|
|
551
|
+
#### Low-Latency Configuration (Fast Failover)
|
|
552
|
+
|
|
553
|
+
```cpp
|
|
554
|
+
painlessmesh::gateway::SharedGatewayConfig config;
|
|
555
|
+
config.internetCheckInterval = 10000; // Check every 10 seconds
|
|
556
|
+
config.internetCheckTimeout = 2000; // 2 second timeout
|
|
557
|
+
config.gatewayHeartbeatInterval = 5000; // Heartbeat every 5 seconds
|
|
558
|
+
config.gatewayFailureTimeout = 15000; // Fail after 15 seconds
|
|
559
|
+
|
|
560
|
+
mesh.initAsSharedGateway("Mesh", "pass", "Router", "pass",
|
|
561
|
+
&userScheduler, 5555, config);
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
#### Memory-Constrained Configuration (ESP8266)
|
|
565
|
+
|
|
566
|
+
```cpp
|
|
567
|
+
painlessmesh::gateway::SharedGatewayConfig config;
|
|
568
|
+
config.maxTrackedMessages = 100; // Limit tracked messages
|
|
569
|
+
config.duplicateTrackingTimeout = 30000; // Shorter tracking window
|
|
570
|
+
config.internetCheckInterval = 60000; // Less frequent checks
|
|
571
|
+
|
|
572
|
+
mesh.initAsSharedGateway("Mesh", "pass", "Router", "pass",
|
|
573
|
+
&userScheduler, 5555, config);
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
#### Non-Participating Node (Backup Only)
|
|
577
|
+
|
|
578
|
+
```cpp
|
|
579
|
+
painlessmesh::gateway::SharedGatewayConfig config;
|
|
580
|
+
config.participateInElection = false; // Never become primary
|
|
581
|
+
|
|
582
|
+
mesh.initAsSharedGateway("Mesh", "pass", "Router", "pass",
|
|
583
|
+
&userScheduler, 5555, config);
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
### Configuration Validation
|
|
587
|
+
|
|
588
|
+
Validate configuration before use:
|
|
589
|
+
|
|
590
|
+
```cpp
|
|
591
|
+
painlessmesh::gateway::SharedGatewayConfig config;
|
|
592
|
+
config.enabled = true;
|
|
593
|
+
config.routerSSID = "MyRouter";
|
|
594
|
+
config.internetCheckInterval = 500; // Too low!
|
|
595
|
+
|
|
596
|
+
auto result = config.validate();
|
|
597
|
+
if (!result.valid) {
|
|
598
|
+
Serial.printf("Config error: %s\n", result.errorMessage.c_str());
|
|
599
|
+
// Output: "internetCheckInterval must be at least 1000ms"
|
|
600
|
+
}
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
## Package Types
|
|
606
|
+
|
|
607
|
+
Shared Gateway Mode uses three internal package types for coordination. These are automatically handled by the mesh but are documented here for advanced users implementing custom handlers.
|
|
608
|
+
|
|
609
|
+
### GatewayDataPackage (Type ID: 620)
|
|
610
|
+
|
|
611
|
+
Used to route Internet-bound data through the mesh when local Internet is unavailable.
|
|
612
|
+
|
|
613
|
+
```cpp
|
|
614
|
+
class GatewayDataPackage : public plugin::SinglePackage {
|
|
615
|
+
public:
|
|
616
|
+
uint32_t messageId; // Unique message identifier
|
|
617
|
+
uint32_t originNode; // Node that created the message
|
|
618
|
+
uint32_t timestamp; // Creation timestamp (mesh time)
|
|
619
|
+
uint8_t priority; // 0=CRITICAL, 1=HIGH, 2=NORMAL, 3=LOW
|
|
620
|
+
TSTRING destination; // URL/endpoint
|
|
621
|
+
TSTRING payload; // Application data
|
|
622
|
+
TSTRING contentType; // MIME type (default: "application/json")
|
|
623
|
+
uint8_t retryCount; // Number of relay attempts
|
|
624
|
+
bool requiresAck; // Whether to send acknowledgment
|
|
625
|
+
};
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
**Message ID Generation:**
|
|
629
|
+
|
|
630
|
+
```cpp
|
|
631
|
+
// Generate unique message ID
|
|
632
|
+
uint32_t msgId = GatewayDataPackage::generateMessageId(mesh.getNodeId());
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
**Manual Package Creation:**
|
|
636
|
+
|
|
637
|
+
```cpp
|
|
638
|
+
painlessmesh::gateway::GatewayDataPackage pkg;
|
|
639
|
+
pkg.messageId = GatewayDataPackage::generateMessageId(mesh.getNodeId());
|
|
640
|
+
pkg.originNode = mesh.getNodeId();
|
|
641
|
+
pkg.timestamp = mesh.getNodeTime();
|
|
642
|
+
pkg.priority = static_cast<uint8_t>(GatewayPriority::PRIORITY_HIGH);
|
|
643
|
+
pkg.destination = "https://api.example.com/data";
|
|
644
|
+
pkg.payload = "{\"sensor\": 42}";
|
|
645
|
+
pkg.contentType = "application/json";
|
|
646
|
+
pkg.requiresAck = true;
|
|
647
|
+
pkg.dest = primaryGatewayId;
|
|
648
|
+
pkg.from = mesh.getNodeId();
|
|
649
|
+
|
|
650
|
+
mesh.sendPackage(&pkg);
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
### GatewayAckPackage (Type ID: 621)
|
|
656
|
+
|
|
657
|
+
Sent by the gateway back to the origin node to confirm delivery status.
|
|
658
|
+
|
|
659
|
+
```cpp
|
|
660
|
+
class GatewayAckPackage : public plugin::SinglePackage {
|
|
661
|
+
public:
|
|
662
|
+
uint32_t messageId; // Message ID being acknowledged
|
|
663
|
+
uint32_t originNode; // Original sender node
|
|
664
|
+
bool success; // Whether delivery succeeded
|
|
665
|
+
uint16_t httpStatus; // HTTP status code (0 if N/A)
|
|
666
|
+
TSTRING error; // Error message if failed
|
|
667
|
+
uint32_t timestamp; // Acknowledgment timestamp
|
|
668
|
+
};
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
**Handling Acknowledgments:**
|
|
672
|
+
|
|
673
|
+
```cpp
|
|
674
|
+
mesh.onPackage(protocol::GATEWAY_ACK, [](protocol::Variant& variant) {
|
|
675
|
+
auto ack = variant.to<painlessmesh::gateway::GatewayAckPackage>();
|
|
676
|
+
|
|
677
|
+
Serial.printf("Ack for message %u: %s\n",
|
|
678
|
+
ack.messageId,
|
|
679
|
+
ack.success ? "Success" : "Failed");
|
|
680
|
+
|
|
681
|
+
if (!ack.success) {
|
|
682
|
+
Serial.printf("Error: %s\n", ack.error.c_str());
|
|
683
|
+
} else {
|
|
684
|
+
Serial.printf("HTTP Status: %d\n", ack.httpStatus);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
return false; // Don't stop propagation
|
|
688
|
+
});
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
---
|
|
692
|
+
|
|
693
|
+
### GatewayHeartbeatPackage (Type ID: 622)
|
|
694
|
+
|
|
695
|
+
Broadcast periodically by the primary gateway to inform all nodes of its status.
|
|
696
|
+
|
|
697
|
+
```cpp
|
|
698
|
+
class GatewayHeartbeatPackage : public plugin::BroadcastPackage {
|
|
699
|
+
public:
|
|
700
|
+
bool isPrimary; // Is this the primary gateway?
|
|
701
|
+
bool hasInternet; // Internet currently available?
|
|
702
|
+
int8_t routerRSSI; // Router signal strength (dBm)
|
|
703
|
+
uint32_t uptime; // Gateway uptime (seconds)
|
|
704
|
+
uint32_t timestamp; // Heartbeat timestamp
|
|
705
|
+
};
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
**Helper Methods:**
|
|
709
|
+
|
|
710
|
+
```cpp
|
|
711
|
+
// Check if gateway is healthy
|
|
712
|
+
bool isHealthy() const; // Returns isPrimary && hasInternet
|
|
713
|
+
|
|
714
|
+
// Check if signal strength is acceptable (> -70 dBm)
|
|
715
|
+
bool hasAcceptableSignal() const;
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
**Monitoring Heartbeats:**
|
|
719
|
+
|
|
720
|
+
```cpp
|
|
721
|
+
mesh.onPackage(protocol::GATEWAY_HEARTBEAT, [](protocol::Variant& variant) {
|
|
722
|
+
auto heartbeat = variant.to<painlessmesh::gateway::GatewayHeartbeatPackage>();
|
|
723
|
+
|
|
724
|
+
Serial.printf("Gateway %u heartbeat:\n", heartbeat.from);
|
|
725
|
+
Serial.printf(" Primary: %s\n", heartbeat.isPrimary ? "Yes" : "No");
|
|
726
|
+
Serial.printf(" Internet: %s\n", heartbeat.hasInternet ? "Yes" : "No");
|
|
727
|
+
Serial.printf(" RSSI: %d dBm\n", heartbeat.routerRSSI);
|
|
728
|
+
Serial.printf(" Uptime: %u seconds\n", heartbeat.uptime);
|
|
729
|
+
Serial.printf(" Healthy: %s\n", heartbeat.isHealthy() ? "Yes" : "No");
|
|
730
|
+
|
|
731
|
+
return false;
|
|
732
|
+
});
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
737
|
+
## Advanced Usage
|
|
738
|
+
|
|
739
|
+
### Failover Scenarios
|
|
740
|
+
|
|
741
|
+
#### Scenario 1: Local Internet Failure
|
|
742
|
+
|
|
743
|
+
```
|
|
744
|
+
┌────────┐ ┌─────────┐ ┌────────────┐
|
|
745
|
+
│ Node A │ │ Node B │ │ Internet │
|
|
746
|
+
│(Sender)│ │(Gateway)│ │ Service │
|
|
747
|
+
└───┬────┘ └────┬────┘ └─────┬──────┘
|
|
748
|
+
│ │ │
|
|
749
|
+
│ 1. sendToInternet() - local fails │ │
|
|
750
|
+
│ │ │
|
|
751
|
+
│ 2. GatewayDataPackage (Type 620) │ │
|
|
752
|
+
│────────────────────────────────────→│ │
|
|
753
|
+
│ │ 3. HTTP POST │
|
|
754
|
+
│ │───────────────────→│
|
|
755
|
+
│ │ │
|
|
756
|
+
│ │ 4. HTTP 200 OK │
|
|
757
|
+
│ │←───────────────────│
|
|
758
|
+
│ │ │
|
|
759
|
+
│ 5. GatewayAckPackage (Type 621) │ │
|
|
760
|
+
│←────────────────────────────────────│ │
|
|
761
|
+
│ │ │
|
|
762
|
+
│ 6. callback(true, 200, "") │ │
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
#### Scenario 2: Primary Gateway Failure
|
|
766
|
+
|
|
767
|
+
```
|
|
768
|
+
Timeline:
|
|
769
|
+
─────────────────────────────────────────────────────────────────────
|
|
770
|
+
0s Primary Gateway (Node A) broadcasting heartbeats
|
|
771
|
+
└─→ All nodes track Node A as primary
|
|
772
|
+
|
|
773
|
+
15s Node A sends heartbeat (normal)
|
|
774
|
+
|
|
775
|
+
30s Node A crashes! No more heartbeats...
|
|
776
|
+
|
|
777
|
+
45s Nodes detect missing heartbeat (gatewayFailureTimeout)
|
|
778
|
+
└─→ Election triggered
|
|
779
|
+
|
|
780
|
+
50s Node B wins election (highest RSSI)
|
|
781
|
+
└─→ Node B broadcasts as new primary
|
|
782
|
+
|
|
783
|
+
55s All nodes acknowledge Node B as primary
|
|
784
|
+
└─→ Normal operation resumes
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
### Election Protocol
|
|
788
|
+
|
|
789
|
+
The gateway election uses a deterministic algorithm to ensure consistent winner selection across all nodes:
|
|
790
|
+
|
|
791
|
+
1. **Eligibility**: Only nodes with Internet connectivity can participate
|
|
792
|
+
2. **Selection Criteria**:
|
|
793
|
+
- **Highest RSSI wins** (better router signal)
|
|
794
|
+
- **If RSSI tie, highest Node ID wins** (deterministic tiebreaker)
|
|
795
|
+
3. **Split-Brain Prevention**: If multiple nodes claim primary, nodes defer to the one with higher priority
|
|
796
|
+
|
|
797
|
+
**Election State Machine:**
|
|
798
|
+
|
|
799
|
+
```
|
|
800
|
+
┌─────────────────────────────────────┐
|
|
801
|
+
│ IDLE │
|
|
802
|
+
│ (monitoring primary heartbeats) │
|
|
803
|
+
└─────────────────┬───────────────────┘
|
|
804
|
+
│
|
|
805
|
+
Primary timeout detected
|
|
806
|
+
│
|
|
807
|
+
▼
|
|
808
|
+
┌─────────────────────────────────────┐
|
|
809
|
+
│ ELECTION_RUNNING │
|
|
810
|
+
│ (collecting candidates, 5 seconds) │
|
|
811
|
+
└─────────────────┬───────────────────┘
|
|
812
|
+
│
|
|
813
|
+
Election duration elapsed
|
|
814
|
+
│
|
|
815
|
+
▼
|
|
816
|
+
┌─────────────────────────────────────┐
|
|
817
|
+
│ COOLDOWN │
|
|
818
|
+
│ (preventing rapid re-elections) │
|
|
819
|
+
└─────────────────┬───────────────────┘
|
|
820
|
+
│
|
|
821
|
+
Cooldown period elapsed
|
|
822
|
+
│
|
|
823
|
+
▼
|
|
824
|
+
[IDLE]
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
### Custom Message Handling
|
|
828
|
+
|
|
829
|
+
Register handlers for gateway packages:
|
|
830
|
+
|
|
831
|
+
```cpp
|
|
832
|
+
// Handle relayed data (as gateway)
|
|
833
|
+
mesh.onPackage(protocol::GATEWAY_DATA, [](protocol::Variant& variant) {
|
|
834
|
+
auto pkg = variant.to<painlessmesh::gateway::GatewayDataPackage>();
|
|
835
|
+
|
|
836
|
+
Serial.printf("Relayed request from %u to %s\n",
|
|
837
|
+
pkg.originNode, pkg.destination.c_str());
|
|
838
|
+
|
|
839
|
+
// Custom handling (e.g., add authentication)
|
|
840
|
+
// The default handler will forward to Internet
|
|
841
|
+
|
|
842
|
+
return false; // Let default handler process
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
// Monitor gateway changes
|
|
846
|
+
mesh.onPackage(protocol::GATEWAY_HEARTBEAT, [](protocol::Variant& variant) {
|
|
847
|
+
auto hb = variant.to<painlessmesh::gateway::GatewayHeartbeatPackage>();
|
|
848
|
+
|
|
849
|
+
if (hb.isPrimary && !hb.hasInternet) {
|
|
850
|
+
Serial.println("Warning: Primary gateway lost Internet!");
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
return false;
|
|
854
|
+
});
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
### Message Tracking and Deduplication
|
|
858
|
+
|
|
859
|
+
The `GatewayMessageHandler` class prevents duplicate message processing:
|
|
860
|
+
|
|
861
|
+
```cpp
|
|
862
|
+
painlessmesh::GatewayMessageHandler handler;
|
|
863
|
+
|
|
864
|
+
// Configure from SharedGatewayConfig
|
|
865
|
+
handler.configure(config);
|
|
866
|
+
|
|
867
|
+
// Handle incoming message
|
|
868
|
+
bool shouldProcess = handler.handleIncomingMessage(pkg);
|
|
869
|
+
if (!shouldProcess) {
|
|
870
|
+
Serial.println("Duplicate message dropped");
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// Check if we should send acknowledgment
|
|
875
|
+
if (pkg.requiresAck && handler.shouldSendAcknowledgment(pkg.messageId, pkg.originNode)) {
|
|
876
|
+
sendAck(pkg);
|
|
877
|
+
handler.markAcknowledgmentSent(pkg.messageId, pkg.originNode);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// Get metrics
|
|
881
|
+
auto metrics = handler.getMetrics();
|
|
882
|
+
Serial.printf("Processed: %u, Duplicates: %u (%d%%)\n",
|
|
883
|
+
metrics.messagesProcessed,
|
|
884
|
+
metrics.duplicatesDetected,
|
|
885
|
+
metrics.getDuplicateRate());
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
---
|
|
889
|
+
|
|
890
|
+
## Troubleshooting
|
|
891
|
+
|
|
892
|
+
### Common Issues
|
|
893
|
+
|
|
894
|
+
#### Issue: Node fails to connect to router
|
|
895
|
+
|
|
896
|
+
**Symptoms:**
|
|
897
|
+
- `initAsSharedGateway()` returns false
|
|
898
|
+
- `WiFi.status()` != `WL_CONNECTED`
|
|
899
|
+
|
|
900
|
+
**Causes:**
|
|
901
|
+
- Incorrect router credentials
|
|
902
|
+
- Router out of range
|
|
903
|
+
- Channel conflict
|
|
904
|
+
|
|
905
|
+
**Solutions:**
|
|
906
|
+
|
|
907
|
+
```cpp
|
|
908
|
+
bool success = mesh.initAsSharedGateway(...);
|
|
909
|
+
|
|
910
|
+
if (!success) {
|
|
911
|
+
Serial.println("Shared Gateway init failed!");
|
|
912
|
+
Serial.printf("WiFi Status: %d\n", WiFi.status());
|
|
913
|
+
|
|
914
|
+
// Check WiFi status codes:
|
|
915
|
+
// WL_IDLE_STATUS = 0
|
|
916
|
+
// WL_NO_SSID_AVAIL = 1
|
|
917
|
+
// WL_SCAN_COMPLETED = 2
|
|
918
|
+
// WL_CONNECTED = 3
|
|
919
|
+
// WL_CONNECT_FAILED = 4
|
|
920
|
+
// WL_CONNECTION_LOST = 5
|
|
921
|
+
// WL_DISCONNECTED = 6
|
|
922
|
+
|
|
923
|
+
// Fallback to mesh-only mode
|
|
924
|
+
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
|
|
925
|
+
}
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
---
|
|
929
|
+
|
|
930
|
+
#### Issue: Internet health check always fails
|
|
931
|
+
|
|
932
|
+
**Symptoms:**
|
|
933
|
+
- `hasLocalInternet()` returns false despite router connection
|
|
934
|
+
- `getInternetStatus().lastError` shows "Connection refused"
|
|
935
|
+
|
|
936
|
+
**Causes:**
|
|
937
|
+
- Firewall blocking outbound connections
|
|
938
|
+
- DNS not working
|
|
939
|
+
- Check host unreachable
|
|
940
|
+
|
|
941
|
+
**Solutions:**
|
|
942
|
+
|
|
943
|
+
```cpp
|
|
944
|
+
// Try alternate check hosts
|
|
945
|
+
painlessmesh::gateway::SharedGatewayConfig config;
|
|
946
|
+
config.internetCheckHost = "1.1.1.1"; // Cloudflare DNS
|
|
947
|
+
config.internetCheckPort = 53;
|
|
948
|
+
|
|
949
|
+
// Or use HTTP endpoint
|
|
950
|
+
config.internetCheckHost = "www.google.com";
|
|
951
|
+
config.internetCheckPort = 80;
|
|
952
|
+
|
|
953
|
+
// Increase timeout
|
|
954
|
+
config.internetCheckTimeout = 10000;
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
---
|
|
958
|
+
|
|
959
|
+
#### Issue: Frequent gateway elections
|
|
960
|
+
|
|
961
|
+
**Symptoms:**
|
|
962
|
+
- `onGatewayChanged()` fires frequently
|
|
963
|
+
- Logs show repeated election cycles
|
|
964
|
+
|
|
965
|
+
**Causes:**
|
|
966
|
+
- Heartbeat interval too short
|
|
967
|
+
- Network congestion
|
|
968
|
+
- Unstable Internet connection
|
|
969
|
+
|
|
970
|
+
**Solutions:**
|
|
971
|
+
|
|
972
|
+
```cpp
|
|
973
|
+
// Increase heartbeat interval and failure timeout
|
|
974
|
+
painlessmesh::gateway::SharedGatewayConfig config;
|
|
975
|
+
config.gatewayHeartbeatInterval = 30000; // 30 seconds
|
|
976
|
+
config.gatewayFailureTimeout = 90000; // 90 seconds
|
|
977
|
+
|
|
978
|
+
// Or disable election participation for unstable nodes
|
|
979
|
+
config.participateInElection = false;
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
---
|
|
983
|
+
|
|
984
|
+
#### Issue: Duplicate messages delivered
|
|
985
|
+
|
|
986
|
+
**Symptoms:**
|
|
987
|
+
- Same data appears multiple times
|
|
988
|
+
- `GatewayMetrics.duplicatesDetected` is 0 but duplicates exist
|
|
989
|
+
|
|
990
|
+
**Causes:**
|
|
991
|
+
- `duplicateTrackingTimeout` too short
|
|
992
|
+
- `maxTrackedMessages` limit reached
|
|
993
|
+
- Messages not using `messageId`
|
|
994
|
+
|
|
995
|
+
**Solutions:**
|
|
996
|
+
|
|
997
|
+
```cpp
|
|
998
|
+
// Increase tracking capacity
|
|
999
|
+
painlessmesh::gateway::SharedGatewayConfig config;
|
|
1000
|
+
config.duplicateTrackingTimeout = 120000; // 2 minutes
|
|
1001
|
+
config.maxTrackedMessages = 1000;
|
|
1002
|
+
|
|
1003
|
+
// Ensure messages have unique IDs
|
|
1004
|
+
pkg.messageId = GatewayDataPackage::generateMessageId(mesh.getNodeId());
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
---
|
|
1008
|
+
|
|
1009
|
+
#### Issue: High memory usage on ESP8266
|
|
1010
|
+
|
|
1011
|
+
**Symptoms:**
|
|
1012
|
+
- `ESP.getFreeHeap()` drops significantly
|
|
1013
|
+
- Crashes or reboots
|
|
1014
|
+
|
|
1015
|
+
**Solutions:**
|
|
1016
|
+
|
|
1017
|
+
```cpp
|
|
1018
|
+
// Memory-optimized configuration
|
|
1019
|
+
painlessmesh::gateway::SharedGatewayConfig config;
|
|
1020
|
+
config.maxTrackedMessages = 50; // Minimum viable
|
|
1021
|
+
config.duplicateTrackingTimeout = 20000; // Short window
|
|
1022
|
+
config.internetCheckInterval = 60000; // Less frequent
|
|
1023
|
+
|
|
1024
|
+
// Monitor memory
|
|
1025
|
+
Serial.printf("Free heap: %u bytes\n", ESP.getFreeHeap());
|
|
1026
|
+
Serial.printf("Tracked messages: %u\n", handler.getTrackedMessageCount());
|
|
1027
|
+
|
|
1028
|
+
// Manual cleanup
|
|
1029
|
+
handler.cleanup(); // Remove expired entries
|
|
1030
|
+
```
|
|
1031
|
+
|
|
1032
|
+
---
|
|
1033
|
+
|
|
1034
|
+
### Debug Logging
|
|
1035
|
+
|
|
1036
|
+
Enable detailed logging for troubleshooting:
|
|
1037
|
+
|
|
1038
|
+
```cpp
|
|
1039
|
+
// Enable all debug types
|
|
1040
|
+
mesh.setDebugMsgTypes(ERROR | STARTUP | MESH_STATUS | CONNECTION |
|
|
1041
|
+
SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE);
|
|
1042
|
+
|
|
1043
|
+
// Gateway-specific logging happens automatically through Log() calls
|
|
1044
|
+
// Look for:
|
|
1045
|
+
// - "GatewayElectionManager:" - Election events
|
|
1046
|
+
// - "GatewayMessageHandler:" - Message processing
|
|
1047
|
+
// - "InternetHealthChecker:" - Connectivity checks
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
---
|
|
1051
|
+
|
|
1052
|
+
## Performance
|
|
1053
|
+
|
|
1054
|
+
### Memory Footprint
|
|
1055
|
+
|
|
1056
|
+
#### SharedGatewayConfig
|
|
1057
|
+
|
|
1058
|
+
| Platform | Minimum | With Typical Content |
|
|
1059
|
+
|----------|---------|---------------------|
|
|
1060
|
+
| ESP8266 | ~80 bytes | ~150-250 bytes |
|
|
1061
|
+
| ESP32 | ~80 bytes | ~150-250 bytes |
|
|
1062
|
+
| PC/Test | ~140 bytes | ~200-300 bytes |
|
|
1063
|
+
|
|
1064
|
+
#### GatewayDataPackage
|
|
1065
|
+
|
|
1066
|
+
| Platform | Base | With 1KB Payload |
|
|
1067
|
+
|----------|------|------------------|
|
|
1068
|
+
| ESP8266 | ~74 bytes | ~1100 bytes |
|
|
1069
|
+
| ESP32 | ~74 bytes | ~1100 bytes |
|
|
1070
|
+
|
|
1071
|
+
#### MessageTracker (per message)
|
|
1072
|
+
|
|
1073
|
+
| Platform | Per Entry | 500 Messages |
|
|
1074
|
+
|----------|-----------|--------------|
|
|
1075
|
+
| ESP8266 | ~40 bytes | ~20 KB |
|
|
1076
|
+
| ESP32 | ~40 bytes | ~20 KB |
|
|
1077
|
+
|
|
1078
|
+
### Recommendations by Platform
|
|
1079
|
+
|
|
1080
|
+
#### ESP8266 (~80KB RAM)
|
|
1081
|
+
|
|
1082
|
+
```cpp
|
|
1083
|
+
// Conservative settings
|
|
1084
|
+
config.maxTrackedMessages = 100; // ~4KB for tracker
|
|
1085
|
+
config.duplicateTrackingTimeout = 30000; // 30 second window
|
|
1086
|
+
config.internetCheckInterval = 60000; // Check every minute
|
|
1087
|
+
|
|
1088
|
+
// Keep payloads under 1KB
|
|
1089
|
+
// Leave 40KB+ for application
|
|
1090
|
+
```
|
|
1091
|
+
|
|
1092
|
+
#### ESP32 (~320KB RAM)
|
|
1093
|
+
|
|
1094
|
+
```cpp
|
|
1095
|
+
// Standard settings work well
|
|
1096
|
+
config.maxTrackedMessages = 500; // ~20KB for tracker
|
|
1097
|
+
config.duplicateTrackingTimeout = 60000; // 60 second window
|
|
1098
|
+
config.internetCheckInterval = 30000; // Check every 30 seconds
|
|
1099
|
+
|
|
1100
|
+
// Can handle larger payloads (up to 4KB)
|
|
1101
|
+
// Leave 200KB+ for application
|
|
1102
|
+
```
|
|
1103
|
+
|
|
1104
|
+
### Bandwidth Considerations
|
|
1105
|
+
|
|
1106
|
+
| Traffic Type | Interval | Size | Impact |
|
|
1107
|
+
|--------------|----------|------|--------|
|
|
1108
|
+
| Gateway Heartbeat | 15s | ~100 bytes | Low |
|
|
1109
|
+
| Internet Check | 30s | N/A (local TCP) | None |
|
|
1110
|
+
| GatewayDataPackage | Varies | 200-2000 bytes | Medium |
|
|
1111
|
+
| GatewayAckPackage | Per message | ~80 bytes | Low |
|
|
1112
|
+
|
|
1113
|
+
---
|
|
1114
|
+
|
|
1115
|
+
## Migration
|
|
1116
|
+
|
|
1117
|
+
### From Bridge Mode to Shared Gateway Mode
|
|
1118
|
+
|
|
1119
|
+
#### Step 1: Update Dependencies
|
|
1120
|
+
|
|
1121
|
+
Ensure you have painlessMesh v1.9.0 or later.
|
|
1122
|
+
|
|
1123
|
+
#### Step 2: Modify Initialization
|
|
1124
|
+
|
|
1125
|
+
**Before (Bridge Mode):**
|
|
1126
|
+
|
|
1127
|
+
```cpp
|
|
1128
|
+
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
|
|
1129
|
+
mesh.stationManual(ROUTER_SSID, ROUTER_PASSWORD);
|
|
1130
|
+
```
|
|
1131
|
+
|
|
1132
|
+
**After (Shared Gateway Mode):**
|
|
1133
|
+
|
|
1134
|
+
```cpp
|
|
1135
|
+
mesh.initAsSharedGateway(
|
|
1136
|
+
MESH_PREFIX, MESH_PASSWORD,
|
|
1137
|
+
ROUTER_SSID, ROUTER_PASSWORD,
|
|
1138
|
+
&userScheduler, MESH_PORT
|
|
1139
|
+
);
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1142
|
+
#### Step 3: Update Internet Sending
|
|
1143
|
+
|
|
1144
|
+
**Before:**
|
|
1145
|
+
|
|
1146
|
+
```cpp
|
|
1147
|
+
// Only bridge node could send to Internet
|
|
1148
|
+
if (mesh.isBridge()) {
|
|
1149
|
+
httpClient.POST(url, data);
|
|
1150
|
+
}
|
|
1151
|
+
```
|
|
1152
|
+
|
|
1153
|
+
**After:**
|
|
1154
|
+
|
|
1155
|
+
```cpp
|
|
1156
|
+
// Any node can send to Internet with automatic failover
|
|
1157
|
+
mesh.sendToInternet(url, data, [](bool success, uint16_t status, String error) {
|
|
1158
|
+
// Handle result
|
|
1159
|
+
});
|
|
1160
|
+
```
|
|
1161
|
+
|
|
1162
|
+
#### Step 4: Handle Gateway Events
|
|
1163
|
+
|
|
1164
|
+
```cpp
|
|
1165
|
+
// Monitor gateway changes
|
|
1166
|
+
mesh.onGatewayChanged([](uint32_t newGateway) {
|
|
1167
|
+
Serial.printf("New primary gateway: %u\n", newGateway);
|
|
1168
|
+
});
|
|
1169
|
+
|
|
1170
|
+
// Monitor Internet connectivity
|
|
1171
|
+
mesh.onLocalInternetChanged([](bool available) {
|
|
1172
|
+
Serial.printf("Internet: %s\n", available ? "Available" : "Lost");
|
|
1173
|
+
});
|
|
1174
|
+
```
|
|
1175
|
+
|
|
1176
|
+
#### Step 5: Update All Nodes
|
|
1177
|
+
|
|
1178
|
+
**Important:** All nodes in the mesh should be updated to use Shared Gateway Mode for full functionality. Mixed-mode networks (some bridge, some shared gateway) are not recommended.
|
|
1179
|
+
|
|
1180
|
+
### Configuration Migration
|
|
1181
|
+
|
|
1182
|
+
| Bridge Mode Setting | Shared Gateway Equivalent |
|
|
1183
|
+
|---------------------|--------------------------|
|
|
1184
|
+
| `stationManual()` | `routerSSID`, `routerPassword` in config |
|
|
1185
|
+
| Bridge election | `participateInElection`, `gatewayFailureTimeout` |
|
|
1186
|
+
| N/A | `internetCheckInterval`, `duplicateTrackingTimeout` |
|
|
1187
|
+
|
|
1188
|
+
---
|
|
1189
|
+
|
|
1190
|
+
## Related Documentation
|
|
1191
|
+
|
|
1192
|
+
- [Design Document](../design/SHARED_GATEWAY_DESIGN.md) - Full technical design
|
|
1193
|
+
- [Implementation Plan](../design/SHARED_GATEWAY_IMPLEMENTATION_PLAN.md) - Development roadmap
|
|
1194
|
+
- [Core API Reference](core-api.md) - Base painlessMesh API
|
|
1195
|
+
- [Example Code](../../examples/sharedGateway/sharedGateway.ino) - Working example
|
|
1196
|
+
|
|
1197
|
+
---
|
|
1198
|
+
|
|
1199
|
+
## Changelog
|
|
1200
|
+
|
|
1201
|
+
| Version | Changes |
|
|
1202
|
+
|---------|---------|
|
|
1203
|
+
| v1.9.0 | Initial release of Shared Gateway Mode |
|
|
1204
|
+
|
|
1205
|
+
---
|
|
1206
|
+
|
|
1207
|
+
*Last updated: November 2025*
|