@alteriom/painlessmesh 2.0.1 → 2.0.3

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,151 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.0.3] - 2026-09-11
11
+
12
+ `sendToInternet()` fixes from one user's WhatsApp integration (#450, #452,
13
+ #453), and one the hardware rig found while validating them. **Upgrade if a
14
+ node of yours is a bridge or relays to the Internet**: on 2.0.2 a bridge's own
15
+ sends were refused for 30 s after boot, a service that answered a refusal with
16
+ HTTP 201 was reported as delivered, a destination that does not resolve
17
+ stalled an ESP32 gateway on every attempt, and a bridge that rebooted as a
18
+ regular node swallowed every request its peers still sent it. Every fix was
19
+ reproduced first -- against the new HTTP test point, which CI now runs, or
20
+ over real TCP on the desktop -- and is covered by a row on the hardware farm.
21
+
22
+ ### Fixed
23
+
24
+ - **A bridge's own `sendToInternet()` was refused for the first 30 s after
25
+ `initAsBridge()`** (#450). The Internet health check is armed one line after
26
+ `stationManual()` re-issues `WiFi.begin()`, so its first probe ran while the
27
+ station was still associating and failed, and the next was a full interval
28
+ away. Every send from the bridge in that window fell through to the mesh
29
+ path and was refused with "No active mesh connections" -- #445 again, with
30
+ a 30 s hole instead of forever. `sendToInternet()` and the retry path now
31
+ spend one on-demand probe per interval when the flag says no, and the
32
+ station's got-IP event re-probes at once on a bridge or shared gateway.
33
+ - **A gateway reported a refusal as delivered, and every failure as a bare
34
+ number** (#450, #452). The gateway decided on the HTTP status alone and
35
+ discarded the response body. CallMeBot's WhatsApp API answers "Too many
36
+ requests" with HTTP 201 and HTTP 203, the same page under both, so a refused
37
+ message sent through a gateway on 2.0.2 could be reported as delivered; and
38
+ it answers HTTP 208 to messages it never delivers, which 2.0.2 reported as
39
+ "Ambiguous response" with nothing to say why. The gateway now reads the
40
+ start of the body (bounded to 512 bytes and 250 ms). Only 200, 201, 202 and
41
+ 204 count as delivered, and not when the body says the service refused the
42
+ request; every other 2xx is a failure. Every failure reaches the origin
43
+ node's callback with a one-line, tag-free excerpt of the body -- for example
44
+ `HTTP 201: service refused the request: Oops! Too many requests...` or
45
+ `HTTP 208: not a delivery the gateway can confirm: ...` -- and is logged at
46
+ ERROR level, so a sketch on the default log levels sees what the service
47
+ said.
48
+ - **A destination whose name does not resolve stalled an ESP32 gateway on
49
+ every attempt** (#453). A failed lookup surfaced as `connection refused`
50
+ after the resolver's own patience, which this library cannot bound on ESP32,
51
+ and every attempt -- the origin node's retries and, since the bridge fix
52
+ above, the bridge's own sends -- paid it again, until relayed requests timed
53
+ out on their origin nodes. An ESP32 gateway now resolves the host once,
54
+ reports `DNS lookup failed for <host>`, and refuses that host for 60 s
55
+ without another lookup. ESP8266 is unchanged: its core bounds the lookup by
56
+ the HTTP timeout. The gateway blocking budget is unchanged.
57
+ - **A bridge that rebooted as a regular node swallowed every Internet request
58
+ routed to it.** Found on the hardware rig while validating this release. A
59
+ bridge that reboots, crashes, loses power or is reflashed announces nothing
60
+ -- only a bridge stepping down in-process sends `leaving` -- so its peers
61
+ kept it in their bridge list for the 60 s they trust a status, and could
62
+ prefer it over a live bridge on RSSI. A regular node had no handler for
63
+ gateway requests and dropped them without a reply; each sender waited out
64
+ its 30 s request timeout and reported "Request timed out". Every node now
65
+ answers a gateway request it cannot serve with
66
+ `Node <id> is not an Internet gateway`; the sender forgets that node as a
67
+ gateway and sends again at once through the next one, without spending a
68
+ retry. When it knows no other gateway, the request rides the ordinary retry
69
+ backoff -- on the rig the live bridge was advertised half a second later --
70
+ and fails with `No Internet gateway available: ...` only when none appears.
71
+ - **Mismatched log format arguments in `routePackage()`** (CodeQL
72
+ `cpp/wrong-type-format-argument`). A message that failed to parse was logged
73
+ with its `size_t` lengths through `%d`/`%u` -- the wrong width on 64-bit
74
+ hosts -- and with its `DeserializationError` object passed through `%u`,
75
+ undefined behaviour on every platform, in the ArduinoJson 7 path every
76
+ current build compiles as well as the legacy one CodeQL flagged.
77
+
78
+ ### Changed
79
+
80
+ - **The mock HTTP server is now the gateway test point.** It keeps a delivery
81
+ ledger (`GET /requests/{tag}`) and emulates CallMeBot's status quirks
82
+ (`GET /callmebot/whatsapp.php`, profile chosen by `apikey`). The desktop CI
83
+ job starts it and `PAINLESSMESH_TESTPOINT` points the suite at it, so the
84
+ library's delivery verdict is checked against what the service actually did,
85
+ not against a table of status codes. The Alteriom farm's gateway probe serves
86
+ the same routes.
87
+ - **`Mesh::sendGatewayAck()` is public and portable.** It moved from the ESP
88
+ gateway code into `painlessmesh::Mesh`, because every node now needs it to
89
+ answer a request it cannot serve.
90
+ - **`Log()` is format-checked in the desktop build.** The test build marks it
91
+ printf-like, so CI's `-Wall -Werror` rejects an argument that does not match
92
+ its specifier. Device builds are unchanged: on ESP-IDF 5 `uint32_t` is
93
+ `unsigned long`, and every `%u` of a node id would warn there.
94
+ - **`sendToInternet` example.** The startup WhatsApp retries every 30 s until
95
+ a gateway with Internet is known instead of firing once before a regular
96
+ node has joined, and the cloud endpoint moved to a `CLOUD_URL` define whose
97
+ placeholder is skipped with a message rather than reported as
98
+ `connection refused`.
99
+
100
+ ## [2.0.2] - 2026-09-08
101
+
102
+ Two gateway defects that reached users on 2.0.1, both in code the desktop test
103
+ suite cannot compile, and both now asserted on real hardware. **Upgrade if a
104
+ node of yours is a bridge**: on 2.0.1 a bridge could not use its own uplink at
105
+ all, and any request that failed below HTTP was reported to the origin node as
106
+ `HTTP 65535`.
107
+
108
+ ### Fixed
109
+
110
+ - **A bridge could not reach the Internet through its own uplink** (#445).
111
+ `sendToInternet()` serves a request locally only when `hasLocalInternet()` is
112
+ true. That flag is set by the Internet health checker, and `initAsBridge()`
113
+ never started it — only `initAsSharedGateway()` did — so on a bridge it was
114
+ false for the life of the node. Every request the bridge itself made fell
115
+ through to the mesh-routing path and failed with *"No active mesh
116
+ connections"* whenever no peer had joined yet, which is exactly what a
117
+ single-node sketch does at start-up. `initAsBridge()` now starts the checker,
118
+ without touching a `setInternetCheckTarget()` the sketch made before `init()`.
119
+
120
+ - **A request that never reached a server was reported as `HTTP 65535`** (#446).
121
+ `HTTPClient` returns an `int`: positive is an HTTP status, negative is one of
122
+ its own transport errors (`-1` refused, `-11` read timeout). The gateway
123
+ stored that in a `uint16_t`, so `-1` wrapped to 65535 — a value that passes
124
+ `httpCode > 0`. Three things followed: the origin node was told "HTTP 65535",
125
+ the `errorToString()` branch was unreachable, and `handleGatewayAck()` filed a
126
+ retryable network failure as a permanent HTTP status. A transport failure now
127
+ arrives as `httpStatus 0` with the real reason in the error string, which is
128
+ what the origin node already treats as retryable.
129
+
130
+ - **A lone gateway consumed its retries without issuing a single request.**
131
+ `retryInternetRequest()` knew only the remote path: it required an active mesh
132
+ connection and then routed to a discovered bridge, so a gateway serving its
133
+ own request satisfied neither check and reported *"Max retries exceeded"* in
134
+ place of the transport error that actually happened — the same dishonest
135
+ failure as #446, one layer up. A retry whose gateway is this node now goes
136
+ back to the local handler.
137
+
138
+ ### Changed
139
+
140
+ - The HTTP result classification moved into `gateway::classifyHttpResult()`, so
141
+ the desktop test suite exercises the same function `wifi.hpp` calls. The
142
+ previous test duplicated the classification — and duplicated the `uint16_t`
143
+ with it, which is why it mirrored #446 instead of catching it.
144
+
145
+ ### Validated
146
+
147
+ Both fixes are asserted on the ESP32 farm, not only in desktop tests: a bridge
148
+ must report Internet on its own uplink, must relay its own request through it,
149
+ must do so with **no mesh peer at all**, and must return `httpStatus 0` with a
150
+ real reason for a refused port, an unresolvable host and a destination that
151
+ answers past the timeout. Those rows did not exist when 2.0.1 shipped — the
152
+ gateway suite passed on the run that carried both bugs.
153
+
154
+
10
155
  ## [2.0.1] - 2026-09-07
11
156
 
12
157
  A packaging and documentation release. **No library behaviour changed**: the
package/CONTRIBUTING.md CHANGED
@@ -55,6 +55,21 @@ and OTA behaviour is validated on the Alteriom hardware-in-the-loop farm; a
55
55
  maintainer runs it on a pull request by adding the `run-hil` label, and the
56
56
  release gate is three consecutive clean runs of the whole suite.
57
57
 
58
+ ### The HTTP test point
59
+
60
+ `test/mock-http-server/server.py` is the controlled Internet destination for
61
+ `sendToInternet()` tests at every level. It answers the way real services do,
62
+ including the ways they get it wrong (its CallMeBot emulation returns refusals
63
+ as HTTP 201 and 203, as the real API does), and it keeps a delivery ledger:
64
+ `GET /requests/{tag}` says whether the service actually accepted a request.
65
+ The desktop CI job starts one and exports `PAINLESSMESH_TESTPOINT`, and
66
+ `catch_issue450_testpoint_semantics` makes real HTTP requests to it and
67
+ requires the library's verdict to match the ledger. The farm's gateway probe
68
+ serves the same routes with the same record shape, so a hardware row and a
69
+ desktop scenario are measured against one source of truth. When a gateway bug
70
+ comes in, add the service behaviour that exposed it to the server first, then
71
+ the test that fails against it.
72
+
58
73
  ### Adding tests for new features
59
74
 
60
75
  1. **Unit tests**: add to `test/catch/` for new components.
package/README.md CHANGED
@@ -596,9 +596,13 @@ These are the message types used by applications built on painlessMesh:
596
596
  - **Event Coordination** - Synchronized displays, distributed processing
597
597
  - **Bridge Networks** - Connect mesh to WiFi/Internet/MQTT - [📖 Bridge Guide](BRIDGE_TO_INTERNET.md)
598
598
 
599
- ## Latest Release: v2.0.1 (September 7, 2026)
599
+ ## Latest Release: v2.0.3 (September 11, 2026)
600
600
 
601
- **A packaging fix over 2.0.0 — no library behaviour changed.** 2.0.0's installation instructions named a PlatformIO package that has no 2.0.0 (`alteriom/…` stops at 1.10.0; releases go out under `sparck75`), and its GitHub release carries no library archive because the upload was refused by an immutable release. Both are fixed; upgrading from 2.0.0 is optional.
601
+ **`sendToInternet()` fixes — upgrade if any node of yours is a bridge or relays to the Internet.** On 2.0.2 a bridge's own sends were refused with "No active mesh connections" for the first 30 s after `initAsBridge()`, because the health check's first probe ran while the station was still associating. The gateway also decided delivery on the HTTP status alone: CallMeBot answers a refusal with HTTP 201, so a message it refused could be reported as sent, and every failure reached the origin node as a bare number. The gateway now reads the start of the response body, counts only 200/201/202/204 without a refusing body as delivered, and hands every failure to your callback with the service's own words. A destination whose name does not resolve no longer stalls an ESP32 gateway on every attempt: it is refused for 60 s after one failed lookup. And a bridge that reboots, crashes or is reflashed as a regular node no longer swallows the requests its peers still send it for a minute: it answers that it is not a gateway, and the sender moves to the next one at once.
602
+
603
+ **2.0.2 — two gateway fixes.** On 2.0.1 a bridge could not reach the Internet through its own uplink at all (`initAsBridge()` never started the health checker that `sendToInternet()`'s local path depends on, so a bridge with no peer yet failed with "No active mesh connections"), and any request that failed *below* HTTP — refused, unresolvable, timed out — was reported to the origin node as `HTTP 65535`, a truncated `-1`, which also stopped it from being retried. Both are now asserted on the hardware rig, including a bridge with no mesh peer at all.
604
+
605
+ **2.0.1 — a packaging fix over 2.0.0, no library behaviour changed.** 2.0.0's installation instructions named a PlatformIO package that has no 2.0.0 (`alteriom/…` stops at 1.10.0; releases go out under `sparck75`), and its GitHub release carried no library archive because the upload was refused by an immutable release.
602
606
 
603
607
  **2.0.0 — delivery confirmation, a unified send path, and a mesh that holds together on real hardware**
604
608
 
package/RELEASE_GUIDE.md CHANGED
@@ -38,13 +38,23 @@ These files must always contain the same semantic version:
38
38
  - `library.properties`
39
39
  - `library.json`
40
40
  - `package.json`
41
+ - `package-lock.json` (the root `version` and `packages[""].version`)
42
+ - `src/AlteriomPainlessMesh.h` (the version string and the MAJOR/MINOR/PATCH
43
+ defines a sketch compiles against)
44
+ - `doxygen/Doxyfile` (`PROJECT_NUMBER`, the number on every generated API page)
41
45
 
42
- Use the repository script to change them together:
46
+ Use the repository script to change them together; it updates all six and then
47
+ verifies they agree:
43
48
 
44
49
  ```bash
45
50
  ./scripts/bump-version.sh patch
51
+ ./scripts/bump-version.sh patch 2.0.3 --yes # no prompt, for CI or an agent
46
52
  ```
47
53
 
54
+ `jq` is used when it is installed and awk otherwise, and both paths change only
55
+ the package's own version — never a dependency range. `test/ci/test_bump_version.sh`
56
+ holds that, and the Code Quality job runs it.
57
+
48
58
  You may use `minor`, `major`, or an explicit version when the release plan
49
59
  requires it. Version 2.0 patch releases must remain wire-compatible with the
50
60
  2.0 protocol.
@@ -82,12 +92,24 @@ The pull request must also pass all required GitHub checks, including:
82
92
  - formatting and documentation checks
83
93
  - CodeQL
84
94
  - simulator scenarios
85
- - ESP32, ESP32-C3, and ESP32-S3 hardware-in-the-loop coverage when the change
95
+ - hardware-in-the-loop coverage on the six-family board bank when the change
86
96
  touches radio, routing, gateway, OTA, or platform-specific behavior
87
97
 
88
- For a hardware defect, attach the HIL run identifier and report link to the
89
- pull request. A unit test alone is not sufficient evidence for a radio or
90
- multi-device timing fix.
98
+ ### How the hardware result arrives
99
+
100
+ The Alteriom ESP32 farm is a separate, private repository, so nothing in this
101
+ one triggers it — a public workflow can hold no credential for it. The farm
102
+ watches instead: it picks up `main` and open non-fork pull requests that touch
103
+ `src/`, `examples/`, `test/` or the library metadata, runs the simulator gate
104
+ and then the physical suite, and posts the verdict back as a **`farm/hil`
105
+ commit status** with a link to the run. Expect it within roughly half an hour
106
+ of a push; nothing is required of the author.
107
+
108
+ For a hardware defect, link that run in the pull request. A unit test alone is
109
+ not sufficient evidence for a radio or multi-device timing fix — and a desktop
110
+ test that re-implements the logic it is checking is not evidence at all
111
+ (`catch_http_status_codes.cpp` copied the `uint16_t` that caused #446 and so
112
+ mirrored the bug instead of catching it).
91
113
 
92
114
  ## Review gate
93
115
 
@@ -187,10 +187,10 @@ The callback provides `httpStatus` to indicate the result:
187
187
 
188
188
  **FAILURE (success = false):**
189
189
  - `203 Non-Authoritative Information` - **Cached/proxied response, NOT actual delivery**
190
- - `4xx` - Client error (bad request, unauthorized, not found, etc.)
191
- - `5xx` - Server error (service unavailable, gateway timeout, etc.)
192
190
 
193
- ⚠️ **Important:** HTTP 203 is treated as **FAILURE** because it indicates the response came from a cache or proxy, not from the actual WhatsApp API server. If you see `HTTP Status: 203`, the message was **NOT delivered**.
191
+ ⚠️ **The status alone does not say whether WhatsApp got the message.** CallMeBot answers a refusal (for example "Too many requests") with HTTP 201 or HTTP 203, the same error page under both. The gateway therefore reads the start of the response body: a 2xx whose body says the service refused the request is reported as a failure, with the service's own words in the callback's `error` string, and HTTP 203 stays a failure because a proxy, not the WhatsApp API, may have answered. If your callback prints `HTTP 201: service refused the request: Oops! Too many requests...`, that is CallMeBot talking, and the message was **NOT delivered**. Likewise `HTTP 208: not a delivery the gateway can confirm: ...`: CallMeBot answers 208 to messages that never arrive (issues #450 and #452), so only 200, 201, 202 and 204 with a clean body are reported as sent, and the rest of the line is whatever the service said.
192
+
193
+ Also replace `CLOUD_URL` at the top of the sketch: the placeholder `api.example.com` does not resolve, and until you change it the sketch skips the cloud send and says so instead of reporting `connection refused` every minute.
194
194
 
195
195
  ## Files
196
196
 
@@ -74,6 +74,19 @@
74
74
  #define WHATSAPP_PHONE "+1234567890" // Your phone number with country code
75
75
  #define WHATSAPP_APIKEY "your_api_key" // Your Callmebot API key
76
76
 
77
+ // ============================================
78
+ // Cloud API Configuration
79
+ // ============================================
80
+ // The endpoint the periodic sensor readings are POSTed to. Replace it with
81
+ // your own; the placeholder below does not resolve, so until you do the
82
+ // sketch skips the cloud send and says so rather than reporting
83
+ // "connection refused" every minute (issue #450).
84
+ // Example endpoints:
85
+ // - ThingsBoard: "https://demo.thingsboard.io/api/v1/YOUR_TOKEN/telemetry"
86
+ // - AWS IoT: "https://YOUR_ENDPOINT.iot.us-east-1.amazonaws.com/topics/sensors"
87
+ // - Custom API: "https://api.yourserver.com/sensors/data"
88
+ #define CLOUD_URL "https://api.example.com/sensors"
89
+
77
90
  // ============================================
78
91
  // Sensor Simulation Configuration
79
92
  // ============================================
@@ -115,6 +128,15 @@ String urlEncode(const String& str);
115
128
  // Task to periodically send sensor data (simulated)
116
129
  Task taskSendSensorData(60000, TASK_FOREVER, &sendSensorDataToCloud);
117
130
 
131
+ // The startup WhatsApp used to be a single 30 s one-shot. A regular node that
132
+ // took longer than that to find the mesh -- following a bridge to another
133
+ // channel takes about a minute -- fired it with no gateway in sight and never
134
+ // tried again (issue #450). It now retries until a gateway with Internet is
135
+ // known, then disables itself.
136
+ void sendStartupAlert();
137
+ Task taskStartupAlert(30000, TASK_FOREVER, &sendStartupAlert);
138
+ String startupMsg;
139
+
118
140
  // ============================================
119
141
  // URL Encoding Helper
120
142
  // ============================================
@@ -184,13 +206,12 @@ void sendAlertToWhatsApp(String message) {
184
206
 
185
207
  // Use sendToInternet() to route the request through a gateway
186
208
  // The callback will be invoked when we get a response (or timeout)
187
- //
188
- // SUCCESS CODES: Only specific HTTP codes indicate genuine delivery:
189
- // - 200 OK: Standard success (most common for WhatsApp API)
190
- // - 201 Created, 202 Accepted, 204 No Content
191
- //
192
- // FAILURE: HTTP 203 (Non-Authoritative) is treated as FAILURE because
193
- // it indicates a cached/proxied response, not actual delivery to WhatsApp.
209
+ //
210
+ // The gateway reads the response body, not only the status: CallMeBot
211
+ // answers a refusal ("Too many requests") with HTTP 201 or 203, so a 2xx
212
+ // alone proves nothing. A refusal arrives here as success=false with the
213
+ // service's own words in `error`; HTTP 203 stays a failure because a proxy,
214
+ // not WhatsApp, may have answered.
194
215
  uint32_t msgId = mesh.sendToInternet(
195
216
  url,
196
217
  "", // No payload needed for GET request - params are in URL
@@ -249,14 +270,13 @@ void sendSensorDataToCloud() {
249
270
  return;
250
271
  }
251
272
 
252
- // Send to cloud API (replace with your actual endpoint)
253
- // Example endpoints:
254
- // - ThingsBoard: "https://demo.thingsboard.io/api/v1/YOUR_TOKEN/telemetry"
255
- // - AWS IoT: "https://YOUR_ENDPOINT.iot.us-east-1.amazonaws.com/topics/sensors"
256
- // - Custom API: "https://api.yourserver.com/sensors/data"
257
-
258
- String cloudUrl = "https://api.example.com/sensors"; // Replace with your endpoint
259
-
273
+ // Send to the cloud API configured at the top of the sketch
274
+ String cloudUrl = CLOUD_URL;
275
+ if (cloudUrl.indexOf("example.com") >= 0) {
276
+ Serial.println(" (CLOUD_URL is still the placeholder; set your endpoint to send readings)");
277
+ return;
278
+ }
279
+
260
280
  uint32_t msgId = mesh.sendToInternet(
261
281
  cloudUrl,
262
282
  payload,
@@ -276,6 +296,21 @@ void sendSensorDataToCloud() {
276
296
  // Mesh Callbacks
277
297
  // ============================================
278
298
 
299
+ /**
300
+ * Send the startup notification once a gateway with Internet is known.
301
+ *
302
+ * Runs every 30 s from taskStartupAlert until it has handed the message to
303
+ * sendToInternet(), then disables itself.
304
+ */
305
+ void sendStartupAlert() {
306
+ if (!mesh.hasInternetConnection()) {
307
+ Serial.println("(startup WhatsApp waiting for a gateway with Internet; retrying in 30 s)");
308
+ return;
309
+ }
310
+ sendAlertToWhatsApp(startupMsg);
311
+ taskStartupAlert.disable();
312
+ }
313
+
279
314
  void receivedCallback(uint32_t from, String& msg) {
280
315
  Serial.printf("📨 Received from %u: %s\n", from, msg.c_str());
281
316
  }
@@ -347,14 +382,14 @@ void setup() {
347
382
  Serial.printf("Is Bridge: %s\n", mesh.isBridge() ? "YES" : "NO");
348
383
  Serial.println("================================================\n");
349
384
 
350
- // Send a startup notification via WhatsApp (demonstrates sendToInternet)
351
- String startupMsg = "🚀 Node " + String(mesh.getNodeId()) + " started!";
352
-
353
- // Delay to allow mesh to connect first
354
- Serial.println("Will attempt to send startup WhatsApp in 30 seconds...\n");
355
- mesh.addTask([startupMsg]() {
356
- sendAlertToWhatsApp(startupMsg);
357
- }, 30000); // 30 second delay
385
+ // Send a startup notification via WhatsApp (demonstrates sendToInternet).
386
+ // First attempt in 30 s, then every 30 s until a gateway with Internet is
387
+ // known: a bridge can use its own uplink at once, a regular node has to
388
+ // find the mesh first.
389
+ startupMsg = "🚀 Node " + String(mesh.getNodeId()) + " started!";
390
+ Serial.println("Will send the startup WhatsApp as soon as a gateway with Internet is known (first try in 30 s)...\n");
391
+ userScheduler.addTask(taskStartupAlert);
392
+ taskStartupAlert.enableDelayed();
358
393
  }
359
394
 
360
395
  // ============================================
package/library.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "type": "git",
7
7
  "url": "https://github.com/Alteriom/painlessMesh"
8
8
  },
9
- "version": "2.0.1",
9
+ "version": "2.0.3",
10
10
  "frameworks": [
11
11
  "arduino"
12
12
  ],
@@ -1,5 +1,5 @@
1
1
  name=Alteriom PainlessMesh
2
- version=2.0.1
2
+ version=2.0.3
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": "2.0.1",
3
+ "version": "2.0.3",
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 "2.0.1"
32
+ #define ALTERIOM_PAINLESS_MESH_VERSION "2.0.3"
33
33
  #define ALTERIOM_PAINLESS_MESH_VERSION_MAJOR 2
34
34
  #define ALTERIOM_PAINLESS_MESH_VERSION_MINOR 0
35
- #define ALTERIOM_PAINLESS_MESH_VERSION_PATCH 1
35
+ #define ALTERIOM_PAINLESS_MESH_VERSION_PATCH 3
36
36
 
37
37
  /**
38
38
  * @brief Library description and usage information