@alteriom/painlessmesh 1.6.1 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +380 -143
- package/LICENSE +674 -674
- package/README.md +477 -434
- package/RELEASE_GUIDE.md +504 -418
- package/docs/DOCUMENTATION_MIGRATION_PLAN.md +175 -175
- package/docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md +1062 -0
- package/docs/MESH_TOPOLOGY_GUIDE.md +992 -0
- package/docs/MESH_TOPOLOGY_PROGRESS.md +422 -0
- package/docs/MQTT_BRIDGE_COMMANDS.md +894 -0
- package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +324 -0
- package/docs/MQTT_COMMAND_SCHEMA_PROPOSAL.md +576 -0
- package/docs/MQTT_SCHEMA_COMPLIANCE.md +285 -0
- package/docs/MQTT_SCHEMA_PROPOSALS.md +446 -0
- package/docs/MQTT_SCHEMA_REVIEW.md +690 -0
- package/docs/OTA_COMMANDS_REFERENCE.md +554 -0
- package/docs/PHASE1_GUIDE.md +349 -0
- package/docs/PHASE2_GUIDE.md +543 -0
- package/docs/README.md +77 -70
- package/docs/SCHEMA_VALIDATION_CHECKLIST.md +222 -0
- package/docs/alteriom/overview.md +507 -507
- package/docs/api/core-api.md +606 -606
- package/docs/architecture/mesh-architecture.md +378 -378
- package/docs/architecture/plugin-system.md +516 -516
- package/docs/getting-started/first-mesh.md +409 -409
- package/docs/getting-started/installation.md +274 -274
- package/docs/getting-started/quickstart.md +157 -157
- package/docs/improvements/FEATURE_PROPOSALS.md +337 -0
- package/docs/improvements/PHASE1_IMPLEMENTATION.md +325 -0
- package/docs/improvements/PHASE2_IMPLEMENTATION.md +567 -0
- package/docs/improvements/README.md +86 -68
- package/docs/improvements/ota-and-status-enhancements.md +911 -0
- package/docs/improvements/ota-status-architecture-diagrams.md +658 -0
- package/docs/improvements/ota-status-quick-reference.md +284 -0
- package/docs/platformio-publishing.md +255 -0
- package/docs/platformio-setup-summary.md +121 -0
- package/docs/troubleshooting/common-issues.md +520 -520
- package/docs/troubleshooting/faq.md +472 -472
- package/docs/tutorials/basic-examples.md +717 -717
- package/docs/wiki/API-Reference.md +245 -245
- package/docs/wiki/Complete-Documentation.md +122 -122
- package/examples/alteriom/README.md +139 -81
- package/examples/alteriom/alteriom.ino +186 -185
- package/examples/alteriom/alteriom_sensor_package.hpp +240 -127
- package/examples/alteriom/platformio.ini +24 -24
- package/examples/alteriomImproved/alteriom_sensor_package.hpp +224 -0
- package/examples/{alteriom → alteriomImproved}/improved_sensor_node.ino +245 -245
- package/examples/alteriomImproved/platformio.ini +25 -0
- package/examples/alteriomPhase1/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomPhase1/phase1_features.ino +242 -0
- package/examples/alteriomPhase1/platformio.ini +25 -0
- package/examples/alteriomPhase2/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomPhase2/phase2_features.ino +186 -0
- package/examples/alteriomPhase2/platformio.ini +25 -0
- package/examples/{alteriom → alteriomSensorNode}/alteriom_sensor_node.ino +183 -183
- package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomSensorNode/platformio.ini +25 -0
- package/examples/basic/basic.ino +66 -66
- package/examples/basic/platformio.ini +25 -25
- package/examples/bridge/bridge.ino +51 -51
- package/examples/bridge/mesh_event_publisher.hpp +253 -0
- package/examples/bridge/mesh_topology_reporter.hpp +303 -0
- package/examples/bridge/mqtt_command_bridge.hpp +459 -0
- package/examples/bridge/mqtt_status_bridge.hpp +519 -0
- package/examples/bridge/platformio.ini +25 -25
- package/examples/echoNode/echoNode.ino +33 -33
- package/examples/echoNode/platformio.ini +25 -25
- package/examples/logClient/logClient.ino +109 -109
- package/examples/logClient/platformio.ini +25 -25
- package/examples/logServer/logServer.ino +81 -81
- package/examples/logServer/platformio.ini +25 -25
- package/examples/meshCommandNode/alteriom_sensor_package.hpp +235 -0
- package/examples/meshCommandNode/meshCommandNode.ino +263 -0
- package/examples/meshCommandNode/platformio.ini +25 -0
- package/examples/mqttBridge/mqttBridge.ino +118 -118
- package/examples/mqttBridge/platformio.ini +26 -26
- package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +235 -0
- package/examples/mqttCommandBridge/mesh_event_publisher.hpp +253 -0
- package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +303 -0
- package/examples/mqttCommandBridge/mqttCommandBridge.ino +252 -0
- package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +459 -0
- package/examples/mqttCommandBridge/platformio.ini +26 -0
- package/examples/mqttStatusBridge/mqttStatusBridge.ino +216 -0
- package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +522 -0
- package/examples/mqttStatusBridge/platformio.ini +26 -0
- package/examples/mqttTopologyTest/README.md +467 -0
- package/examples/mqttTopologyTest/mqttTopologyTest.ino +748 -0
- package/examples/mqttTopologyTest/platformio.ini +26 -0
- package/examples/namedMesh/namedMesh.ino +97 -97
- package/examples/namedMesh/platformio.ini +25 -25
- package/examples/otaReceiver/otaReceiver.ino +79 -79
- package/examples/otaReceiver/platformio.ini +25 -25
- package/examples/otaSender/otaSender.ino +160 -151
- package/examples/otaSender/platformio.ini +25 -25
- package/examples/startHere/platformio.ini +25 -25
- package/examples/startHere/startHere.ino +159 -159
- package/examples/webServer/platformio.ini +27 -27
- package/examples/webServer/webServer.ino +89 -89
- package/keywords.txt +48 -48
- package/library.json +55 -34
- package/library.properties +10 -10
- package/package.json +86 -78
- package/src/AlteriomPainlessMesh.h +97 -97
- package/src/arduino/wifi.hpp +365 -365
- package/src/boost/asynctcp.hpp +279 -279
- package/src/painlessMesh.h +70 -70
- package/src/painlessMeshSTA.cpp +236 -236
- package/src/painlessMeshSTA.h +58 -58
- package/src/painlessTaskOptions.h +4 -4
- package/src/painlessmesh/base64.hpp +111 -111
- package/src/painlessmesh/buffer.hpp +229 -229
- package/src/painlessmesh/callback.hpp +91 -91
- package/src/painlessmesh/configuration.hpp +77 -77
- package/src/painlessmesh/connection.hpp +192 -192
- package/src/painlessmesh/layout.hpp +188 -188
- package/src/painlessmesh/logger.hpp +158 -158
- package/src/painlessmesh/memory.hpp +119 -119
- package/src/painlessmesh/mesh.hpp +761 -560
- package/src/painlessmesh/metrics.hpp +322 -322
- package/src/painlessmesh/ntp.hpp +263 -263
- package/src/painlessmesh/ota.hpp +582 -553
- package/src/painlessmesh/plugin.hpp +188 -188
- package/src/painlessmesh/protocol.hpp +813 -813
- package/src/painlessmesh/router.hpp +322 -322
- package/src/painlessmesh/tcp.hpp +71 -71
- package/src/painlessmesh/validation.hpp +238 -238
- package/src/plugin/performance.hpp +214 -214
- package/src/plugin/remote.hpp +64 -64
- package/src/scheduler.cpp +10 -10
- package/src/wifi.cpp +2 -2
|
@@ -1,410 +1,410 @@
|
|
|
1
|
-
# Your First Mesh Network
|
|
2
|
-
|
|
3
|
-
This tutorial builds on the [Quick Start Guide](quickstart.md) to create a more comprehensive mesh network with multiple types of nodes and practical functionality.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
We'll build a mesh network with three types of nodes:
|
|
8
|
-
1. **Sensor Node** - Collects and broadcasts environmental data
|
|
9
|
-
2. **Controller Node** - Receives sensor data and controls devices
|
|
10
|
-
3. **Bridge Node** - Connects mesh to external networks (WiFi/Internet)
|
|
11
|
-
|
|
12
|
-
## Node 1: Sensor Node
|
|
13
|
-
|
|
14
|
-
This node simulates environmental sensors and broadcasts data to the mesh.
|
|
15
|
-
|
|
16
|
-
```cpp
|
|
17
|
-
#include "painlessMesh.h"
|
|
18
|
-
|
|
19
|
-
#define MESH_PREFIX "MyMeshNetwork"
|
|
20
|
-
#define MESH_PASSWORD "somethingSneaky"
|
|
21
|
-
#define MESH_PORT 5555
|
|
22
|
-
|
|
23
|
-
Scheduler userScheduler;
|
|
24
|
-
painlessMesh mesh;
|
|
25
|
-
|
|
26
|
-
// Sensor simulation
|
|
27
|
-
float temperature = 22.5;
|
|
28
|
-
float humidity = 65.0;
|
|
29
|
-
uint32_t sensorId = 1001;
|
|
30
|
-
|
|
31
|
-
// Task to send sensor data every 30 seconds
|
|
32
|
-
Task taskSendSensor(30000, TASK_FOREVER, [](){
|
|
33
|
-
// Simulate sensor readings with some variation
|
|
34
|
-
temperature += random(-10, 10) / 10.0;
|
|
35
|
-
humidity += random(-50, 50) / 10.0;
|
|
36
|
-
|
|
37
|
-
// Keep values in reasonable ranges
|
|
38
|
-
temperature = constrain(temperature, 15.0, 35.0);
|
|
39
|
-
humidity = constrain(humidity, 30.0, 90.0);
|
|
40
|
-
|
|
41
|
-
// Create JSON message
|
|
42
|
-
String msg = "{";
|
|
43
|
-
msg += "\"type\":\"sensor\",";
|
|
44
|
-
msg += "\"nodeId\":" + String(mesh.getNodeId()) + ",";
|
|
45
|
-
msg += "\"sensorId\":" + String(sensorId) + ",";
|
|
46
|
-
msg += "\"temperature\":" + String(temperature, 1) + ",";
|
|
47
|
-
msg += "\"humidity\":" + String(humidity, 1) + ",";
|
|
48
|
-
msg += "\"timestamp\":" + String(mesh.getNodeTime());
|
|
49
|
-
msg += "}";
|
|
50
|
-
|
|
51
|
-
mesh.sendBroadcast(msg);
|
|
52
|
-
Serial.printf("Sent sensor data: T=%.1f°C, H=%.1f%%\n", temperature, humidity);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
void receivedCallback(uint32_t from, String &msg) {
|
|
56
|
-
Serial.printf("Sensor Node: Received from %u: %s\n", from, msg.c_str());
|
|
57
|
-
|
|
58
|
-
// Sensor nodes can respond to commands
|
|
59
|
-
if (msg.indexOf("\"command\":\"read_sensor\"") > 0) {
|
|
60
|
-
// Force immediate sensor reading
|
|
61
|
-
taskSendSensor.forceNextIteration();
|
|
62
|
-
Serial.println("Forced sensor reading requested");
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
void newConnectionCallback(uint32_t nodeId) {
|
|
67
|
-
Serial.printf("Sensor Node: New connection to %u\n", nodeId);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
void changedConnectionCallback() {
|
|
71
|
-
Serial.printf("Sensor Node: Changed connections. Nodes: %s\n",
|
|
72
|
-
mesh.subConnectionJson().c_str());
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
void setup() {
|
|
76
|
-
Serial.begin(115200);
|
|
77
|
-
Serial.println("=== Sensor Node Starting ===");
|
|
78
|
-
|
|
79
|
-
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
80
|
-
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
|
|
81
|
-
mesh.onReceive(&receivedCallback);
|
|
82
|
-
mesh.onNewConnection(&newConnectionCallback);
|
|
83
|
-
mesh.onChangedConnections(&changedConnectionCallback);
|
|
84
|
-
|
|
85
|
-
userScheduler.addTask(taskSendSensor);
|
|
86
|
-
taskSendSensor.enable();
|
|
87
|
-
|
|
88
|
-
Serial.printf("Sensor Node initialized. Node ID: %u\n", mesh.getNodeId());
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
void loop() {
|
|
92
|
-
mesh.update();
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Node 2: Controller Node
|
|
97
|
-
|
|
98
|
-
This node receives sensor data and can send commands to other nodes.
|
|
99
|
-
|
|
100
|
-
```cpp
|
|
101
|
-
#include "painlessMesh.h"
|
|
102
|
-
|
|
103
|
-
#define MESH_PREFIX "MyMeshNetwork"
|
|
104
|
-
#define MESH_PASSWORD "somethingSneaky"
|
|
105
|
-
#define MESH_PORT 5555
|
|
106
|
-
|
|
107
|
-
Scheduler userScheduler;
|
|
108
|
-
painlessMesh mesh;
|
|
109
|
-
|
|
110
|
-
// Storage for sensor data
|
|
111
|
-
struct SensorData {
|
|
112
|
-
uint32_t nodeId;
|
|
113
|
-
uint32_t sensorId;
|
|
114
|
-
float temperature;
|
|
115
|
-
float humidity;
|
|
116
|
-
uint32_t timestamp;
|
|
117
|
-
bool valid;
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
SensorData sensors[10]; // Store data from up to 10 sensors
|
|
121
|
-
int sensorCount = 0;
|
|
122
|
-
|
|
123
|
-
// Task to request sensor data every 60 seconds
|
|
124
|
-
Task taskRequestData(60000, TASK_FOREVER, [](){
|
|
125
|
-
String cmd = "{";
|
|
126
|
-
cmd += "\"type\":\"command\",";
|
|
127
|
-
cmd += "\"command\":\"read_sensor\",";
|
|
128
|
-
cmd += "\"from\":" + String(mesh.getNodeId());
|
|
129
|
-
cmd += "}";
|
|
130
|
-
|
|
131
|
-
mesh.sendBroadcast(cmd);
|
|
132
|
-
Serial.println("Requested sensor data from all nodes");
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// Task to display collected data every 45 seconds
|
|
136
|
-
Task taskDisplayData(45000, TASK_FOREVER, [](){
|
|
137
|
-
Serial.println("=== Collected Sensor Data ===");
|
|
138
|
-
for (int i = 0; i < sensorCount; i++) {
|
|
139
|
-
if (sensors[i].valid) {
|
|
140
|
-
Serial.printf("Node %u (Sensor %u): T=%.1f°C, H=%.1f%%, Age=%u seconds\n",
|
|
141
|
-
sensors[i].nodeId, sensors[i].sensorId,
|
|
142
|
-
sensors[i].temperature, sensors[i].humidity,
|
|
143
|
-
(mesh.getNodeTime() - sensors[i].timestamp) / 1000000);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
Serial.println("============================");
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
void storeSensorData(uint32_t nodeId, uint32_t sensorId, float temp, float hum, uint32_t timestamp) {
|
|
150
|
-
// Find existing entry or create new one
|
|
151
|
-
int index = -1;
|
|
152
|
-
for (int i = 0; i < sensorCount; i++) {
|
|
153
|
-
if (sensors[i].nodeId == nodeId && sensors[i].sensorId == sensorId) {
|
|
154
|
-
index = i;
|
|
155
|
-
break;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (index == -1 && sensorCount < 10) {
|
|
160
|
-
index = sensorCount++;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (index != -1) {
|
|
164
|
-
sensors[index].nodeId = nodeId;
|
|
165
|
-
sensors[index].sensorId = sensorId;
|
|
166
|
-
sensors[index].temperature = temp;
|
|
167
|
-
sensors[index].humidity = hum;
|
|
168
|
-
sensors[index].timestamp = timestamp;
|
|
169
|
-
sensors[index].valid = true;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
void receivedCallback(uint32_t from, String &msg) {
|
|
174
|
-
Serial.printf("Controller: Received from %u: %s\n", from, msg.c_str());
|
|
175
|
-
|
|
176
|
-
// Parse sensor data
|
|
177
|
-
if (msg.indexOf("\"type\":\"sensor\"") > 0) {
|
|
178
|
-
// Simple JSON parsing (in production, use ArduinoJson library)
|
|
179
|
-
int tempStart = msg.indexOf("\"temperature\":") + 14;
|
|
180
|
-
int tempEnd = msg.indexOf(",", tempStart);
|
|
181
|
-
float temperature = msg.substring(tempStart, tempEnd).toFloat();
|
|
182
|
-
|
|
183
|
-
int humStart = msg.indexOf("\"humidity\":") + 11;
|
|
184
|
-
int humEnd = msg.indexOf(",", humStart);
|
|
185
|
-
float humidity = msg.substring(humStart, humEnd).toFloat();
|
|
186
|
-
|
|
187
|
-
int sensorStart = msg.indexOf("\"sensorId\":") + 11;
|
|
188
|
-
int sensorEnd = msg.indexOf(",", sensorStart);
|
|
189
|
-
uint32_t sensorId = msg.substring(sensorStart, sensorEnd).toInt();
|
|
190
|
-
|
|
191
|
-
int timeStart = msg.indexOf("\"timestamp\":") + 12;
|
|
192
|
-
int timeEnd = msg.indexOf("}", timeStart);
|
|
193
|
-
uint32_t timestamp = msg.substring(timeStart, timeEnd).toInt();
|
|
194
|
-
|
|
195
|
-
storeSensorData(from, sensorId, temperature, humidity, timestamp);
|
|
196
|
-
|
|
197
|
-
// Trigger actions based on sensor data
|
|
198
|
-
if (temperature > 30.0) {
|
|
199
|
-
Serial.println("WARNING: High temperature detected!");
|
|
200
|
-
// Could send cooling command here
|
|
201
|
-
}
|
|
202
|
-
if (humidity > 80.0) {
|
|
203
|
-
Serial.println("WARNING: High humidity detected!");
|
|
204
|
-
// Could trigger ventilation here
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
void newConnectionCallback(uint32_t nodeId) {
|
|
210
|
-
Serial.printf("Controller: New connection to %u\n", nodeId);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
void changedConnectionCallback() {
|
|
214
|
-
Serial.printf("Controller: Changed connections. Nodes: %s\n",
|
|
215
|
-
mesh.subConnectionJson().c_str());
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
void setup() {
|
|
219
|
-
Serial.begin(115200);
|
|
220
|
-
Serial.println("=== Controller Node Starting ===");
|
|
221
|
-
|
|
222
|
-
// Initialize sensor storage
|
|
223
|
-
for (int i = 0; i < 10; i++) {
|
|
224
|
-
sensors[i].valid = false;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
228
|
-
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
|
|
229
|
-
mesh.onReceive(&receivedCallback);
|
|
230
|
-
mesh.onNewConnection(&newConnectionCallback);
|
|
231
|
-
mesh.onChangedConnections(&changedConnectionCallback);
|
|
232
|
-
|
|
233
|
-
userScheduler.addTask(taskRequestData);
|
|
234
|
-
userScheduler.addTask(taskDisplayData);
|
|
235
|
-
taskRequestData.enable();
|
|
236
|
-
taskDisplayData.enable();
|
|
237
|
-
|
|
238
|
-
Serial.printf("Controller Node initialized. Node ID: %u\n", mesh.getNodeId());
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
void loop() {
|
|
242
|
-
mesh.update();
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
## Node 3: Bridge Node
|
|
247
|
-
|
|
248
|
-
This node connects the mesh to WiFi/Internet for external connectivity.
|
|
249
|
-
|
|
250
|
-
```cpp
|
|
251
|
-
#include "painlessMesh.h"
|
|
252
|
-
#include <WiFi.h> // Use <ESP8266WiFi.h> for ESP8266
|
|
253
|
-
|
|
254
|
-
#define MESH_PREFIX "MyMeshNetwork"
|
|
255
|
-
#define MESH_PASSWORD "somethingSneaky"
|
|
256
|
-
#define MESH_PORT 5555
|
|
257
|
-
|
|
258
|
-
// External WiFi credentials
|
|
259
|
-
#define STATION_SSID "YourHomeWiFi"
|
|
260
|
-
#define STATION_PASSWORD "YourWiFiPassword"
|
|
261
|
-
|
|
262
|
-
Scheduler userScheduler;
|
|
263
|
-
painlessMesh mesh;
|
|
264
|
-
|
|
265
|
-
// Task to report bridge status
|
|
266
|
-
Task taskBridgeStatus(30000, TASK_FOREVER, [](){
|
|
267
|
-
String status = "{";
|
|
268
|
-
status += "\"type\":\"bridge_status\",";
|
|
269
|
-
status += "\"nodeId\":" + String(mesh.getNodeId()) + ",";
|
|
270
|
-
status += "\"wifi_connected\":" + String(WiFi.status() == WL_CONNECTED ? "true" : "false") + ",";
|
|
271
|
-
status += "\"wifi_rssi\":" + String(WiFi.RSSI()) + ",";
|
|
272
|
-
status += "\"mesh_connections\":" + String(mesh.getNodeList().size()) + ",";
|
|
273
|
-
status += "\"timestamp\":" + String(mesh.getNodeTime());
|
|
274
|
-
status += "}";
|
|
275
|
-
|
|
276
|
-
mesh.sendBroadcast(status);
|
|
277
|
-
Serial.printf("Bridge Status: WiFi=%s, RSSI=%d, Mesh Nodes=%d\n",
|
|
278
|
-
WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected",
|
|
279
|
-
WiFi.RSSI(), mesh.getNodeList().size());
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
void receivedCallback(uint32_t from, String &msg) {
|
|
283
|
-
Serial.printf("Bridge: Received from %u: %s\n", from, msg.c_str());
|
|
284
|
-
|
|
285
|
-
// Forward sensor data to external server (example)
|
|
286
|
-
if (msg.indexOf("\"type\":\"sensor\"") > 0 && WiFi.status() == WL_CONNECTED) {
|
|
287
|
-
// Here you could forward to HTTP/MQTT/etc
|
|
288
|
-
Serial.println("Would forward sensor data to external server");
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
void newConnectionCallback(uint32_t nodeId) {
|
|
293
|
-
Serial.printf("Bridge: New mesh connection to %u\n", nodeId);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
void changedConnectionCallback() {
|
|
297
|
-
Serial.printf("Bridge: Mesh topology changed. Nodes: %s\n",
|
|
298
|
-
mesh.subConnectionJson().c_str());
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
void setup() {
|
|
302
|
-
Serial.begin(115200);
|
|
303
|
-
Serial.println("=== Bridge Node Starting ===");
|
|
304
|
-
|
|
305
|
-
// Initialize mesh
|
|
306
|
-
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
307
|
-
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
|
|
308
|
-
mesh.onReceive(&receivedCallback);
|
|
309
|
-
mesh.onNewConnection(&newConnectionCallback);
|
|
310
|
-
mesh.onChangedConnections(&changedConnectionCallback);
|
|
311
|
-
|
|
312
|
-
// Connect to external WiFi
|
|
313
|
-
WiFi.begin(STATION_SSID, STATION_PASSWORD);
|
|
314
|
-
Serial.printf("Connecting to WiFi: %s", STATION_SSID);
|
|
315
|
-
|
|
316
|
-
while (WiFi.status() != WL_CONNECTED) {
|
|
317
|
-
delay(500);
|
|
318
|
-
Serial.print(".");
|
|
319
|
-
}
|
|
320
|
-
Serial.println();
|
|
321
|
-
Serial.printf("WiFi connected! IP: %s\n", WiFi.localIP().toString().c_str());
|
|
322
|
-
|
|
323
|
-
userScheduler.addTask(taskBridgeStatus);
|
|
324
|
-
taskBridgeStatus.enable();
|
|
325
|
-
|
|
326
|
-
Serial.printf("Bridge Node initialized. Node ID: %u\n", mesh.getNodeId());
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
void loop() {
|
|
330
|
-
mesh.update();
|
|
331
|
-
}
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
## Deployment Steps
|
|
335
|
-
|
|
336
|
-
1. **Upload Sensor Node code** to your first ESP32/ESP8266
|
|
337
|
-
2. **Upload Controller Node code** to your second device
|
|
338
|
-
3. **Upload Bridge Node code** to your third device (update WiFi credentials first!)
|
|
339
|
-
4. **Power up all devices** and open Serial Monitors to watch them connect
|
|
340
|
-
5. **Observe the mesh in action**:
|
|
341
|
-
- Sensor nodes broadcast environmental data
|
|
342
|
-
- Controller receives and processes sensor data
|
|
343
|
-
- Bridge provides external connectivity and status updates
|
|
344
|
-
|
|
345
|
-
## What You'll See
|
|
346
|
-
|
|
347
|
-
### Sensor Node Output
|
|
348
|
-
```
|
|
349
|
-
=== Sensor Node Starting ===
|
|
350
|
-
Sensor Node initialized. Node ID: 123456789
|
|
351
|
-
Sensor Node: New connection to 987654321
|
|
352
|
-
Sent sensor data: T=23.2°C, H=67.4%
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
### Controller Node Output
|
|
356
|
-
```
|
|
357
|
-
=== Controller Node Starting ===
|
|
358
|
-
Controller Node initialized. Node ID: 987654321
|
|
359
|
-
Requested sensor data from all nodes
|
|
360
|
-
Controller: Received from 123456789: {"type":"sensor",...}
|
|
361
|
-
=== Collected Sensor Data ===
|
|
362
|
-
Node 123456789 (Sensor 1001): T=23.2°C, H=67.4%, Age=5 seconds
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
### Bridge Node Output
|
|
366
|
-
```
|
|
367
|
-
=== Bridge Node Starting ===
|
|
368
|
-
Connecting to WiFi: YourHomeWiFi....
|
|
369
|
-
WiFi connected! IP: 192.168.1.100
|
|
370
|
-
Bridge Node initialized. Node ID: 555444333
|
|
371
|
-
Bridge Status: WiFi=Connected, RSSI=-45, Mesh Nodes=2
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
## Key Features Demonstrated
|
|
375
|
-
|
|
376
|
-
- **Automatic Discovery**: Nodes find each other automatically
|
|
377
|
-
- **Message Broadcasting**: Sensor data reaches all interested nodes
|
|
378
|
-
- **JSON Communication**: Structured data exchange
|
|
379
|
-
- **Command System**: Controller can request data from sensors
|
|
380
|
-
- **External Connectivity**: Bridge connects mesh to Internet
|
|
381
|
-
- **Self-Healing**: Network continues working if nodes disconnect
|
|
382
|
-
|
|
383
|
-
## Extending Your Mesh
|
|
384
|
-
|
|
385
|
-
### Add More Sensors
|
|
386
|
-
- Temperature/humidity sensors (DHT22)
|
|
387
|
-
- Motion detectors (PIR)
|
|
388
|
-
- Light sensors (photoresistor)
|
|
389
|
-
- Soil moisture sensors
|
|
390
|
-
|
|
391
|
-
### Add Actuators
|
|
392
|
-
- LED strips for notifications
|
|
393
|
-
- Servo motors for mechanical control
|
|
394
|
-
- Relays for switching devices
|
|
395
|
-
- Buzzers for alerts
|
|
396
|
-
|
|
397
|
-
### External Integrations
|
|
398
|
-
- MQTT broker connectivity
|
|
399
|
-
- HTTP REST API calls
|
|
400
|
-
- Home Assistant integration
|
|
401
|
-
- Cloud database logging
|
|
402
|
-
|
|
403
|
-
## Next Steps
|
|
404
|
-
|
|
405
|
-
- Explore [Custom Packages](../tutorials/custom-packages.md) for type-safe messaging
|
|
406
|
-
- Learn about [Alteriom Extensions](../alteriom/overview.md) for pre-built sensor packages
|
|
407
|
-
- Dive into [Advanced Topics](../advanced/performance.md) for optimization
|
|
408
|
-
- Check out [Troubleshooting](../troubleshooting/common-issues.md) if you encounter issues
|
|
409
|
-
|
|
1
|
+
# Your First Mesh Network
|
|
2
|
+
|
|
3
|
+
This tutorial builds on the [Quick Start Guide](quickstart.md) to create a more comprehensive mesh network with multiple types of nodes and practical functionality.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
We'll build a mesh network with three types of nodes:
|
|
8
|
+
1. **Sensor Node** - Collects and broadcasts environmental data
|
|
9
|
+
2. **Controller Node** - Receives sensor data and controls devices
|
|
10
|
+
3. **Bridge Node** - Connects mesh to external networks (WiFi/Internet)
|
|
11
|
+
|
|
12
|
+
## Node 1: Sensor Node
|
|
13
|
+
|
|
14
|
+
This node simulates environmental sensors and broadcasts data to the mesh.
|
|
15
|
+
|
|
16
|
+
```cpp
|
|
17
|
+
#include "painlessMesh.h"
|
|
18
|
+
|
|
19
|
+
#define MESH_PREFIX "MyMeshNetwork"
|
|
20
|
+
#define MESH_PASSWORD "somethingSneaky"
|
|
21
|
+
#define MESH_PORT 5555
|
|
22
|
+
|
|
23
|
+
Scheduler userScheduler;
|
|
24
|
+
painlessMesh mesh;
|
|
25
|
+
|
|
26
|
+
// Sensor simulation
|
|
27
|
+
float temperature = 22.5;
|
|
28
|
+
float humidity = 65.0;
|
|
29
|
+
uint32_t sensorId = 1001;
|
|
30
|
+
|
|
31
|
+
// Task to send sensor data every 30 seconds
|
|
32
|
+
Task taskSendSensor(30000, TASK_FOREVER, [](){
|
|
33
|
+
// Simulate sensor readings with some variation
|
|
34
|
+
temperature += random(-10, 10) / 10.0;
|
|
35
|
+
humidity += random(-50, 50) / 10.0;
|
|
36
|
+
|
|
37
|
+
// Keep values in reasonable ranges
|
|
38
|
+
temperature = constrain(temperature, 15.0, 35.0);
|
|
39
|
+
humidity = constrain(humidity, 30.0, 90.0);
|
|
40
|
+
|
|
41
|
+
// Create JSON message
|
|
42
|
+
String msg = "{";
|
|
43
|
+
msg += "\"type\":\"sensor\",";
|
|
44
|
+
msg += "\"nodeId\":" + String(mesh.getNodeId()) + ",";
|
|
45
|
+
msg += "\"sensorId\":" + String(sensorId) + ",";
|
|
46
|
+
msg += "\"temperature\":" + String(temperature, 1) + ",";
|
|
47
|
+
msg += "\"humidity\":" + String(humidity, 1) + ",";
|
|
48
|
+
msg += "\"timestamp\":" + String(mesh.getNodeTime());
|
|
49
|
+
msg += "}";
|
|
50
|
+
|
|
51
|
+
mesh.sendBroadcast(msg);
|
|
52
|
+
Serial.printf("Sent sensor data: T=%.1f°C, H=%.1f%%\n", temperature, humidity);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
void receivedCallback(uint32_t from, String &msg) {
|
|
56
|
+
Serial.printf("Sensor Node: Received from %u: %s\n", from, msg.c_str());
|
|
57
|
+
|
|
58
|
+
// Sensor nodes can respond to commands
|
|
59
|
+
if (msg.indexOf("\"command\":\"read_sensor\"") > 0) {
|
|
60
|
+
// Force immediate sensor reading
|
|
61
|
+
taskSendSensor.forceNextIteration();
|
|
62
|
+
Serial.println("Forced sensor reading requested");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void newConnectionCallback(uint32_t nodeId) {
|
|
67
|
+
Serial.printf("Sensor Node: New connection to %u\n", nodeId);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
void changedConnectionCallback() {
|
|
71
|
+
Serial.printf("Sensor Node: Changed connections. Nodes: %s\n",
|
|
72
|
+
mesh.subConnectionJson().c_str());
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
void setup() {
|
|
76
|
+
Serial.begin(115200);
|
|
77
|
+
Serial.println("=== Sensor Node Starting ===");
|
|
78
|
+
|
|
79
|
+
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
80
|
+
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
|
|
81
|
+
mesh.onReceive(&receivedCallback);
|
|
82
|
+
mesh.onNewConnection(&newConnectionCallback);
|
|
83
|
+
mesh.onChangedConnections(&changedConnectionCallback);
|
|
84
|
+
|
|
85
|
+
userScheduler.addTask(taskSendSensor);
|
|
86
|
+
taskSendSensor.enable();
|
|
87
|
+
|
|
88
|
+
Serial.printf("Sensor Node initialized. Node ID: %u\n", mesh.getNodeId());
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
void loop() {
|
|
92
|
+
mesh.update();
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Node 2: Controller Node
|
|
97
|
+
|
|
98
|
+
This node receives sensor data and can send commands to other nodes.
|
|
99
|
+
|
|
100
|
+
```cpp
|
|
101
|
+
#include "painlessMesh.h"
|
|
102
|
+
|
|
103
|
+
#define MESH_PREFIX "MyMeshNetwork"
|
|
104
|
+
#define MESH_PASSWORD "somethingSneaky"
|
|
105
|
+
#define MESH_PORT 5555
|
|
106
|
+
|
|
107
|
+
Scheduler userScheduler;
|
|
108
|
+
painlessMesh mesh;
|
|
109
|
+
|
|
110
|
+
// Storage for sensor data
|
|
111
|
+
struct SensorData {
|
|
112
|
+
uint32_t nodeId;
|
|
113
|
+
uint32_t sensorId;
|
|
114
|
+
float temperature;
|
|
115
|
+
float humidity;
|
|
116
|
+
uint32_t timestamp;
|
|
117
|
+
bool valid;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
SensorData sensors[10]; // Store data from up to 10 sensors
|
|
121
|
+
int sensorCount = 0;
|
|
122
|
+
|
|
123
|
+
// Task to request sensor data every 60 seconds
|
|
124
|
+
Task taskRequestData(60000, TASK_FOREVER, [](){
|
|
125
|
+
String cmd = "{";
|
|
126
|
+
cmd += "\"type\":\"command\",";
|
|
127
|
+
cmd += "\"command\":\"read_sensor\",";
|
|
128
|
+
cmd += "\"from\":" + String(mesh.getNodeId());
|
|
129
|
+
cmd += "}";
|
|
130
|
+
|
|
131
|
+
mesh.sendBroadcast(cmd);
|
|
132
|
+
Serial.println("Requested sensor data from all nodes");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Task to display collected data every 45 seconds
|
|
136
|
+
Task taskDisplayData(45000, TASK_FOREVER, [](){
|
|
137
|
+
Serial.println("=== Collected Sensor Data ===");
|
|
138
|
+
for (int i = 0; i < sensorCount; i++) {
|
|
139
|
+
if (sensors[i].valid) {
|
|
140
|
+
Serial.printf("Node %u (Sensor %u): T=%.1f°C, H=%.1f%%, Age=%u seconds\n",
|
|
141
|
+
sensors[i].nodeId, sensors[i].sensorId,
|
|
142
|
+
sensors[i].temperature, sensors[i].humidity,
|
|
143
|
+
(mesh.getNodeTime() - sensors[i].timestamp) / 1000000);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
Serial.println("============================");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
void storeSensorData(uint32_t nodeId, uint32_t sensorId, float temp, float hum, uint32_t timestamp) {
|
|
150
|
+
// Find existing entry or create new one
|
|
151
|
+
int index = -1;
|
|
152
|
+
for (int i = 0; i < sensorCount; i++) {
|
|
153
|
+
if (sensors[i].nodeId == nodeId && sensors[i].sensorId == sensorId) {
|
|
154
|
+
index = i;
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (index == -1 && sensorCount < 10) {
|
|
160
|
+
index = sensorCount++;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (index != -1) {
|
|
164
|
+
sensors[index].nodeId = nodeId;
|
|
165
|
+
sensors[index].sensorId = sensorId;
|
|
166
|
+
sensors[index].temperature = temp;
|
|
167
|
+
sensors[index].humidity = hum;
|
|
168
|
+
sensors[index].timestamp = timestamp;
|
|
169
|
+
sensors[index].valid = true;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
void receivedCallback(uint32_t from, String &msg) {
|
|
174
|
+
Serial.printf("Controller: Received from %u: %s\n", from, msg.c_str());
|
|
175
|
+
|
|
176
|
+
// Parse sensor data
|
|
177
|
+
if (msg.indexOf("\"type\":\"sensor\"") > 0) {
|
|
178
|
+
// Simple JSON parsing (in production, use ArduinoJson library)
|
|
179
|
+
int tempStart = msg.indexOf("\"temperature\":") + 14;
|
|
180
|
+
int tempEnd = msg.indexOf(",", tempStart);
|
|
181
|
+
float temperature = msg.substring(tempStart, tempEnd).toFloat();
|
|
182
|
+
|
|
183
|
+
int humStart = msg.indexOf("\"humidity\":") + 11;
|
|
184
|
+
int humEnd = msg.indexOf(",", humStart);
|
|
185
|
+
float humidity = msg.substring(humStart, humEnd).toFloat();
|
|
186
|
+
|
|
187
|
+
int sensorStart = msg.indexOf("\"sensorId\":") + 11;
|
|
188
|
+
int sensorEnd = msg.indexOf(",", sensorStart);
|
|
189
|
+
uint32_t sensorId = msg.substring(sensorStart, sensorEnd).toInt();
|
|
190
|
+
|
|
191
|
+
int timeStart = msg.indexOf("\"timestamp\":") + 12;
|
|
192
|
+
int timeEnd = msg.indexOf("}", timeStart);
|
|
193
|
+
uint32_t timestamp = msg.substring(timeStart, timeEnd).toInt();
|
|
194
|
+
|
|
195
|
+
storeSensorData(from, sensorId, temperature, humidity, timestamp);
|
|
196
|
+
|
|
197
|
+
// Trigger actions based on sensor data
|
|
198
|
+
if (temperature > 30.0) {
|
|
199
|
+
Serial.println("WARNING: High temperature detected!");
|
|
200
|
+
// Could send cooling command here
|
|
201
|
+
}
|
|
202
|
+
if (humidity > 80.0) {
|
|
203
|
+
Serial.println("WARNING: High humidity detected!");
|
|
204
|
+
// Could trigger ventilation here
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
void newConnectionCallback(uint32_t nodeId) {
|
|
210
|
+
Serial.printf("Controller: New connection to %u\n", nodeId);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
void changedConnectionCallback() {
|
|
214
|
+
Serial.printf("Controller: Changed connections. Nodes: %s\n",
|
|
215
|
+
mesh.subConnectionJson().c_str());
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
void setup() {
|
|
219
|
+
Serial.begin(115200);
|
|
220
|
+
Serial.println("=== Controller Node Starting ===");
|
|
221
|
+
|
|
222
|
+
// Initialize sensor storage
|
|
223
|
+
for (int i = 0; i < 10; i++) {
|
|
224
|
+
sensors[i].valid = false;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
228
|
+
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
|
|
229
|
+
mesh.onReceive(&receivedCallback);
|
|
230
|
+
mesh.onNewConnection(&newConnectionCallback);
|
|
231
|
+
mesh.onChangedConnections(&changedConnectionCallback);
|
|
232
|
+
|
|
233
|
+
userScheduler.addTask(taskRequestData);
|
|
234
|
+
userScheduler.addTask(taskDisplayData);
|
|
235
|
+
taskRequestData.enable();
|
|
236
|
+
taskDisplayData.enable();
|
|
237
|
+
|
|
238
|
+
Serial.printf("Controller Node initialized. Node ID: %u\n", mesh.getNodeId());
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
void loop() {
|
|
242
|
+
mesh.update();
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Node 3: Bridge Node
|
|
247
|
+
|
|
248
|
+
This node connects the mesh to WiFi/Internet for external connectivity.
|
|
249
|
+
|
|
250
|
+
```cpp
|
|
251
|
+
#include "painlessMesh.h"
|
|
252
|
+
#include <WiFi.h> // Use <ESP8266WiFi.h> for ESP8266
|
|
253
|
+
|
|
254
|
+
#define MESH_PREFIX "MyMeshNetwork"
|
|
255
|
+
#define MESH_PASSWORD "somethingSneaky"
|
|
256
|
+
#define MESH_PORT 5555
|
|
257
|
+
|
|
258
|
+
// External WiFi credentials
|
|
259
|
+
#define STATION_SSID "YourHomeWiFi"
|
|
260
|
+
#define STATION_PASSWORD "YourWiFiPassword"
|
|
261
|
+
|
|
262
|
+
Scheduler userScheduler;
|
|
263
|
+
painlessMesh mesh;
|
|
264
|
+
|
|
265
|
+
// Task to report bridge status
|
|
266
|
+
Task taskBridgeStatus(30000, TASK_FOREVER, [](){
|
|
267
|
+
String status = "{";
|
|
268
|
+
status += "\"type\":\"bridge_status\",";
|
|
269
|
+
status += "\"nodeId\":" + String(mesh.getNodeId()) + ",";
|
|
270
|
+
status += "\"wifi_connected\":" + String(WiFi.status() == WL_CONNECTED ? "true" : "false") + ",";
|
|
271
|
+
status += "\"wifi_rssi\":" + String(WiFi.RSSI()) + ",";
|
|
272
|
+
status += "\"mesh_connections\":" + String(mesh.getNodeList().size()) + ",";
|
|
273
|
+
status += "\"timestamp\":" + String(mesh.getNodeTime());
|
|
274
|
+
status += "}";
|
|
275
|
+
|
|
276
|
+
mesh.sendBroadcast(status);
|
|
277
|
+
Serial.printf("Bridge Status: WiFi=%s, RSSI=%d, Mesh Nodes=%d\n",
|
|
278
|
+
WiFi.status() == WL_CONNECTED ? "Connected" : "Disconnected",
|
|
279
|
+
WiFi.RSSI(), mesh.getNodeList().size());
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
void receivedCallback(uint32_t from, String &msg) {
|
|
283
|
+
Serial.printf("Bridge: Received from %u: %s\n", from, msg.c_str());
|
|
284
|
+
|
|
285
|
+
// Forward sensor data to external server (example)
|
|
286
|
+
if (msg.indexOf("\"type\":\"sensor\"") > 0 && WiFi.status() == WL_CONNECTED) {
|
|
287
|
+
// Here you could forward to HTTP/MQTT/etc
|
|
288
|
+
Serial.println("Would forward sensor data to external server");
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
void newConnectionCallback(uint32_t nodeId) {
|
|
293
|
+
Serial.printf("Bridge: New mesh connection to %u\n", nodeId);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
void changedConnectionCallback() {
|
|
297
|
+
Serial.printf("Bridge: Mesh topology changed. Nodes: %s\n",
|
|
298
|
+
mesh.subConnectionJson().c_str());
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
void setup() {
|
|
302
|
+
Serial.begin(115200);
|
|
303
|
+
Serial.println("=== Bridge Node Starting ===");
|
|
304
|
+
|
|
305
|
+
// Initialize mesh
|
|
306
|
+
mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
|
|
307
|
+
mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
|
|
308
|
+
mesh.onReceive(&receivedCallback);
|
|
309
|
+
mesh.onNewConnection(&newConnectionCallback);
|
|
310
|
+
mesh.onChangedConnections(&changedConnectionCallback);
|
|
311
|
+
|
|
312
|
+
// Connect to external WiFi
|
|
313
|
+
WiFi.begin(STATION_SSID, STATION_PASSWORD);
|
|
314
|
+
Serial.printf("Connecting to WiFi: %s", STATION_SSID);
|
|
315
|
+
|
|
316
|
+
while (WiFi.status() != WL_CONNECTED) {
|
|
317
|
+
delay(500);
|
|
318
|
+
Serial.print(".");
|
|
319
|
+
}
|
|
320
|
+
Serial.println();
|
|
321
|
+
Serial.printf("WiFi connected! IP: %s\n", WiFi.localIP().toString().c_str());
|
|
322
|
+
|
|
323
|
+
userScheduler.addTask(taskBridgeStatus);
|
|
324
|
+
taskBridgeStatus.enable();
|
|
325
|
+
|
|
326
|
+
Serial.printf("Bridge Node initialized. Node ID: %u\n", mesh.getNodeId());
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
void loop() {
|
|
330
|
+
mesh.update();
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Deployment Steps
|
|
335
|
+
|
|
336
|
+
1. **Upload Sensor Node code** to your first ESP32/ESP8266
|
|
337
|
+
2. **Upload Controller Node code** to your second device
|
|
338
|
+
3. **Upload Bridge Node code** to your third device (update WiFi credentials first!)
|
|
339
|
+
4. **Power up all devices** and open Serial Monitors to watch them connect
|
|
340
|
+
5. **Observe the mesh in action**:
|
|
341
|
+
- Sensor nodes broadcast environmental data
|
|
342
|
+
- Controller receives and processes sensor data
|
|
343
|
+
- Bridge provides external connectivity and status updates
|
|
344
|
+
|
|
345
|
+
## What You'll See
|
|
346
|
+
|
|
347
|
+
### Sensor Node Output
|
|
348
|
+
```
|
|
349
|
+
=== Sensor Node Starting ===
|
|
350
|
+
Sensor Node initialized. Node ID: 123456789
|
|
351
|
+
Sensor Node: New connection to 987654321
|
|
352
|
+
Sent sensor data: T=23.2°C, H=67.4%
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Controller Node Output
|
|
356
|
+
```
|
|
357
|
+
=== Controller Node Starting ===
|
|
358
|
+
Controller Node initialized. Node ID: 987654321
|
|
359
|
+
Requested sensor data from all nodes
|
|
360
|
+
Controller: Received from 123456789: {"type":"sensor",...}
|
|
361
|
+
=== Collected Sensor Data ===
|
|
362
|
+
Node 123456789 (Sensor 1001): T=23.2°C, H=67.4%, Age=5 seconds
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Bridge Node Output
|
|
366
|
+
```
|
|
367
|
+
=== Bridge Node Starting ===
|
|
368
|
+
Connecting to WiFi: YourHomeWiFi....
|
|
369
|
+
WiFi connected! IP: 192.168.1.100
|
|
370
|
+
Bridge Node initialized. Node ID: 555444333
|
|
371
|
+
Bridge Status: WiFi=Connected, RSSI=-45, Mesh Nodes=2
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Key Features Demonstrated
|
|
375
|
+
|
|
376
|
+
- **Automatic Discovery**: Nodes find each other automatically
|
|
377
|
+
- **Message Broadcasting**: Sensor data reaches all interested nodes
|
|
378
|
+
- **JSON Communication**: Structured data exchange
|
|
379
|
+
- **Command System**: Controller can request data from sensors
|
|
380
|
+
- **External Connectivity**: Bridge connects mesh to Internet
|
|
381
|
+
- **Self-Healing**: Network continues working if nodes disconnect
|
|
382
|
+
|
|
383
|
+
## Extending Your Mesh
|
|
384
|
+
|
|
385
|
+
### Add More Sensors
|
|
386
|
+
- Temperature/humidity sensors (DHT22)
|
|
387
|
+
- Motion detectors (PIR)
|
|
388
|
+
- Light sensors (photoresistor)
|
|
389
|
+
- Soil moisture sensors
|
|
390
|
+
|
|
391
|
+
### Add Actuators
|
|
392
|
+
- LED strips for notifications
|
|
393
|
+
- Servo motors for mechanical control
|
|
394
|
+
- Relays for switching devices
|
|
395
|
+
- Buzzers for alerts
|
|
396
|
+
|
|
397
|
+
### External Integrations
|
|
398
|
+
- MQTT broker connectivity
|
|
399
|
+
- HTTP REST API calls
|
|
400
|
+
- Home Assistant integration
|
|
401
|
+
- Cloud database logging
|
|
402
|
+
|
|
403
|
+
## Next Steps
|
|
404
|
+
|
|
405
|
+
- Explore [Custom Packages](../tutorials/custom-packages.md) for type-safe messaging
|
|
406
|
+
- Learn about [Alteriom Extensions](../alteriom/overview.md) for pre-built sensor packages
|
|
407
|
+
- Dive into [Advanced Topics](../advanced/performance.md) for optimization
|
|
408
|
+
- Check out [Troubleshooting](../troubleshooting/common-issues.md) if you encounter issues
|
|
409
|
+
|
|
410
410
|
Congratulations! You now have a working multi-node mesh network with real-world functionality.
|