@alteriom/painlessmesh 1.8.13 → 1.8.15
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 +43 -0
- package/README.md +2 -0
- package/RELEASE_NOTES_1.8.15.md +160 -0
- package/RELEASE_READINESS_PLAN.md +323 -0
- package/TESTING_WITH_SIMULATOR.md +259 -0
- package/docs/BRIDGE_INITIALIZATION_FALLBACK.md +357 -0
- package/docs/SIMULATOR_TESTING.md +408 -0
- package/docs/troubleshooting/common-architecture-mistakes.md +438 -0
- package/docs/troubleshooting/common-issues.md +28 -0
- package/docs/troubleshooting/faq.md +113 -12
- package/docs/troubleshooting/internet-access-faq.md +299 -0
- 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/bridge_failover.ino +17 -3
- package/examples/multi_bridge/primary_bridge.ino +15 -3
- package/examples/multi_bridge/secondary_bridge.ino +15 -3
- package/library.json +1 -1
- package/library.properties +1 -1
- package/package.json +5 -2
- package/src/arduino/wifi.hpp +60 -9
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
# Common Architecture Mistakes
|
|
2
|
+
|
|
3
|
+
This document explains common misunderstandings about painlessMesh architecture and how to fix them.
|
|
4
|
+
|
|
5
|
+
## Mistake #1: Expecting Regular Nodes to Have Internet Access
|
|
6
|
+
|
|
7
|
+
### The Problem
|
|
8
|
+
|
|
9
|
+
**What users expect:**
|
|
10
|
+
```cpp
|
|
11
|
+
// Regular mesh node trying to make HTTP requests
|
|
12
|
+
void sendSensorData() {
|
|
13
|
+
HTTPClient http;
|
|
14
|
+
http.begin("http://api.example.com/sensor");
|
|
15
|
+
http.POST("{\"temp\":25.5}"); // ❌ This fails!
|
|
16
|
+
http.end();
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Error message:**
|
|
21
|
+
```
|
|
22
|
+
[HTTPS] GET... failed, error: connection refused
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Why This Fails
|
|
26
|
+
|
|
27
|
+
painlessMesh creates a **mesh network**, not a mesh-routed internet gateway. Only the bridge node connects to your WiFi router.
|
|
28
|
+
|
|
29
|
+
**Architecture:**
|
|
30
|
+
```text
|
|
31
|
+
Internet
|
|
32
|
+
|
|
|
33
|
+
Router (WiFi - Channel 6)
|
|
34
|
+
|
|
|
35
|
+
Bridge Node (WIFI_AP_STA mode)
|
|
36
|
+
| ← Only this node has internet!
|
|
37
|
+
|
|
|
38
|
+
Mesh Network (Channel 6)
|
|
39
|
+
/ | \
|
|
40
|
+
Node1 Node2 Node3 ← These nodes do NOT have internet!
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Technical explanation:**
|
|
44
|
+
|
|
45
|
+
1. **Bridge node** (`WIFI_AP_STA` mode):
|
|
46
|
+
- Acts as Access Point (AP) for mesh
|
|
47
|
+
- Acts as Station (STA) connected to router
|
|
48
|
+
- Has internet access via router connection
|
|
49
|
+
- Can make HTTP/HTTPS requests
|
|
50
|
+
|
|
51
|
+
2. **Regular nodes** (`WIFI_AP` mode):
|
|
52
|
+
- Only act as Access Points for mesh
|
|
53
|
+
- No router connection
|
|
54
|
+
- No internet access
|
|
55
|
+
- Cannot make HTTP/HTTPS requests directly
|
|
56
|
+
|
|
57
|
+
ESP8266/ESP32 WiFi hardware can only operate on one channel at a time. Regular nodes use their WiFi radio to create the mesh AP - they cannot simultaneously connect to your router.
|
|
58
|
+
|
|
59
|
+
### The Solution
|
|
60
|
+
|
|
61
|
+
**Pattern 1: Forward through bridge (Recommended)**
|
|
62
|
+
|
|
63
|
+
```cpp
|
|
64
|
+
// ==== BRIDGE NODE ====
|
|
65
|
+
#include "painlessMesh.h"
|
|
66
|
+
#include "HTTPClient.h"
|
|
67
|
+
|
|
68
|
+
painlessMesh mesh;
|
|
69
|
+
|
|
70
|
+
void setup() {
|
|
71
|
+
// Initialize as bridge with internet access
|
|
72
|
+
mesh.initAsBridge(MESH_PREFIX, MESH_PASSWORD,
|
|
73
|
+
ROUTER_SSID, ROUTER_PASSWORD,
|
|
74
|
+
&userScheduler, 5555);
|
|
75
|
+
|
|
76
|
+
mesh.onReceive(&receivedCallback);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
void receivedCallback(uint32_t from, String& msg) {
|
|
80
|
+
// Parse message from mesh nodes
|
|
81
|
+
DynamicJsonDocument doc(1024);
|
|
82
|
+
deserializeJson(doc, msg);
|
|
83
|
+
|
|
84
|
+
// Forward to internet service
|
|
85
|
+
if (WiFi.status() == WL_CONNECTED) {
|
|
86
|
+
HTTPClient http;
|
|
87
|
+
http.begin("http://api.example.com/sensor");
|
|
88
|
+
http.addHeader("Content-Type", "application/json");
|
|
89
|
+
int httpCode = http.POST(msg);
|
|
90
|
+
|
|
91
|
+
if (httpCode > 0) {
|
|
92
|
+
Serial.printf("Data forwarded to cloud: %d\n", httpCode);
|
|
93
|
+
} else {
|
|
94
|
+
Serial.printf("HTTP POST failed: %s\n", http.errorToString(httpCode).c_str());
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
http.end();
|
|
98
|
+
} else {
|
|
99
|
+
Serial.println("No internet connection - data not forwarded");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ==== REGULAR SENSOR NODE ====
|
|
104
|
+
#include "painlessMesh.h"
|
|
105
|
+
|
|
106
|
+
painlessMesh mesh;
|
|
107
|
+
uint32_t bridgeNodeId = 0;
|
|
108
|
+
|
|
109
|
+
void setup() {
|
|
110
|
+
// Regular node - no router connection
|
|
111
|
+
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, 5555);
|
|
112
|
+
mesh.onReceive(&receivedCallback);
|
|
113
|
+
mesh.onNewConnection(&newConnectionCallback);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
void loop() {
|
|
117
|
+
mesh.update();
|
|
118
|
+
|
|
119
|
+
// Read sensor
|
|
120
|
+
float temperature = readTemperatureSensor();
|
|
121
|
+
|
|
122
|
+
// Send to bridge (NOT directly to internet!)
|
|
123
|
+
if (bridgeNodeId != 0) {
|
|
124
|
+
String msg = "{\"sensor\":\"temp\",\"value\":" + String(temperature) + "}";
|
|
125
|
+
mesh.sendSingle(bridgeNodeId, msg);
|
|
126
|
+
Serial.println("Data sent to bridge for forwarding");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
void newConnectionCallback(uint32_t nodeId) {
|
|
131
|
+
// You could implement bridge discovery here
|
|
132
|
+
// For now, configure bridge ID manually or via broadcast discovery
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Pattern 2: Bridge failover (High availability)**
|
|
137
|
+
|
|
138
|
+
```cpp
|
|
139
|
+
// All nodes configured with router credentials
|
|
140
|
+
mesh.setRouterCredentials(ROUTER_SSID, ROUTER_PASSWORD);
|
|
141
|
+
mesh.enableBridgeFailover(true);
|
|
142
|
+
|
|
143
|
+
mesh.onBridgeRoleChanged(&bridgeRoleCallback);
|
|
144
|
+
|
|
145
|
+
void bridgeRoleCallback(bool isBridge, String reason) {
|
|
146
|
+
if (isBridge) {
|
|
147
|
+
Serial.printf("I am now bridge: %s\n", reason.c_str());
|
|
148
|
+
// This node now has internet access
|
|
149
|
+
startForwardingToCloud();
|
|
150
|
+
} else {
|
|
151
|
+
Serial.println("I am a regular node - no internet access");
|
|
152
|
+
// This node must forward through bridge
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
See [BRIDGE_FAILOVER.md](../BRIDGE_FAILOVER.md) for details.
|
|
158
|
+
|
|
159
|
+
## Mistake #2: Thinking All Nodes Should Be Bridges
|
|
160
|
+
|
|
161
|
+
### The Problem
|
|
162
|
+
|
|
163
|
+
Some users try to make every node a bridge:
|
|
164
|
+
|
|
165
|
+
```cpp
|
|
166
|
+
// ❌ Bad idea: Making all nodes bridges
|
|
167
|
+
void setup() {
|
|
168
|
+
// Every node connects to router
|
|
169
|
+
mesh.initAsBridge(MESH_PREFIX, MESH_PASSWORD,
|
|
170
|
+
ROUTER_SSID, ROUTER_PASSWORD,
|
|
171
|
+
&userScheduler, 5555);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Why This Is Problematic
|
|
176
|
+
|
|
177
|
+
1. **Memory overhead**: Each router connection uses 5-10KB RAM
|
|
178
|
+
2. **Performance**: All nodes compete for router bandwidth
|
|
179
|
+
3. **Complexity**: Loses benefits of mesh architecture
|
|
180
|
+
4. **Channel conflicts**: All nodes must match router channel
|
|
181
|
+
5. **Connection limit**: Router has max client limit
|
|
182
|
+
|
|
183
|
+
### The Solution
|
|
184
|
+
|
|
185
|
+
**Use the bridge-forwarding pattern:**
|
|
186
|
+
|
|
187
|
+
- **1 bridge node**: Connects to router and mesh
|
|
188
|
+
- **N regular nodes**: Connect to mesh only, forward data to bridge
|
|
189
|
+
- **Bridge forwards**: Takes messages and forwards to internet
|
|
190
|
+
|
|
191
|
+
This is the intended architecture and scales much better.
|
|
192
|
+
|
|
193
|
+
## Mistake #3: Not Identifying the Bridge Node
|
|
194
|
+
|
|
195
|
+
### The Problem
|
|
196
|
+
|
|
197
|
+
Regular nodes send data but don't know which node is the bridge:
|
|
198
|
+
|
|
199
|
+
```cpp
|
|
200
|
+
// ❌ How do I know which node is the bridge?
|
|
201
|
+
void sendData() {
|
|
202
|
+
String msg = "{\"data\":\"value\"}";
|
|
203
|
+
mesh.sendBroadcast(msg); // Wasteful - sends to everyone!
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### The Solution
|
|
208
|
+
|
|
209
|
+
**Option 1: Bridge discovery via status broadcasts**
|
|
210
|
+
|
|
211
|
+
```cpp
|
|
212
|
+
// Bridge node broadcasts status
|
|
213
|
+
#include "examples/alteriom/alteriom_sensor_package.hpp"
|
|
214
|
+
using namespace alteriom;
|
|
215
|
+
|
|
216
|
+
// Bridge node
|
|
217
|
+
Task taskBridgeStatus(30000, TASK_FOREVER, []() {
|
|
218
|
+
if (mesh.isRoot()) {
|
|
219
|
+
BridgeStatusPackage status;
|
|
220
|
+
status.from = mesh.getNodeId();
|
|
221
|
+
status.internetConnected = (WiFi.status() == WL_CONNECTED);
|
|
222
|
+
status.routerRSSI = WiFi.RSSI();
|
|
223
|
+
|
|
224
|
+
mesh.sendBroadcast(status.toJsonString());
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Regular node
|
|
229
|
+
uint32_t bridgeNodeId = 0;
|
|
230
|
+
|
|
231
|
+
void receivedCallback(uint32_t from, String& msg) {
|
|
232
|
+
DynamicJsonDocument doc(1024);
|
|
233
|
+
deserializeJson(doc, msg);
|
|
234
|
+
|
|
235
|
+
if (doc["type"] == 610) { // BridgeStatusPackage
|
|
236
|
+
bridgeNodeId = from;
|
|
237
|
+
Serial.printf("Bridge node discovered: %u\n", bridgeNodeId);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
void sendDataToBridge() {
|
|
242
|
+
if (bridgeNodeId != 0) {
|
|
243
|
+
mesh.sendSingle(bridgeNodeId, myData);
|
|
244
|
+
} else {
|
|
245
|
+
Serial.println("Bridge not yet discovered");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Option 2: Hardcode bridge ID (simple approach)**
|
|
251
|
+
|
|
252
|
+
```cpp
|
|
253
|
+
// Configure bridge ID on all nodes
|
|
254
|
+
#define BRIDGE_NODE_ID 1234567890
|
|
255
|
+
|
|
256
|
+
void sendDataToBridge() {
|
|
257
|
+
mesh.sendSingle(BRIDGE_NODE_ID, myData);
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Option 3: Use root node as bridge**
|
|
262
|
+
|
|
263
|
+
```cpp
|
|
264
|
+
void setup() {
|
|
265
|
+
mesh.setRoot(true); // Bridge should be root
|
|
266
|
+
mesh.setContainsRoot(true); // Tell all nodes
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
void sendDataToBridge() {
|
|
270
|
+
// Send to root node (which is the bridge)
|
|
271
|
+
auto nodeList = mesh.getNodeList();
|
|
272
|
+
for (auto nodeId : nodeList) {
|
|
273
|
+
// Check if this node is root
|
|
274
|
+
// (painlessMesh automatically routes toward root)
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Mistake #4: Using Wrong WiFi Mode
|
|
280
|
+
|
|
281
|
+
### The Problem
|
|
282
|
+
|
|
283
|
+
```cpp
|
|
284
|
+
// ❌ Regular node trying to use AP+STA mode
|
|
285
|
+
void setup() {
|
|
286
|
+
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, 5555,
|
|
287
|
+
WIFI_AP_STA); // This is for bridges!
|
|
288
|
+
|
|
289
|
+
// Then trying to connect to router
|
|
290
|
+
WiFi.begin(ROUTER_SSID, ROUTER_PASSWORD); // Conflicts with mesh!
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### The Solution
|
|
295
|
+
|
|
296
|
+
**Bridge nodes:**
|
|
297
|
+
```cpp
|
|
298
|
+
// Use initAsBridge() which handles AP+STA mode correctly
|
|
299
|
+
mesh.initAsBridge(MESH_PREFIX, MESH_PASSWORD,
|
|
300
|
+
ROUTER_SSID, ROUTER_PASSWORD,
|
|
301
|
+
&userScheduler, 5555);
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Regular nodes:**
|
|
305
|
+
```cpp
|
|
306
|
+
// Use default WIFI_AP mode (or let init() choose)
|
|
307
|
+
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, 5555);
|
|
308
|
+
// No router connection needed
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Mistake #5: Blocking Code on Regular Nodes Waiting for Internet
|
|
312
|
+
|
|
313
|
+
### The Problem
|
|
314
|
+
|
|
315
|
+
```cpp
|
|
316
|
+
// ❌ Regular node waiting forever for internet that never comes
|
|
317
|
+
void sendToCloud() {
|
|
318
|
+
HTTPClient http;
|
|
319
|
+
http.begin("http://api.example.com");
|
|
320
|
+
http.setTimeout(30000); // Waits 30 seconds
|
|
321
|
+
http.POST(data); // Will always timeout!
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### The Solution
|
|
326
|
+
|
|
327
|
+
**Check your node role:**
|
|
328
|
+
|
|
329
|
+
```cpp
|
|
330
|
+
bool isBridgeNode = false;
|
|
331
|
+
|
|
332
|
+
void setup() {
|
|
333
|
+
if (shouldBeBridge()) {
|
|
334
|
+
mesh.initAsBridge(...);
|
|
335
|
+
isBridgeNode = true;
|
|
336
|
+
} else {
|
|
337
|
+
mesh.init(...);
|
|
338
|
+
isBridgeNode = false;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
void sendData() {
|
|
343
|
+
if (isBridgeNode && WiFi.status() == WL_CONNECTED) {
|
|
344
|
+
// Bridge can send directly to internet
|
|
345
|
+
http.POST("http://api.example.com", data);
|
|
346
|
+
} else {
|
|
347
|
+
// Regular node forwards to bridge
|
|
348
|
+
mesh.sendSingle(bridgeNodeId, data);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Real-World Example: WhatsApp Notifications
|
|
354
|
+
|
|
355
|
+
This is a real issue reported by a user trying to use the Callmebot-ESP32 library with painlessMesh.
|
|
356
|
+
|
|
357
|
+
### Original (Incorrect) Approach
|
|
358
|
+
|
|
359
|
+
```cpp
|
|
360
|
+
// ❌ Regular mesh node trying to send WhatsApp messages
|
|
361
|
+
#include "Callmebot_ESP32.h"
|
|
362
|
+
|
|
363
|
+
Callmebot_ESP32 whatsapp;
|
|
364
|
+
|
|
365
|
+
void sendAlarm() {
|
|
366
|
+
// This fails on regular nodes: "connection refused"
|
|
367
|
+
whatsapp.sendMessage("Sensor alarm!"); // ❌ No internet!
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Corrected Approach
|
|
372
|
+
|
|
373
|
+
```cpp
|
|
374
|
+
// ==== BRIDGE NODE ====
|
|
375
|
+
#include "painlessMesh.h"
|
|
376
|
+
#include "Callmebot_ESP32.h"
|
|
377
|
+
|
|
378
|
+
Callmebot_ESP32 whatsapp;
|
|
379
|
+
|
|
380
|
+
void setup() {
|
|
381
|
+
// Bridge has internet access
|
|
382
|
+
mesh.initAsBridge(MESH_PREFIX, MESH_PASSWORD,
|
|
383
|
+
ROUTER_SSID, ROUTER_PASSWORD,
|
|
384
|
+
&userScheduler, 5555);
|
|
385
|
+
|
|
386
|
+
whatsapp.begin(PHONE_NUMBER, API_KEY);
|
|
387
|
+
mesh.onReceive(&receivedCallback);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
void receivedCallback(uint32_t from, String& msg) {
|
|
391
|
+
DynamicJsonDocument doc(1024);
|
|
392
|
+
deserializeJson(doc, msg);
|
|
393
|
+
|
|
394
|
+
// Check for alarm messages from mesh nodes
|
|
395
|
+
if (doc["alarm"] == true) {
|
|
396
|
+
String alertMsg = "ALARM from sensor " + String(from);
|
|
397
|
+
alertMsg += ": " + doc["message"].as<String>();
|
|
398
|
+
|
|
399
|
+
// Bridge can send WhatsApp messages
|
|
400
|
+
if (WiFi.status() == WL_CONNECTED) {
|
|
401
|
+
whatsapp.sendMessage(alertMsg);
|
|
402
|
+
Serial.println("WhatsApp alert sent!");
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// ==== SENSOR NODE ====
|
|
408
|
+
void checkSensorAndAlert() {
|
|
409
|
+
float oxygenLevel = readO2Sensor();
|
|
410
|
+
|
|
411
|
+
if (oxygenLevel < CRITICAL_THRESHOLD) {
|
|
412
|
+
// Send alarm to bridge (not directly to WhatsApp!)
|
|
413
|
+
String alarm = "{\"alarm\":true,\"sensor\":\"O2\",";
|
|
414
|
+
alarm += "\"value\":" + String(oxygenLevel) + ",";
|
|
415
|
+
alarm += "\"message\":\"Critical O2 level!\"}";
|
|
416
|
+
|
|
417
|
+
mesh.sendSingle(bridgeNodeId, alarm);
|
|
418
|
+
Serial.println("Alarm sent to bridge for WhatsApp notification");
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Summary: Architecture Best Practices
|
|
424
|
+
|
|
425
|
+
1. ✅ **One bridge node**: Connects to router and mesh, has internet access
|
|
426
|
+
2. ✅ **Regular nodes**: Connect to mesh only, NO internet access
|
|
427
|
+
3. ✅ **Forward pattern**: Regular nodes send data to bridge, bridge forwards to internet
|
|
428
|
+
4. ✅ **Bridge discovery**: Implement mechanism for nodes to find the bridge
|
|
429
|
+
5. ✅ **Error handling**: Bridge checks internet connectivity before forwarding
|
|
430
|
+
6. ✅ **Failover option**: Use bridge failover for high availability (v1.8.0+)
|
|
431
|
+
|
|
432
|
+
## Additional Resources
|
|
433
|
+
|
|
434
|
+
- [BRIDGE_TO_INTERNET.md](../../BRIDGE_TO_INTERNET.md) - Complete bridge setup guide
|
|
435
|
+
- [BRIDGE_FAILOVER.md](../BRIDGE_FAILOVER.md) - Automatic failover for reliability
|
|
436
|
+
- [examples/mqttBridge/](../../examples/mqttBridge/) - Working example of bridge pattern
|
|
437
|
+
- [Mesh Architecture](../architecture/mesh-architecture.md) - Understanding mesh design
|
|
438
|
+
- [FAQ](faq.md) - Common questions and answers
|
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
This guide covers the most frequently encountered problems when working with painlessMesh and their solutions.
|
|
4
4
|
|
|
5
|
+
## Architecture & Design Issues
|
|
6
|
+
|
|
7
|
+
### Regular Nodes Cannot Access Internet / HTTP Requests Fail
|
|
8
|
+
|
|
9
|
+
**Symptoms:**
|
|
10
|
+
- HTTP/HTTPS requests fail with "connection refused"
|
|
11
|
+
- `WiFi.status()` shows disconnected on regular mesh nodes
|
|
12
|
+
- Internet services (APIs, WhatsApp bot, etc.) only work on bridge node
|
|
13
|
+
|
|
14
|
+
**Cause:**
|
|
15
|
+
|
|
16
|
+
This is **expected behavior**, not a bug. Only bridge nodes have internet access.
|
|
17
|
+
|
|
18
|
+
**Solution:**
|
|
19
|
+
|
|
20
|
+
See the dedicated guide for this common architecture mistake:
|
|
21
|
+
|
|
22
|
+
📖 **[Common Architecture Mistakes](common-architecture-mistakes.md)**
|
|
23
|
+
|
|
24
|
+
**Quick Summary:**
|
|
25
|
+
|
|
26
|
+
painlessMesh uses a bridge-forwarding pattern:
|
|
27
|
+
- **Bridge node**: Has internet access, forwards data to/from internet
|
|
28
|
+
- **Regular nodes**: No internet access, send data to bridge
|
|
29
|
+
- **Architecture**: Regular nodes → Bridge → Internet
|
|
30
|
+
|
|
31
|
+
Regular nodes must send data to the bridge, which then forwards to internet services.
|
|
32
|
+
|
|
5
33
|
## Platform-Specific Issues
|
|
6
34
|
|
|
7
35
|
### ESP32-C6 Crashes on Startup
|
|
@@ -293,30 +293,131 @@ String createSecureMessage(String data) {
|
|
|
293
293
|
|
|
294
294
|
### Q: Can I connect the mesh to the internet?
|
|
295
295
|
|
|
296
|
-
**A:** Yes, using bridge nodes
|
|
296
|
+
**A:** Yes, using bridge nodes. **Important:** Only the bridge node has internet access - regular mesh nodes do NOT have internet access.
|
|
297
|
+
|
|
298
|
+
**Architecture:**
|
|
299
|
+
```text
|
|
300
|
+
Internet
|
|
301
|
+
|
|
|
302
|
+
Router (WiFi)
|
|
303
|
+
|
|
|
304
|
+
Bridge Node (AP+STA mode) ← Only this node has internet access
|
|
305
|
+
|
|
|
306
|
+
Mesh Network
|
|
307
|
+
/ | \
|
|
308
|
+
Node1 Node2 Node3... ← These nodes do NOT have internet access
|
|
309
|
+
```
|
|
297
310
|
|
|
311
|
+
**Bridge Node Setup:**
|
|
298
312
|
```cpp
|
|
299
313
|
// Bridge node connects to both mesh and internet
|
|
300
314
|
void setup() {
|
|
301
|
-
//
|
|
315
|
+
// Modern approach: Auto-detect channel and connect
|
|
316
|
+
mesh.initAsBridge(MESH_PREFIX, MESH_PASSWORD,
|
|
317
|
+
ROUTER_SSID, ROUTER_PASSWORD,
|
|
318
|
+
&userScheduler, MESH_PORT);
|
|
319
|
+
|
|
320
|
+
mesh.onReceive(&receivedCallback);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Forward mesh data to internet services
|
|
324
|
+
void receivedCallback(uint32_t from, String& msg) {
|
|
325
|
+
// Bridge forwards messages to HTTP server, MQTT broker, etc.
|
|
326
|
+
if (WiFi.status() == WL_CONNECTED) {
|
|
327
|
+
httpClient.POST("http://myserver.com/api/data", msg);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**Regular Nodes:**
|
|
333
|
+
```cpp
|
|
334
|
+
// Regular nodes send data TO the bridge (no direct internet access)
|
|
335
|
+
void setup() {
|
|
302
336
|
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
|
|
337
|
+
mesh.onReceive(&receivedCallback);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
void sendDataToInternet() {
|
|
341
|
+
// Regular nodes send to bridge, which forwards to internet
|
|
342
|
+
String data = "{\"sensor\":\"temp\",\"value\":25.5}";
|
|
343
|
+
mesh.sendSingle(bridgeNodeId, data);
|
|
344
|
+
// Bridge will forward this to internet services
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
See [BRIDGE_TO_INTERNET.md](../../BRIDGE_TO_INTERNET.md) for complete documentation.
|
|
349
|
+
|
|
350
|
+
### Q: Why can't my regular mesh nodes access the Internet / make HTTP requests?
|
|
351
|
+
|
|
352
|
+
**A:** This is expected behavior. **Only the bridge node has internet access** - regular mesh nodes only communicate with other mesh nodes.
|
|
353
|
+
|
|
354
|
+
**Why this happens:**
|
|
355
|
+
|
|
356
|
+
ESP8266/ESP32 WiFi hardware can only operate on one channel at a time. In a mesh network:
|
|
357
|
+
|
|
358
|
+
- **Bridge node** uses `WIFI_AP_STA` mode:
|
|
359
|
+
- Access Point (AP) for mesh on channel X
|
|
360
|
+
- Station (STA) connected to router on channel X
|
|
361
|
+
- Has internet access via router
|
|
362
|
+
|
|
363
|
+
- **Regular nodes** use `WIFI_AP` mode:
|
|
364
|
+
- Access Point (AP) for mesh only
|
|
365
|
+
- No router connection
|
|
366
|
+
- No internet access
|
|
367
|
+
|
|
368
|
+
**Solution - Forward through bridge:**
|
|
369
|
+
|
|
370
|
+
```cpp
|
|
371
|
+
// ==== BRIDGE NODE ====
|
|
372
|
+
#include "HTTPClient.h"
|
|
373
|
+
|
|
374
|
+
void receivedCallback(uint32_t from, String& msg) {
|
|
375
|
+
// Parse message from mesh nodes
|
|
376
|
+
DynamicJsonDocument doc(1024);
|
|
377
|
+
deserializeJson(doc, msg);
|
|
303
378
|
|
|
304
|
-
//
|
|
305
|
-
WiFi.
|
|
306
|
-
|
|
307
|
-
|
|
379
|
+
// Forward to internet service
|
|
380
|
+
if (WiFi.status() == WL_CONNECTED) {
|
|
381
|
+
HTTPClient http;
|
|
382
|
+
http.begin("http://api.example.com/data");
|
|
383
|
+
http.addHeader("Content-Type", "application/json");
|
|
384
|
+
http.POST(msg);
|
|
385
|
+
http.end();
|
|
308
386
|
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// ==== REGULAR NODE ====
|
|
390
|
+
void sendDataToCloud() {
|
|
391
|
+
// Create message
|
|
392
|
+
String msg = "{\"sensor\":\"temp\",\"value\":25.5}";
|
|
393
|
+
|
|
394
|
+
// Send to bridge (NOT directly to internet!)
|
|
395
|
+
mesh.sendSingle(bridgeNodeId, msg);
|
|
309
396
|
|
|
310
|
-
|
|
397
|
+
// Bridge will forward to internet service
|
|
311
398
|
}
|
|
399
|
+
```
|
|
312
400
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
401
|
+
**Common mistake:**
|
|
402
|
+
|
|
403
|
+
```cpp
|
|
404
|
+
// ❌ This will NOT work on regular mesh nodes:
|
|
405
|
+
HTTPClient http;
|
|
406
|
+
http.begin("http://api.example.com/data");
|
|
407
|
+
http.POST(data); // ERROR: No internet connection!
|
|
408
|
+
|
|
409
|
+
// ✅ Correct approach - send to bridge:
|
|
410
|
+
mesh.sendSingle(bridgeNodeId, data); // Bridge forwards to internet
|
|
318
411
|
```
|
|
319
412
|
|
|
413
|
+
**Architecture patterns:**
|
|
414
|
+
|
|
415
|
+
1. **Single bridge**: One node connects to router, others forward through it
|
|
416
|
+
2. **Bridge failover**: Multiple nodes have router credentials, automatic failover
|
|
417
|
+
3. **Multi-bridge**: Multiple simultaneous bridges for load balancing
|
|
418
|
+
|
|
419
|
+
See [BRIDGE_TO_INTERNET.md](../../BRIDGE_TO_INTERNET.md) and [BRIDGE_FAILOVER.md](../BRIDGE_FAILOVER.md).
|
|
420
|
+
|
|
320
421
|
### Q: Can I use MQTT with painlessMesh?
|
|
321
422
|
|
|
322
423
|
**A:** Yes, through bridge nodes or by running MQTT alongside the mesh:
|