@alteriom/painlessmesh 1.8.4 → 1.8.5

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 CHANGED
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.8.5] - 2025-11-12
11
+
12
+ ### Fixed
13
+
14
+ - **ntpTimeSyncBridge and ntpTimeSyncNode Compilation (Issue #108)** - Arduino IDE compilation errors fixed
15
+ - Fixed include path in ntpTimeSyncBridge.ino from `"examples/alteriom/alteriom_sensor_package.hpp"` to `"alteriom_sensor_package.hpp"`
16
+ - Fixed include path in ntpTimeSyncNode.ino from `"examples/alteriom/alteriom_sensor_package.hpp"` to `"alteriom_sensor_package.hpp"`
17
+ - Arduino IDE compiles sketches with sketch directory as working directory, requiring local header files
18
+ - Resolves @woodlist's compilation error: "No such file or directory"
19
+
20
+ - **Arduino String Method Compatibility** - Fixed incompatible method call in wifi.hpp
21
+ - Changed `stationSSID.empty()` to `stationSSID.isEmpty()` in src/arduino/wifi.hpp line 171
22
+ - Arduino's String class uses `isEmpty()` method instead of STL's `empty()`
23
+ - Fixes CI build failures for ESP32/ESP8266 examples
24
+ - Related to station credentials feature added in #113
25
+
26
+ ### Documentation
27
+
28
+ - **Example Sketches** - Updated NTP time synchronization examples
29
+ - ntpTimeSyncBridge now compiles correctly in Arduino IDE
30
+ - ntpTimeSyncNode now compiles correctly in Arduino IDE
31
+ - Examples: `examples/ntpTimeSyncBridge/`, `examples/ntpTimeSyncNode/`
32
+
10
33
  ## [1.8.4] - 2025-11-12
11
34
 
12
35
  ### Fixed
@@ -0,0 +1 @@
1
+ Created
@@ -0,0 +1,182 @@
1
+ # Station Credentials Design Rationale
2
+
3
+ ## Question
4
+
5
+ Why does `mesh.init()` require a separate `mesh.stationManual()` call to connect to a router, instead of accepting station credentials directly?
6
+
7
+ ## Answer: Multiple Valid Approaches
8
+
9
+ The library now supports **three approaches** for connecting a bridge node to a router, each with different use cases:
10
+
11
+ ### 1. Separate stationManual() Call (Original Design)
12
+
13
+ ```cpp
14
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT, WIFI_AP_STA, 6);
15
+ mesh.stationManual(STATION_SSID, STATION_PASSWORD);
16
+ mesh.setRoot(true);
17
+ mesh.setContainsRoot(true);
18
+ ```
19
+
20
+ **When to use:**
21
+ - Maximum flexibility - can change router connection without reinitializing mesh
22
+ - Dynamic router selection at runtime
23
+ - Need to call `setHostname()` or other WiFi configuration between init and connection
24
+ - Following existing examples or legacy code
25
+
26
+ **Advantages:**
27
+ - Separation of concerns: mesh setup vs router connection
28
+ - Can reconnect to different routers without mesh reinitialization
29
+ - More control over connection timing and error handling
30
+
31
+ ### 2. Optional Parameters in init() (New Convenience Feature)
32
+
33
+ ```cpp
34
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT,
35
+ WIFI_AP_STA, 6, 0, MAX_CONN,
36
+ STATION_SSID, STATION_PASSWORD); // Optional parameters
37
+ mesh.setRoot(true);
38
+ mesh.setContainsRoot(true);
39
+ ```
40
+
41
+ **When to use:**
42
+ - Simple bridge setup with known credentials
43
+ - Static configuration (credentials won't change)
44
+ - Want slightly more concise code
45
+ - Don't need hostname or other WiFi customization
46
+
47
+ **Advantages:**
48
+ - One line instead of two for basic bridge setup
49
+ - All connection parameters in one place
50
+ - Still maintains full flexibility of other options
51
+
52
+ ### 3. initAsBridge() Method (Recommended for New Projects)
53
+
54
+ ```cpp
55
+ mesh.initAsBridge(MESH_PREFIX, MESH_PASSWORD,
56
+ STATION_SSID, STATION_PASSWORD,
57
+ &userScheduler, MESH_PORT);
58
+ ```
59
+
60
+ **When to use:**
61
+ - New bridge implementations (recommended)
62
+ - Want automatic channel detection
63
+ - Need simplest possible setup
64
+ - Following modern best practices
65
+
66
+ **Advantages:**
67
+ - **Automatic channel detection** - no manual channel configuration needed
68
+ - Automatically sets node as root
69
+ - Maintains router connection through channel switches
70
+ - Broadcasts bridge status (Type 610) automatically
71
+ - Comprehensive initialization in one call
72
+
73
+ ## Design Rationale for Original Separation
74
+
75
+ The original design separated `init()` and `stationManual()` for good architectural reasons:
76
+
77
+ ### 1. Separation of Concerns
78
+
79
+ **Mesh Setup (`init()`):**
80
+ - Creates mesh network (AP mode)
81
+ - Sets up mesh routing and protocol
82
+ - Configures mesh-specific parameters
83
+ - Lifetime: typically never changes
84
+
85
+ **Router Connection (`stationManual()`):**
86
+ - Connects to external WiFi (STA mode)
87
+ - Different lifecycle - may connect/disconnect/change
88
+ - Network-specific credentials and settings
89
+ - Can be reconfigured at runtime
90
+
91
+ This separation allows clean code organization and different lifecycles for each concern.
92
+
93
+ ### 2. Not All Nodes Need Router Connection
94
+
95
+ In a typical mesh network:
96
+ - **1 bridge node**: Needs router connection (AP+STA mode)
97
+ - **N regular nodes**: Mesh only (AP mode, or AP+STA for mesh connections)
98
+
99
+ Regular nodes use:
100
+ ```cpp
101
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT, WIFI_AP_STA);
102
+ // No stationManual() call - not a bridge
103
+ ```
104
+
105
+ If `init()` always required station credentials, it would be confusing for regular nodes.
106
+
107
+ ### 3. Dynamic Router Switching
108
+
109
+ Some advanced use cases require changing router connections at runtime:
110
+
111
+ ```cpp
112
+ // Initial setup
113
+ mesh.init(...);
114
+ mesh.stationManual("Router1", "pass1");
115
+
116
+ // Later, switch to different router
117
+ mesh.stationManual("Router2", "pass2");
118
+
119
+ // Or respond to failover
120
+ void onRouterDisconnect() {
121
+ mesh.stationManual(backupSSID, backupPassword);
122
+ }
123
+ ```
124
+
125
+ With station credentials baked into `init()`, this flexibility would be lost.
126
+
127
+ ### 4. Additional WiFi Configuration
128
+
129
+ Many users need to configure WiFi settings between initialization and connection:
130
+
131
+ ```cpp
132
+ mesh.init(...);
133
+ mesh.setHostname("MESH_BRIDGE"); // Must be before stationManual()
134
+ mesh.stationManual(...);
135
+ ```
136
+
137
+ The separation provides a natural place for these configurations.
138
+
139
+ ### 5. Error Handling and Retry Logic
140
+
141
+ Separating the calls allows better error handling:
142
+
143
+ ```cpp
144
+ mesh.init(...); // This typically doesn't fail
145
+
146
+ // Retry router connection with backoff
147
+ for (int retry = 0; retry < 3; retry++) {
148
+ if (tryStationConnect()) break;
149
+ delay(1000 * (retry + 1));
150
+ }
151
+ ```
152
+
153
+ ## Comparison Table
154
+
155
+ | Approach | Setup Complexity | Flexibility | Channel Detection | Best For |
156
+ |----------|-----------------|-------------|-------------------|----------|
157
+ | **stationManual()** | Medium | Highest | Manual | Dynamic configs, legacy code |
158
+ | **init() params** | Low-Medium | High | Manual | Simple static bridges |
159
+ | **initAsBridge()** | Lowest | Medium | Automatic | New projects, recommended |
160
+
161
+ ## Recommendation
162
+
163
+ **For new projects:** Use `initAsBridge()` - it's the modern, recommended approach with automatic channel detection.
164
+
165
+ **For existing projects:** The original `init()` + `stationManual()` pattern remains fully supported and appropriate.
166
+
167
+ **For simple bridges:** The new optional parameters in `init()` provide a middle ground with good flexibility.
168
+
169
+ All three approaches are valid and will continue to be supported. Choose based on your specific needs.
170
+
171
+ ## Implementation Note
172
+
173
+ When station credentials are passed to `init()`, the implementation internally calls `stationManual()` after mesh initialization. This maintains consistency and code reuse while providing convenience.
174
+
175
+ ```cpp
176
+ // Inside init() implementation
177
+ if (!stationSSID.empty() && (connectMode & WIFI_STA)) {
178
+ this->stationManual(stationSSID, stationPassword);
179
+ }
180
+ ```
181
+
182
+ This design ensures all three approaches use the same underlying connection logic.
@@ -12,7 +12,7 @@
12
12
  */
13
13
 
14
14
  #include "painlessMesh.h"
15
- #include "examples/alteriom/alteriom_sensor_package.hpp"
15
+ #include "alteriom_sensor_package.hpp"
16
16
 
17
17
  // Mesh configuration
18
18
  #define MESH_PREFIX "AlteriomMesh"
@@ -12,7 +12,7 @@
12
12
  */
13
13
 
14
14
  #include "painlessMesh.h"
15
- #include "examples/alteriom/alteriom_sensor_package.hpp"
15
+ #include "alteriom_sensor_package.hpp"
16
16
 
17
17
  // Mesh configuration
18
18
  #define MESH_PREFIX "AlteriomMesh"
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.4",
9
+ "version": "1.8.5",
10
10
  "frameworks": [
11
11
  "arduino"
12
12
  ],
@@ -1,5 +1,5 @@
1
1
  name=Alteriom PainlessMesh
2
- version=1.8.4
2
+ version=1.8.5
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.4",
3
+ "version": "1.8.5",
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",
@@ -44,7 +44,8 @@ class Mesh : public painlessmesh::Mesh<Connection> {
44
44
  */
45
45
  void init(TSTRING ssid, TSTRING password, uint16_t port = 5555,
46
46
  WiFiMode_t connectMode = WIFI_AP_STA, uint8_t channel = 1,
47
- uint8_t hidden = 0, uint8_t maxconn = MAX_CONN) {
47
+ uint8_t hidden = 0, uint8_t maxconn = MAX_CONN,
48
+ TSTRING stationSSID = "", TSTRING stationPassword = "") {
48
49
  using namespace logger;
49
50
  // Init random generator seed to generate delay variance
50
51
  randomSeed(millis());
@@ -165,6 +166,12 @@ class Mesh : public painlessmesh::Mesh<Connection> {
165
166
  if (connectMode & WIFI_STA) {
166
167
  this->initStation();
167
168
  }
169
+
170
+ // If station credentials provided, connect to router
171
+ if (!stationSSID.isEmpty() && (connectMode & WIFI_STA)) {
172
+ Log(STARTUP, "init(): Connecting to station %s\n", stationSSID.c_str());
173
+ this->stationManual(stationSSID, stationPassword);
174
+ }
168
175
  }
169
176
 
170
177
  /** Initialize the mesh network
@@ -187,9 +194,11 @@ class Mesh : public painlessmesh::Mesh<Connection> {
187
194
  void init(TSTRING ssid, TSTRING password, Scheduler *baseScheduler,
188
195
  uint16_t port = 5555, WiFiMode_t connectMode = WIFI_AP_STA,
189
196
  uint8_t channel = 1, uint8_t hidden = 0,
190
- uint8_t maxconn = MAX_CONN) {
197
+ uint8_t maxconn = MAX_CONN,
198
+ TSTRING stationSSID = "", TSTRING stationPassword = "") {
191
199
  this->setScheduler(baseScheduler);
192
- init(ssid, password, port, connectMode, channel, hidden, maxconn);
200
+ init(ssid, password, port, connectMode, channel, hidden, maxconn,
201
+ stationSSID, stationPassword);
193
202
  }
194
203
 
195
204
  /**