@alteriom/painlessmesh 1.8.5 → 1.8.7

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.
@@ -30,10 +30,20 @@ Regular nodes track these broadcasts and detect failures when:
30
30
 
31
31
  ### 2. Election Trigger
32
32
 
33
- When the primary bridge fails:
33
+ An election is triggered when:
34
+
35
+ **Scenario 1: No Bridge Exists (Auto-Election Mode)**
36
+ - After 60-second startup period
37
+ - Periodic monitoring (every 30s) detects no healthy bridge
34
38
  - Nodes with router credentials configured start an election
35
39
  - Nodes without credentials remain passive
36
40
 
41
+ **Scenario 2: Bridge Failure**
42
+ - Primary bridge fails or loses Internet connectivity
43
+ - No status received within 60 seconds (configurable timeout)
44
+ - Bridge reports `internetConnected: false`
45
+ - Nodes detect failure and start election
46
+
37
47
  ### 3. Election Protocol
38
48
 
39
49
  **Step 1: Candidacy Broadcast (Type 611)**
@@ -97,34 +107,77 @@ To prevent oscillation:
97
107
 
98
108
  ## Setup Instructions
99
109
 
100
- ### 1. Flash Initial Bridge Node
110
+ You can choose between two deployment modes:
111
+
112
+ ### Option A: Auto-Election Mode (Recommended)
113
+
114
+ **Best for**: Equal peers where any node can become the bridge based on signal strength.
115
+
116
+ 1. Keep `INITIAL_BRIDGE = false` on **ALL nodes**
117
+ 2. Configure mesh credentials (MESH_PREFIX, MESH_PASSWORD)
118
+ 3. Configure router credentials (ROUTER_SSID, ROUTER_PASSWORD)
119
+ 4. Flash the same sketch to all ESP32/ESP8266 devices
120
+ 5. Power on all nodes simultaneously
121
+
122
+ **What happens**:
123
+ - Nodes start as regular mesh nodes
124
+ - After 60-second startup period, automatic monitoring begins
125
+ - If no bridge exists, nodes trigger an election
126
+ - Node with best router RSSI wins and becomes bridge
127
+ - Other nodes remain regular with failover capability
128
+
129
+ **Advantages**:
130
+ - Simpler setup - no need to designate a specific node
131
+ - True dynamic failover - any node can become bridge
132
+ - Best bridge selected based on signal strength
133
+
134
+ ### Option B: Pre-Designated Bridge Mode
135
+
136
+ **Best for**: When you want a specific node to start as the bridge.
137
+
138
+ **1. Flash Initial Bridge Node**
101
139
 
102
140
  1. Set `INITIAL_BRIDGE` to `true`
103
141
  2. Configure router credentials
104
142
  3. Flash to one ESP32/ESP8266
105
143
  4. This node will connect to router and start as bridge
106
144
 
107
- ### 2. Flash Regular Nodes
145
+ **2. Flash Regular Nodes**
108
146
 
109
147
  1. Set `INITIAL_BRIDGE` to `false`
110
148
  2. Configure same mesh and router credentials
111
149
  3. Flash to other ESP32/ESP8266 devices
112
150
  4. These nodes can become bridges via election
113
151
 
114
- ### 3. Test Failover
152
+ **Advantages**:
153
+ - Immediate bridge availability (no 60s wait)
154
+ - Predictable initial bridge selection
155
+ - Good for nodes with fixed locations
156
+
157
+ ### Test Failover Scenarios
115
158
 
116
- **Scenario 1: Bridge Goes Offline**
117
- 1. Power off the initial bridge node
159
+ **Scenario 1: Auto-Election (No Initial Bridge)**
160
+ 1. Flash all nodes with `INITIAL_BRIDGE = false`
161
+ 2. Power on all nodes
162
+ 3. Wait 60 seconds for startup period
163
+ 4. Automatic monitoring detects no bridge
164
+ 5. Election starts automatically within 30 seconds
165
+ 6. Node with best router signal becomes bridge
166
+ 7. Monitor serial output to see election process
167
+
168
+ **Scenario 2: Bridge Goes Offline**
169
+ 1. Power off the current bridge node (initial or elected)
118
170
  2. After 60 seconds, regular nodes detect failure
119
171
  3. Election starts automatically
120
172
  4. Node with best router signal becomes new bridge
121
173
  5. Monitor serial output to see election process
122
174
 
123
- **Scenario 2: Bridge Loses Internet**
124
- 1. Disconnect router from Internet
175
+ **Scenario 3: Bridge Loses Internet**
176
+ 1. Disconnect router from Internet (or block bridge node's Internet)
125
177
  2. Bridge reports `internetConnected: false`
126
- 3. Election may start (nodes decide if failover needed)
127
- 4. New bridge elected if necessary
178
+ 3. Nodes detect loss of Internet via status broadcasts
179
+ 4. Election starts to find a node with working Internet
180
+ 5. New bridge elected if another node has Internet access
128
181
 
129
182
  ## Serial Output
130
183
 
@@ -287,6 +340,17 @@ bool amBridge = mesh.isBridge();
287
340
  - Wait a few seconds after startup for initial discovery
288
341
  - Bridge now broadcasts immediately on startup and when nodes connect (fixed in v1.8.4+)
289
342
 
343
+ ### Bridge Reports No Internet When Router Has Internet
344
+
345
+ **Symptoms**: Bridge shows "Internet available: NO" or `hasInternet: false` despite router having Internet
346
+
347
+ **Cause**: Fixed in v1.8.5+. Previously only checked WiFi connection status, not actual Internet availability.
348
+
349
+ **Solutions**:
350
+ - Update to painlessMesh v1.8.5 or later
351
+ - Bridge now checks both WiFi connection AND valid gateway IP
352
+ - If still seeing issues, verify router's gateway IP is accessible: check `WiFi.gatewayIP()` returns valid IP (not 0.0.0.0)
353
+
290
354
  ### Election Doesn't Start
291
355
 
292
356
  **Symptoms**: Bridge fails but no election occurs
@@ -9,14 +9,26 @@
9
9
  // - ESP32 or ESP8266
10
10
  // - WiFi router with Internet connection
11
11
  //
12
- // Setup:
12
+ // Setup Options:
13
+ //
14
+ // OPTION A - Auto-Election Mode (Recommended):
15
+ // 1. Configure your mesh credentials (MESH_PREFIX, MESH_PASSWORD)
16
+ // 2. Configure your router credentials (ROUTER_SSID, ROUTER_PASSWORD)
17
+ // 3. Keep INITIAL_BRIDGE = false on ALL nodes
18
+ // 4. Flash multiple nodes with this sketch
19
+ // 5. After startup (~60 seconds), nodes will automatically elect a bridge
20
+ // based on best router signal strength (RSSI)
21
+ //
22
+ // OPTION B - Pre-Designated Bridge Mode:
13
23
  // 1. Configure your mesh credentials (MESH_PREFIX, MESH_PASSWORD)
14
24
  // 2. Configure your router credentials (ROUTER_SSID, ROUTER_PASSWORD)
15
- // 3. Flash multiple nodes with this sketch
16
- // 4. Designate one as the initial bridge by calling mesh.initAsBridge()
17
- // 5. Other nodes will automatically participate in elections if bridge fails
25
+ // 3. Set INITIAL_BRIDGE = true on ONE node (your designated bridge)
26
+ // 4. Keep INITIAL_BRIDGE = false on all other nodes
27
+ // 5. Flash the nodes - designated bridge starts immediately
28
+ // 6. If designated bridge fails, others will hold election
18
29
  //
19
30
  // Features Demonstrated:
31
+ // - Automatic bridge election when no bridge exists
20
32
  // - Automatic bridge failure detection via heartbeats
21
33
  // - RSSI-based election protocol
22
34
  // - Deterministic winner selection with tiebreakers
@@ -46,7 +46,12 @@ Task taskBroadcastNTP(NTP_INTERVAL, TASK_FOREVER, [](){
46
46
  pkg.timestamp = millis();
47
47
 
48
48
  // Serialize and broadcast to mesh
49
- String msg = pkg.toJson();
49
+ JsonDocument doc;
50
+ JsonObject obj = doc.to<JsonObject>();
51
+ pkg.addTo(std::move(obj));
52
+
53
+ String msg;
54
+ serializeJson(doc, msg);
50
55
  mesh.sendBroadcast(msg);
51
56
 
52
57
  Serial.printf("Broadcast NTP time: %u from %s (accuracy: %ums)\n",
package/library.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "type": "git",
7
7
  "url": "https://github.com/Alteriom/painlessMesh"
8
8
  },
9
- "version": "1.8.5",
9
+ "version": "1.8.7",
10
10
  "frameworks": [
11
11
  "arduino"
12
12
  ],
@@ -1,5 +1,5 @@
1
1
  name=Alteriom PainlessMesh
2
- version=1.8.5
2
+ version=1.8.7
3
3
  author=Coopdis,Scotty Franzyshen,Edwin van Leeuwen,Germán Martín,Maximilian Schwarz,Doanh Doanh,Alteriom
4
4
  maintainer=Alteriom
5
5
  sentence=A painless way to setup a mesh with ESP8266 and ESP32 devices with Alteriom extensions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alteriom/painlessmesh",
3
- "version": "1.8.5",
3
+ "version": "1.8.7",
4
4
  "description": "painlessMesh is a user-friendly library for creating mesh networks with ESP8266 and ESP32 devices. This Alteriom fork includes additional packages for sensor data (SensorPackage), device commands (CommandPackage), and status monitoring (StatusPackage). It handles routing and network management automatically, so you can focus on your application. The library uses JSON-based messaging and syncs time across all nodes, making it ideal for coordinated behaviour like synchronized light displays or sensor networks reporting to a central node.",
5
5
  "keywords": [
6
6
  "arduino",
@@ -29,10 +29,10 @@
29
29
  /**
30
30
  * @brief AlteriomPainlessMesh library version information
31
31
  */
32
- #define ALTERIOM_PAINLESS_MESH_VERSION "1.6.1"
32
+ #define ALTERIOM_PAINLESS_MESH_VERSION "1.8.7"
33
33
  #define ALTERIOM_PAINLESS_MESH_VERSION_MAJOR 1
34
- #define ALTERIOM_PAINLESS_MESH_VERSION_MINOR 6
35
- #define ALTERIOM_PAINLESS_MESH_VERSION_PATCH 1
34
+ #define ALTERIOM_PAINLESS_MESH_VERSION_MINOR 8
35
+ #define ALTERIOM_PAINLESS_MESH_VERSION_PATCH 7
36
36
 
37
37
  /**
38
38
  * @brief Library description and usage information
@@ -155,6 +155,44 @@ class Mesh : public painlessmesh::Mesh<Connection> {
155
155
  }
156
156
  });
157
157
 
158
+ // Add periodic monitoring task to detect when no bridge exists
159
+ // This handles the case where no node was initially configured as a bridge
160
+ this->addTask(30000, TASK_FOREVER, [this]() {
161
+ // Only check if failover is enabled and we have credentials
162
+ if (!bridgeFailoverEnabled || !routerCredentialsConfigured) {
163
+ return;
164
+ }
165
+
166
+ // Don't check if we're already a bridge
167
+ if (this->isBridge()) {
168
+ return;
169
+ }
170
+
171
+ // Skip check during startup period (60 seconds) to allow initial bridge discovery
172
+ if (millis() < 60000) {
173
+ return;
174
+ }
175
+
176
+ // Check if there are any healthy bridges
177
+ bool hasHealthyBridge = false;
178
+ for (const auto& bridge : this->getBridges()) {
179
+ if (bridge.isHealthy(bridgeTimeoutMs) && bridge.internetConnected) {
180
+ hasHealthyBridge = true;
181
+ break;
182
+ }
183
+ }
184
+
185
+ // If no healthy bridge exists, trigger an election
186
+ if (!hasHealthyBridge) {
187
+ Log(CONNECTION, "Bridge monitor: No healthy bridge detected, triggering election\n");
188
+ // Small delay to randomize election start across nodes
189
+ uint32_t randomDelay = random(1000, 3000);
190
+ this->addTask(randomDelay, TASK_ONCE, [this]() {
191
+ this->startBridgeElection();
192
+ });
193
+ }
194
+ });
195
+
158
196
  tcpServerInit();
159
197
  eventHandleInit();
160
198
 
@@ -1147,7 +1185,12 @@ class Mesh : public painlessmesh::Mesh<Connection> {
1147
1185
  obj["from"] = this->nodeId;
1148
1186
  obj["routing"] = 2; // BROADCAST routing
1149
1187
  obj["timestamp"] = this->getNodeTime();
1150
- obj["internetConnected"] = (WiFi.status() == WL_CONNECTED);
1188
+
1189
+ // Check Internet connectivity: WiFi connected AND valid gateway IP
1190
+ bool hasInternet = (WiFi.status() == WL_CONNECTED) &&
1191
+ (WiFi.gatewayIP() != IPAddress(0, 0, 0, 0));
1192
+ obj["internetConnected"] = hasInternet;
1193
+
1151
1194
  obj["routerRSSI"] = WiFi.RSSI();
1152
1195
  obj["routerChannel"] = WiFi.channel();
1153
1196
  obj["uptime"] = millis();
@@ -1158,7 +1201,7 @@ class Mesh : public painlessmesh::Mesh<Connection> {
1158
1201
  serializeJson(doc, msg);
1159
1202
 
1160
1203
  Log(GENERAL, "sendBridgeStatus(): Broadcasting status (Internet: %s)\n",
1161
- (WiFi.status() == WL_CONNECTED) ? "Connected" : "Disconnected");
1204
+ hasInternet ? "Connected" : "Disconnected");
1162
1205
 
1163
1206
  this->sendBroadcast(msg);
1164
1207
  }
@@ -5,7 +5,7 @@
5
5
  * @file painlessMesh.h
6
6
  * @brief Main header file for Alteriom painlessMesh library
7
7
  *
8
- * @version 1.8.4
8
+ * @version 1.8.7
9
9
  * @date 2025-11-12
10
10
  *
11
11
  * painlessMesh is a user-friendly library for creating mesh networks with