Merge branch 'letscontrolit:mega' into andbad-72x40

This commit is contained in:
andbad
2026-05-13 13:27:12 +02:00
committed by GitHub
55 changed files with 1781 additions and 642 deletions
+105
View File
@@ -0,0 +1,105 @@
name: Bug Report
description: Create a report to help improve PubSubClient3
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: description
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is.
placeholder: Tell us what happened...
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Steps to reproduce
description: Steps to reproduce the behavior
placeholder: |
1. Connect to '...'
2. Publish message to '...'
3. See error
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: input
id: version
attributes:
label: Library version
description: What version of PubSubClient3 are you running?
placeholder: v3.3.0
validations:
required: true
- type: dropdown
id: platform
attributes:
label: Platform
description: What platform are you using?
options:
- Arduino AVR
- ESP32
- ESP8266
- Other (specify in environment)
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment
description: |
Provide details about your hardware and software environment, including:
- Board: (e.g., Arduino Uno, ESP12E, ESP32, NodeMCU, etc.)
- Framework Version: (e.g., Arduino AVR 5.2.0, ESP32 Arduino 3.3.2, ESP8266 Core 3.1.2 / 3.2.0-git)
- Development Environment: (e.g., Arduino IDE 2.3.6, PlatformIO Core 6.1.8)
- Platform: (if Other was selected above)
placeholder: |
- Board:
- Framework Version:
- Development Environment:
render: markdown
validations:
required: true
- type: textarea
id: example_code
attributes:
label: Minimal reproducible example (MVP)
description: Provide the smallest code/config and exact steps that reproduce the bug. Paste complete minimal sketch or commands.
placeholder: |
```cpp
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// minimal setup showing the bug
void setup() {
// ...
}
void loop() {
// ...
}
```
render: markdown
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output
render: shell
@@ -0,0 +1,32 @@
name: Feature Request
description: Suggest a new feature for PubSubClient3
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to suggest a new feature!
- type: textarea
id: reason
attributes:
label: Describe the reason of your feature request
description: A clear and concise description of what the problem is.
placeholder: I want to do [...]
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: context
attributes:
label: Additional context
description: Add any other context or code examples about the feature request here.
render: markdown
Vendored Regular → Executable
+1 -1
View File
@@ -29,7 +29,7 @@ ln -s $GITHUB_WORKSPACE $HOME/Arduino/libraries/CI_Test_Library
# Compile all *.ino files for the Arduino
for f in **/*.ino ; do
if [[ "$f" != *mqtt_esp8266.ino && "$f" != *mqtt_large_message.ino ]]; then
if [[ "$f" != *"mqtt_esp"* ]]; then
echo "################################################################"
echo "Arduino Uno compiling file ${f}"
arduino-cli compile -b arduino:avr:uno $f
Vendored Regular → Executable
+1 -1
View File
@@ -9,7 +9,7 @@ cd $GITHUB_WORKSPACE
#command -v clang-format >/dev/null 2>&1 || sudo apt-get -y install clang-format
# need Ubuntu clang-format version 19.1.1 (1ubuntu1~24.04.2)
# default Ubuntu clang-format version 18.1.3 (1ubuntu1) is not working
sudo apt-get -y install clang-format-19
#sudo apt-get -y install clang-format-19
# Check clang-format output
for f in **/*.{h,c,hpp,cpp,ino} ; do
#if [ -f "$f" ] && [[ "$f" != "tests/"* ]]; then
+7
View File
@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly
time: "06:00"
View File
+103
View File
@@ -0,0 +1,103 @@
name: Compile examples
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
paths:
- ".github/workflows/compile-examples.yml"
- 'examples/**'
- 'src/**'
pull_request:
paths:
- ".github/workflows/compile-examples.yml"
- 'examples/**'
- 'src/**'
jobs:
build:
name: ${{ matrix.board.fqbn }}
runs-on: ubuntu-latest
env:
SKETCHES_REPORTS_PATH: sketches-reports
strategy:
fail-fast: false
matrix:
board:
- fqbn: arduino:avr:uno
platforms: |
- name: arduino:avr
libraries: ""
artifact-name-suffix: arduino-avr-uno
- fqbn: arduino:megaavr:uno2018
platforms: |
- name: arduino:megaavr
libraries: |
- name: WiFiNINA
artifact-name-suffix: arduino-megaavr-uno2018
- fqbn: arduino:samd:mkr1000
platforms: |
- name: arduino:samd
libraries: |
- name: WiFi101
artifact-name-suffix: arduino-samd-mkr1000
- fqbn: esp8266:esp8266:generic
platforms: |
- name: esp8266:esp8266
source-url: https://arduino.esp8266.com/stable/package_esp8266com_index.json
libraries: ""
artifact-name-suffix: esp8266-esp8266-generic
- fqbn: "esp32:esp32:esp32"
platforms: |
- name: esp32:esp32
libraries: ""
artifact-name-suffix: esp32-esp32-esp32
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Download SRAM library
run: |
mkdir -p ./arduino-libraries
git -C ./arduino-libraries clone https://github.com/ennui2342/arduino-sram.git
- name: Filter examples
if: success()
run: |
if [[ "${{ matrix.board.fqbn }}" == esp32:esp32:* ]]; then
echo "Removing non-ESP32 specific examples"
rm -rf examples/mqtt_stream
fi
if [[ ! "${{ matrix.board.fqbn }}" == *:esp*:* ]]; then
echo "Removing ESP specific examples"
rm -rf examples/mqtt_esp*
fi
- name: Compile examples
uses: arduino/compile-sketches@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fqbn: ${{ matrix.board.fqbn }}
platforms: ${{ matrix.board.platforms }}
libraries: |
# Install the library from the local path
- source-path: ./
- source-path: ./arduino-libraries/arduino-sram
# Install libraries from GitHub
#- source-url: https://github.com/ennui2342/arduino-sram
- name: Ethernet
${{ matrix.board.libraries }}
sketch-paths: |
- examples
enable-deltas-report: true
sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }}
- name: Save sketches report as workflow artifact
uses: actions/upload-artifact@v7
with:
if-no-files-found: error
path: ${{ env.SKETCHES_REPORTS_PATH }}
name: sketches-report-${{ matrix.board.artifact-name-suffix }}
+6 -7
View File
@@ -7,7 +7,7 @@ name: Generate Doxygen API and deploy content to GitHub Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["master"]
branches: ["release"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
@@ -34,12 +34,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Update Doxyfile PROJECT_NUMBER
run: bash .github/doxygen-update-version.sh
- name: Doxygenize
#uses: langroodi/doxygenize@v1.7.1 # waiting for update ...
uses: langroodi/doxygenize@6e920681c5d838e9a1b5cd273b814d1e4023b63d
uses: langroodi/doxygenize@v1.7.1
#uses: hmueller01/doxygenize@update-alpine-linux+patches
with:
# Doxygen configuration file path
@@ -54,12 +53,12 @@ jobs:
# run: |
# find ./site
- name: Setup Pages
uses: actions/configure-pages@v5
uses: actions/configure-pages@v6
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
uses: actions/upload-pages-artifact@v5
with:
#path: '.' # Upload entire repository
path: './site'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v5
+28
View File
@@ -0,0 +1,28 @@
name: Lint
on:
push:
branches: [ "master" ]
paths:
- 'examples/**'
- 'src/**'
- 'tests/**'
pull_request:
branches: [ "master" ]
jobs:
run-checks:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install deps
# need Ubuntu clang-format version 19.1.1 (1ubuntu1~24.04.2)
# default Ubuntu clang-format version 18.1.3 (1ubuntu1) is not working
run: |
sudo apt-get update
sudo apt-get install -y clang-format-19
- name: Check clang-format conformity
run: bash .github/clang-lint.sh
@@ -0,0 +1,24 @@
name: Report Size Deltas
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
paths:
- ".github/workflows/report-size-deltas.yml"
schedule:
# Run at the minimum interval allowed by GitHub Actions.
# Note: GitHub Actions periodically has outages which result in workflow failures.
# In this event, the workflows will start passing again once the service recovers.
- cron: "*/5 * * * *"
workflow_dispatch:
repository_dispatch:
jobs:
report:
runs-on: ubuntu-latest
steps:
- name: Comment size deltas reports to PRs
uses: arduino/report-size-deltas@v1
with:
# Regex matching the names of the workflow artifacts created by the "Compile Examples" workflow
sketches-reports-source: ^sketches-report-.+
@@ -1,4 +1,4 @@
name: build
name: Unit tests
on:
push:
@@ -11,14 +11,11 @@ on:
branches: [ "master" ]
jobs:
build:
run-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Check clang-format conformity
run: bash .github/clang-lint.sh
uses: actions/checkout@v6
- name: Build tests
# Build / Execute tests defined in tests folder
@@ -31,5 +28,5 @@ jobs:
#run: make test
run: bin/connect_spec && bin/publish_spec && bin/receive_spec && bin/subscribe_spec
- name: Build on Arduino CLI
run: bash .github/build-arduino.sh
# - name: Build on Arduino CLI
# run: bash .github/build-arduino.sh
+5 -3
View File
@@ -1,6 +1,8 @@
tests/bin
.pioenvs
.piolibdeps
.clang_complete
.gcc-flags.json
.pio/
.pioenvs
.piolibdeps
.vscode/
site/api
tests/bin
+192
View File
@@ -0,0 +1,192 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to
[Semantic Versioning](https://semver.org/).
## Unreleased
### Changed
* Improved test coverage for all QoS levels (0, 1, 2)
* Increased robustness and correctness in client-side handling of QoS 1 and QoS 2 messages (proper handling of PUBACK, PUBREC, PUBREL, PUBCOMP sequences)
* Merged and cleaned up tests to ensure MQTT protocol compliance for all QoS scenarios
## [3.3.0] - 2025-12-14
### Added
* Speedup publish large messages by using a buffer by @TD-er in [#59](https://github.com/hmueller01/pubsubclient3/pull/59)
* Support `PROGMEM` and `__FlashStringHelper` topics by @hmueller01 in [#72](https://github.com/hmueller01/pubsubclient3/pull/72)
* Added issue template by @hmueller01 in [#76](https://github.com/hmueller01/pubsubclient3/pull/76)
* Report delta sizes in pull requests by @hmueller01 in [#77](https://github.com/hmueller01/pubsubclient3/pull/77)
### Changed
* Refactored private members by @hmueller01 in [#68](https://github.com/hmueller01/pubsubclient3/pull/68)
* Refactored private functions by @hmueller01 in [#70](https://github.com/hmueller01/pubsubclient3/pull/70)
* Do not crash if `_client` not set by @hmueller01 in [#69](https://github.com/hmueller01/pubsubclient3/pull/69)
* Minor updates that come across by @hmueller01 in [#73](https://github.com/hmueller01/pubsubclient3/pull/73)
* Inline optimisation by @hmueller01 in [#75](https://github.com/hmueller01/pubsubclient3/pull/75)
* Bump actions/upload-pages-artifact from 3 to 4 by @dependabot[bot] in [#78](https://github.com/hmueller01/pubsubclient3/pull/78)
* Bump actions/checkout from 2 to 5 by @dependabot[bot] in [#79](https://github.com/hmueller01/pubsubclient3/pull/79)
* Tag unused parameter to avoid warnings by @hmueller01 in [#82](https://github.com/hmueller01/pubsubclient3/pull/82)
* Fix compile warning at strnlen bound by @hmueller01 in [#83](https://github.com/hmueller01/pubsubclient3/pull/83)
* Fix deprecated `BUILTIN_LED` by @hmueller01 in [#84](https://github.com/hmueller01/pubsubclient3/pull/84)
* Bump actions/checkout from 5 to 6 by @dependabot[bot] in [#85](https://github.com/hmueller01/pubsubclient3/pull/85)
* Update workflows by @hmueller01 in [#86](https://github.com/hmueller01/pubsubclient3/pull/86)
## [3.2.1] - 2025-09-11
### Fixed
- Fixed bug introduced with QoS &gt; 0 support (#65)
## [3.2.0] - 2025-07-20
### Added
- Support publish at QoS 1 and 2 (by @hmueller01) (#49)
- Doxygen API documentation on gh-pages (by @hmueller01) (#51)
### Changed
- Add check for nullptr in `CHECK_STRING_LENGTH` (by @TD-er) (#48)
- Move `CHECK_STRING_LENGTH` to `PubSubClient.cpp` (by @hmueller01) (#50)
- Get rid of lazy calling parameter (by @hmueller01) (#53)
- Implemented `writeNextMsgId()` (by @hmueller01) (#54)
- Cleanup `writeString()` (by @hmueller01) (#55)
## [3.1.0] - 2025-03-20
### Added
- Added `ERROR_PSC_PRINTF` and `ERROR_PSC_PRINTF_P` outputs (#25)
### Changed
- Fix `setServer(domain, ...)` by copying domain string to an internal buffer (prevent potential dangling pointer) (#10)
- Connect to broker only if port != 0 (protect against incorrect initialization) (#10)
- Refactored buffer length types to `size_t` (#11)
- Added warnings and `-Werror` to tests Makefile (#11)
- Reformatted tests code using Google style (see `.clang-format`) (#11)
- Fix keepalive handling (thanks to @uschnindler) (#14)
- Use initializer lists for constructors (#15)
- Fix `DEBUG_PSC_PRINTF` outputs (#18)
- Introduce `MQTTRETAINED` flag (#21)
- Added documentation on `readByte()` and `readPacket()` (#23)
- Refactored `buildHeader()`, `readPacket()`, `readByte()`, `beginPublish()`/`endPublish()`, `publish()`/`publish_P()`, `connect()`, `connected()`, `subscribe()`/`unsubscribe()` and internal timing handling (#22, #23, #28, #30, #31, #33, #34, #37, #38, #39, #40, #44)
- Fixed potential memory corruption in `MQTTPUBLISH` callback preparation (#25)
- Fixed a missing failure test on `_client->read()` in `readByte()` (#32)
- Switch from constructor init-lists to class member initialization (C++ core guideline C.45) (#42)
## [3.0.2] - 2025-02-27
### Added
- GitHub workflow to execute tests
- GitHub workflow to compile examples using Arduino CLI
- Examples: Use a better source of randomness (#9)
- Optionally deactivate `std::function` usage (#7)
## [3.0.1] - 2025-02-20
### Added
- Added `.editorconfig`
- Added GitHub workflow to check code style on push/PR
### Changed
- Reformatted code using Google style
- Fixes for tests: missing def for `strlen_P` & Python libs
## [3.0] - 2025-02-17
Maintenance taken over by Holger Mueller
### Added
- In-source documentation added to `PubSubClient` header
- Add flag for enabling debugging of library
### Changed
- Always use `PubSubClient()` constructor
- Use `bool` instead of `boolean`
- Add `yield()` calls in `connect()` and `write()` to avoid watchdog resets
- Fix bug in `publish_P` handling of PROGMEM payload length
- Fix increase `bytesToWrite` to `uint16_t` to prevent overflow
- Remove compiler warning about unsigned `expectedLength`
- Extend usage of `std::function` where available
- Fix for keep alive zero
## [2.8] - 2020-05-20
### Added
- `setBufferSize()` to override `MQTT_MAX_PACKET_SIZE`
- `setKeepAlive()` to override `MQTT_KEEPALIVE`
- `setSocketTimeout()` to override `MQTT_SOCKET_TIMEOUT`
- Check to prevent subscribe/unsubscribe to empty topics
- Declare WiFi mode prior to connect in ESP example
- Use `strnlen` to avoid overruns
- Support pre-connected `Client` objects
## [2.7] - 2018-11-02
### Added
- Added large-payload API: `beginPublish`/`write`/`publish`/`endPublish`
- Added `yield` calls to improve reliability on ESP
- Added Clean Session flag to connect options
- Added ESP32 support for functional callback signature
### Fixed
- Fixed remaining-length handling to prevent buffer overrun
## [2.4] - 2015-11-21
### Added
- `MQTT_SOCKET_TIMEOUT` to avoid blocking indefinitely while waiting for inbound data
### Fixed
- Fixed return code when publishing &gt;256 bytes
## [2.3] - 2015-09-11
### Added
- `publish(topic,payload,retained)` convenience overload
## [2.2] - 2015-09-07
### Changed
- Changed code layout to match Arduino Library requirements
## [2.1] - 2015-09-07
### Added
- `MAX_TRANSFER_SIZE` to chunk messages if needed
- Reject topic/payloads that exceed `MQTT_MAX_PACKET_SIZE`
## [2.0] - 2015-08-28
### Added
- MQTT 3.1.1 support
- Fix PROGMEM handling for Intel Galileo/ESP8266
- Overloaded constructors for convenience
- Chainable setters for server/callback/client/stream
- `state()` function to return CONNACK code
## [1.0] - 2009-02-02
- Initial release notes: QoS 0 only, 128 byte max message size, keepalive 30s, no Will messages
-136
View File
@@ -1,136 +0,0 @@
3.1.0
* Fix setServer(domain, ...) by copy domain string to own buffer (prevent potential dangling string pointer) #10
* Connect to broker only if port != 0 (e.g. in case of incorrect PubSubClient initialization) #10
* Refactored different buffer length types to size_t #11
* Added a bunch of warnings and -Werror to tests Makefile #11
* Reformatted tests code using Google sytle (see .clang-format) #11
* Fix keepalive handling, thanks to @uschnindler providing this to thingsboard #14
* Use initializer lists instead of assigning global members in constructor #15
* Fix DEBUG_PSC_PRINTF outputs #18
* Added ERROR_PSC_PRINTF and ERROR_PSC_PRINTF_P outputs #25
* Introduce MQTTRETAINED flag instead of hard coding #21
* Added documentation on readByte() and readPacket() functions #23
* Refactored buildHeader() (change return type, use MQTT_MAX_HEADER_SIZE, locals) #22, #34, #37
* Refactored readPacket() (changed return type to size_t, used MQTT_MAX_HEADER_SIZE, locals) #23
* Refactored readByte() #23
* Refactored beginPublish() and endPublish() #28
* Refactored publish() #31
* Refactored publish_P() #30
* Refactored connect() #40
* Refactored connected() (mostly rewritten and simplified, added setting pingOutstanding, don't need flush()) #44
* Refactored subscribe() and unsubscribe() #44
* Refactored internal socketTimeout and keepAlive to millis to improve performance #33, #38, #39
* Fix potential memory corruption in MQTTPUBLISH callback preparation #25
* Fix potential error in readByte() (missing failure test on _client->read()) #32
* Switch from constructor init-lists to class member initialization, see C++ core guideline C.45 #42
3.0.2
* Added github workflow to execute tests
* Added github workflow to compile examples using arduino-cli
* Examples: Use a better source of random #9
* Deactivate use of std::function on demand #7
3.0.1
* Reformatted code using Google sytle (see .clang-format)
* Added .editorconfig
* Added github workflow to check code sytle on push and pull request
* Fix-tests: missing def for strlen_P & Python libs
3.0
* Maintenance taken over by Holger Mueller
* Adds in-source documentation to PubSubClient header.
* Add flag for enabling debugging of library
* Always use PubSubClient() constructor
* Use bool instead of boolean
* Add yield() calls in connect() and write() to avoid wdt resets if either blocks for too long
* Fix bug in publish_P which will always treat the payload length as 0 when used with PROGMEM
* Fix increase `bytesToWrite` to uint16_t to prevent overflow
* Remove compiler warning `expectedLength` should be unsigned
* Extend usage of std::function on all the platforms where it's available
* Fix for keep alive zero
2.8
* Add setBufferSize() to override MQTT_MAX_PACKET_SIZE
* Add setKeepAlive() to override MQTT_KEEPALIVE
* Add setSocketTimeout() to overide MQTT_SOCKET_TIMEOUT
* Added check to prevent subscribe/unsubscribe to empty topics
* Declare wifi mode prior to connect in ESP example
* Use `strnlen` to avoid overruns
* Support pre-connected Client objects
2.7
* Fix remaining-length handling to prevent buffer overrun
* Add large-payload API - beginPublish/write/publish/endPublish
* Add yield call to improve reliability on ESP
* Add Clean Session flag to connect options
* Add ESP32 support for functional callback signature
* Various other fixes
2.4
* Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely
whilst waiting for inbound data
* Fixed return code when publishing >256 bytes
2.3
* Add publish(topic,payload,retained) function
2.2
* Change code layout to match Arduino Library reqs
2.1
* Add MAX_TRANSFER_SIZE def to chunk messages if needed
* Reject topic/payloads that exceed MQTT_MAX_PACKET_SIZE
2.0
* Add (and default to) MQTT 3.1.1 support
* Fix PROGMEM handling for Intel Galileo/ESP8266
* Add overloaded constructors for convenience
* Add chainable setters for server/callback/client/stream
* Add state function to return connack return code
1.9
* Do not split MQTT packets over multiple calls to _client->write()
* API change: All constructors now require an instance of Client
to be passed in.
* Fixed example to match 1.8 api changes - dpslwk
* Added username/password support - WilHall
* Added publish_P - publishes messages from PROGMEM - jobytaffey
1.8
* KeepAlive interval is configurable in PubSubClient.h
* Maximum packet size is configurable in PubSubClient.h
* API change: Return boolean rather than int from various functions
* API change: Length parameter in message callback changed
from int to unsigned int
* Various internal tidy-ups around types
1.7
* Improved keepalive handling
* Updated to the Arduino-1.0 API
1.6
* Added the ability to publish a retained message
1.5
* Added default constructor
* Fixed compile error when used with arduino-0021 or later
1.4
* Fixed connection lost handling
1.3
* Fixed packet reading bug in PubSubClient.readPacket
1.2
* Fixed compile error when used with arduino-0016 or later
1.1
* Reduced size of library
* Added support for Will messages
* Clarified licensing - see LICENSE.txt
1.0
* Only Quality of Service (QOS) 0 messaging is supported
* The maximum message size, including header, is 128 bytes
* The keepalive interval is set to 30 seconds
* No support for Will messages
Regular → Executable
View File
+17 -3
View File
@@ -29,7 +29,7 @@ Full API documentation is available here: https://hmueller01.github.io/pubsubcli
## Limitations
- The client is based on the [MQTT Version 3.1.1 specification](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html) with some limitations.
- It can publish at QoS 0, 1 or 2.
- It can publish at QoS 0 and since [v3.2.0](https://github.com/hmueller01/pubsubclient3/releases/tag/v3.2.0) also at QoS 1 or 2.
**WARNING:** No retransmission is supported to keep the library as much memory friendly as possible.
@@ -45,7 +45,17 @@ Full API documentation is available here: https://hmueller01.github.io/pubsubcli
`PubSubClient::setKeepAlive(keepAlive)`.
- The client uses MQTT 3.1.1 by default. It can be changed to use MQTT 3.1 by
changing value of `MQTT_VERSION` in `PubSubClient.h`.
- Since [v3.3.0](https://github.com/hmueller01/pubsubclient3/releases/tag/v3.3.0) it can publish and subscribe to `PROGMEM` or `__FlashStringHelper` topics.
Details see [mqtt_progmem](https://github.com/hmueller01/pubsubclient3/blob/aae84e4d1aa65e752e19e30239b5796b4fe2705b/examples/mqtt_progmem/src/mqtt_progmem.cpp#L39-L48) example.
But if you like to publish `PROGMEM` topics you have to use
```c
const char TOPIC[] PROGMEM = "test";
const char HELLO_WORLD[] PROGMEM = "hello world";
client.beginPublish_P(TOPIC, strlen_P(HELLO_WORLD), MQTT_QOS0, false);
client.write_P(HELLO_WORLD);
client.endPublish();
```
as `client.publish_P(...)` is already used for `PROGMEM` payloads.
## Compatible Hardware
@@ -69,6 +79,10 @@ The library cannot currently be used with hardware based on the ENC28J60 chip
such as the Nanode or the Nuelectronics Ethernet Shield. For those, there is an
[alternative library](https://github.com/njh/NanodeMQTT) available.
## Changelog
See [CHANGELOG.md](CHANGELOG.md)
## License
This code is released under the MIT License.
This code is released under the [MIT License](LICENSE.txt).
+3 -1
View File
@@ -11,12 +11,14 @@
#include <PubSubClient.h>
#include <SPI.h>
#define _UNUSED_ __attribute__((unused))
// Update these with values suitable for your network.
byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED};
IPAddress ip(172, 16, 0, 100);
IPAddress server(172, 16, 0, 2);
void callback(char* topic, uint8_t* payload, size_t plength) {
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t plength) {
// handle message arrived
}
View File
@@ -23,7 +23,7 @@
#elif defined(ESP32)
#include <WiFi.h>
#include <esp_random.h>
#define BUILTIN_LED A0
#define LED_BUILTIN A0
#define RANDOM_REG32 esp_random()
#else
#error Platform not supported.
@@ -77,11 +77,11 @@ void callback(char* topic, uint8_t* payload, size_t plength) {
// Switch on the LED if an 1 was received as first character
if ((char)payload[0] == '1') {
digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level
digitalWrite(LED_BUILTIN, LOW); // Turn the LED on (Note that LOW is the voltage level
// but actually the LED is on; this is because
// it is active low on the ESP-01)
} else {
digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH
digitalWrite(LED_BUILTIN, HIGH); // Turn the LED off by making the voltage HIGH
}
}
@@ -110,7 +110,7 @@ void reconnect() {
}
void setup() {
pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
@@ -127,7 +127,7 @@ void loop() {
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
snprintf(msg, MSG_BUFFER_SIZE, "hello world #%ld", value);
snprintf(msg, MSG_BUFFER_SIZE, "hello world #%d", value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("outTopic", msg);
@@ -28,7 +28,6 @@
#elif defined(ESP32)
#include <WiFi.h>
#include <esp_random.h>
#define BUILTIN_LED A0
#define RANDOM_REG32 esp_random()
#else
#error Platform not supported.
@@ -170,7 +169,6 @@ void reconnect() {
}
void setup() {
pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
@@ -0,0 +1,3 @@
// Example sketch showing how to use PubSubClient with strings stored in PROGMEM.
// This needs to be an empty file to satisfy the arduino-cli build system.
// See src/mqtt_progmem.cpp for the actual example code.
@@ -0,0 +1,40 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
; https://docs.platformio.org/en/latest/boards/atmelavr/uno.html
[platformio]
description = Basic MQTT example with Authentication and Progmem strings
[env]
framework = arduino
lib_deps =
arduino-libraries/Ethernet @ ^2.0.2
hmueller01/PubSubClient3 @ ^3.3.0
build_flags =
; -D DEBUG_ESP_PORT=Serial
; -D DEBUG_PUBSUBCLIENT
; -D MQTT_MAX_PACKET_SIZE=512
; -D MQTT_KEEPALIVE=120
[env:uno]
platform = atmelavr
board = uno
[env:esp8266]
platform = espressif8266
platform_packages = platformio/framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git
board = esp12e
build_flags =
${env.build_flags}
-D PIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK305
[env:esp32]
platform = espressif32
board = esp32dev
@@ -0,0 +1,54 @@
/*
Basic MQTT example with Authentication
- connects to an MQTT server, providing username
and password
- publishes "hello world" to the topic "outTopic"
- subscribes to the topic "inTopic"
*/
#include <Ethernet.h>
#include <PubSubClient.h>
#include <SPI.h>
#define _UNUSED_ __attribute__((unused))
// Update these with values suitable for your network.
byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED};
IPAddress ip(172, 16, 0, 100);
IPAddress server(172, 16, 0, 2);
const char HELLO_WORLD_3[] PROGMEM = "hello world 3";
const char HELLO_WORLD_4[] PROGMEM = "hello world 4";
const char SUBSCRIBE_TOPIC[] PROGMEM = "inTopic1";
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t plength) {
// handle message arrived
}
EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);
void setup() {
Ethernet.begin(mac, ip);
// Note - the default maximum packet size is 128 bytes. If the
// combined length of clientId, username and password exceed this use the
// following to increase the buffer size:
// client.setBufferSize(255);
if (client.connect("arduinoClient", "testuser", "testpass")) {
client.publish(F("outTopic"), "hello world 1", MQTT_QOS0, false);
client.publish(F("outTopic"), F("hello world 2"), MQTT_QOS1, false);
client.publish_P(F("outTopic"), HELLO_WORLD_3, MQTT_QOS2, false);
client.beginPublish(F("outTopic"), strlen_P(HELLO_WORLD_4), MQTT_QOS1, false);
client.write_P(HELLO_WORLD_4);
client.endPublish();
client.subscribe(F("inTopic"));
client.subscribe_P(SUBSCRIBE_TOPIC, MQTT_QOS1);
}
}
void loop() {
client.loop();
}
@@ -17,6 +17,8 @@
#include <PubSubClient.h>
#include <SPI.h>
#define _UNUSED_ __attribute__((unused))
// Update these with values suitable for your network.
byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED};
IPAddress ip(172, 16, 0, 100);
@@ -29,7 +31,7 @@ EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);
// Callback function
void callback(char* topic, uint8_t* payload, size_t plength) {
void callback(_UNUSED_ char* topic, uint8_t* payload, size_t plength) {
// In order to republish this payload, a copy must be made
// as the orignal payload buffer will be overwritten whilst
// constructing the PUBLISH packet.
@@ -11,12 +11,14 @@
#include <PubSubClient.h>
#include <SPI.h>
#define _UNUSED_ __attribute__((unused))
// Update these with values suitable for your hardware/network.
byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED};
IPAddress ip(172, 16, 0, 100);
IPAddress server(172, 16, 0, 2);
void callback(char* topic, uint8_t* payload, size_t plength) {
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t plength) {
// handle message arrived
}
@@ -14,6 +14,8 @@
#include <SPI.h>
#include <SRAM.h>
#define _UNUSED_ __attribute__((unused))
// Update these with values suitable for your network.
byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED};
IPAddress ip(172, 16, 0, 100);
@@ -21,7 +23,7 @@ IPAddress server(172, 16, 0, 2);
SRAM sram(4, SRAM_1024);
void callback(char* topic, uint8_t* payload, size_t plength) {
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, size_t plength) {
sram.seek(1);
// do something with the message
Regular → Executable
+3
View File
@@ -17,9 +17,12 @@ disconnect KEYWORD2
publish KEYWORD2
publish_P KEYWORD2
beginPublish KEYWORD2
beginPublish_P KEYWORD2
endPublish KEYWORD2
write KEYWORD2
write_P KEYWORD2
subscribe KEYWORD2
subscribe_P KEYWORD2
unsubscribe KEYWORD2
loop KEYWORD2
connected KEYWORD2
+3 -1
View File
@@ -6,13 +6,15 @@
"type": "git",
"url": "https://github.com/hmueller01/pubsubclient3.git"
},
"version": "3.1.0",
"version": "3.3.0",
"license": "MIT",
"exclude": "tests",
"examples": "examples/*/*.ino",
"frameworks": "arduino",
"platforms": [
"atmelavr",
"atmelsam",
"atmelmegaavr",
"espressif8266",
"espressif32"
]
+1 -1
View File
@@ -1,5 +1,5 @@
name=PubSubClient3
version=3.1.0
version=3.3.0
author=Nick O'Leary <nick.oleary@gmail.com>
maintainer=Holger Mueller <github@euhm.de>
license=MIT
+359 -312
View File
File diff suppressed because it is too large Load Diff
+272 -45
View File
@@ -34,7 +34,7 @@
* @brief Maximum packet size defined by MQTT protocol.
*/
#ifndef MQTT_MAX_POSSIBLE_PACKET_SIZE
#define MQTT_MAX_POSSIBLE_PACKET_SIZE 268435455
#define MQTT_MAX_POSSIBLE_PACKET_SIZE ((size_t)268435455) // might be limited to 65535 if size_t is 16-bit (unsigned int)
#endif
/**
@@ -176,36 +176,39 @@
class PubSubClient : public Print {
private:
Client* _client{};
uint8_t* buffer{};
size_t bufferSize{};
unsigned long keepAliveMillis{};
unsigned long socketTimeoutMillis{};
uint16_t nextMsgId{};
unsigned long lastOutActivity{};
unsigned long lastInActivity{};
bool pingOutstanding{};
MQTT_CALLBACK_SIGNATURE{};
IPAddress ip{};
char* domain{};
uint16_t port{};
Stream* stream{};
int _state{MQTT_DISCONNECTED};
uint8_t* _buffer{};
size_t _bufferSize{};
size_t _bufferWritePos{};
uint8_t _qos{MQTT_QOS0};
unsigned long _keepAliveMillis{};
unsigned long _socketTimeoutMillis{};
uint16_t _nextMsgId{};
unsigned long _lastOutActivity{};
unsigned long _lastInActivity{};
bool _pingOutstanding{};
MQTT_CALLBACK_SIGNATURE{};
IPAddress _ip{};
char* _domain{};
uint16_t _port{};
Stream* _stream{};
int _state{MQTT_DISCONNECTED};
size_t readPacket(uint8_t* hdrLen);
bool handlePacket(uint8_t hdrLen, size_t len);
bool readByte(uint8_t* result);
bool readByte(uint8_t* result, size_t* pos);
uint8_t buildHeader(uint8_t header, uint8_t* buf, size_t length);
bool write(uint8_t header, uint8_t* buf, size_t length);
size_t writeString(const char* string, uint8_t* buf, size_t pos, size_t size);
size_t writeNextMsgId(uint8_t* buf, size_t pos, size_t size);
uint8_t buildHeader(uint8_t header, size_t length);
bool writeControlPacket(uint8_t header, size_t length);
size_t writeBuffer(size_t pos, size_t size);
size_t writeStringImpl(bool progmem, const char* string, size_t pos);
size_t writeString(const char* string, size_t pos);
size_t writeNextMsgId(size_t pos);
bool beginPublishImpl(bool progmem, const char* topic, size_t plength, uint8_t qos, bool retained);
bool subscribeImpl(bool progmem, const char* topic, uint8_t qos);
bool unsubscribeImpl(bool progmem, const char* topic);
// Add to buffer and flush if full (only to be used with beginPublish/endPublish)Add commentMore actions
// Add to buffer and flush if full (only to be used with beginPublish/endPublish)
size_t appendBuffer(uint8_t data);
size_t appendBuffer(const uint8_t *data, size_t size);
size_t flushBuffer();
public:
@@ -428,7 +431,9 @@ class PubSubClient : public Print {
* @return true If client succeeded in establishing a connection to the broker.
* false If client failed to establish a connection to the broker.
*/
bool connect(const char* id);
inline bool connect(const char* id) {
return connect(id, nullptr, nullptr, nullptr, MQTT_QOS0, false, nullptr, true);
}
/**
* @brief Connects the client using a clean session with username and password.
@@ -440,7 +445,9 @@ class PubSubClient : public Print {
* @return true If client succeeded in establishing a connection to the broker.
* false If client failed to establish a connection to the broker.
*/
bool connect(const char* id, const char* user, const char* pass);
inline bool connect(const char* id, const char* user, const char* pass) {
return connect(id, user, pass, nullptr, MQTT_QOS0, false, nullptr, true);
}
/**
* @brief Connects the client using a clean session and will.
@@ -453,7 +460,9 @@ class PubSubClient : public Print {
* @return true If client succeeded in establishing a connection to the broker.
* false If client failed to establish a connection to the broker.
*/
bool connect(const char* id, const char* willTopic, uint8_t willQos, bool willRetain, const char* willMessage);
inline bool connect(const char* id, const char* willTopic, uint8_t willQos, bool willRetain, const char* willMessage) {
return connect(id, nullptr, nullptr, willTopic, willQos, willRetain, willMessage, true);
}
/**
* @brief Connects the client using a clean session with username, password and will.
@@ -470,7 +479,10 @@ class PubSubClient : public Print {
* @return true If client succeeded in establishing a connection to the broker.
* false If client failed to establish a connection to the broker.
*/
bool connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, bool willRetain, const char* willMessage);
inline bool connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, bool willRetain,
const char* willMessage) {
return connect(id, user, pass, willTopic, willQos, willRetain, willMessage, true);
}
/**
* @brief Connects the client with all possible parameters (user, password, will and session).
@@ -503,7 +515,9 @@ class PubSubClient : public Print {
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish(const char* topic, const char* payload);
inline bool publish(const char* topic, const char* payload) {
return publish(topic, payload, MQTT_QOS0, false);
}
/**
* @brief Publishes a message to the specified topic using QoS 0.
@@ -513,7 +527,9 @@ class PubSubClient : public Print {
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish(const char* topic, const char* payload, bool retained);
inline bool publish(const char* topic, const char* payload, bool retained) {
return publish(topic, payload, MQTT_QOS0, retained);
}
/**
* @brief Publishes a message to the specified topic.
@@ -524,7 +540,35 @@ class PubSubClient : public Print {
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish(const char* topic, const char* payload, uint8_t qos, bool retained);
inline bool publish(const char* topic, const char* payload, uint8_t qos, bool retained) {
return publish(topic, reinterpret_cast<const uint8_t*>(payload), payload ? strlen(payload) : 0, qos, retained);
}
/**
* @brief Publishes a message to the specified topic.
* @param topic The topic from __FlashStringHelper to publish to.
* @param payload The message to publish.
* @param qos The quality of service (\ref group_qos) to publish at. [0, 1, 2].
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
inline bool publish(const __FlashStringHelper* topic, const char* payload, uint8_t qos, bool retained) {
return publish(topic, reinterpret_cast<const uint8_t*>(payload), payload ? strlen(payload) : 0, qos, retained);
}
/**
* @brief Publishes a message from __FlashStringHelper to the specified topic from __FlashStringHelper.
* @param topic The topic to publish to.
* @param payload The message to publish.
* @param qos The quality of service (\ref group_qos) to publish at. [0, 1, 2].
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
inline bool publish(const __FlashStringHelper* topic, const __FlashStringHelper* payload, uint8_t qos, bool retained) {
return publish_P(topic, reinterpret_cast<const uint8_t*>(payload), payload ? strlen_P(reinterpret_cast<const char*>(payload)) : 0, qos, retained);
}
/**
* @brief Publishes a non retained message to the specified topic using QoS 0.
@@ -534,7 +578,9 @@ class PubSubClient : public Print {
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish(const char* topic, const uint8_t* payload, size_t plength);
inline bool publish(const char* topic, const uint8_t* payload, size_t plength) {
return publish(topic, payload, plength, MQTT_QOS0, false);
}
/**
* @brief Publishes a message to the specified topic using QoS 0.
@@ -545,7 +591,9 @@ class PubSubClient : public Print {
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish(const char* topic, const uint8_t* payload, size_t plength, bool retained);
inline bool publish(const char* topic, const uint8_t* payload, size_t plength, bool retained) {
return publish(topic, payload, plength, MQTT_QOS0, retained);
}
/**
* @brief Publishes a message to the specified topic.
@@ -559,6 +607,18 @@ class PubSubClient : public Print {
*/
bool publish(const char* topic, const uint8_t* payload, size_t plength, uint8_t qos, bool retained);
/**
* @brief Publishes a message to the specified topic.
* @param topic The topic from __FlashStringHelper to publish to.
* @param payload The message to publish.
* @param plength The length of the payload.
* @param qos The quality of service (\ref group_qos) to publish at. [0, 1, 2].
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish(const __FlashStringHelper* topic, const uint8_t* payload, size_t plength, uint8_t qos, bool retained);
/**
* @brief Publishes a message stored in PROGMEM to the specified topic using QoS 0.
* @param topic The topic to publish to.
@@ -567,7 +627,9 @@ class PubSubClient : public Print {
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish_P(const char* topic, const char* payload, bool retained);
inline bool publish_P(const char* topic, PGM_P payload, bool retained) {
return publish_P(topic, payload, MQTT_QOS0, retained);
}
/**
* @brief Publishes a message stored in PROGMEM to the specified topic.
@@ -578,7 +640,22 @@ class PubSubClient : public Print {
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish_P(const char* topic, const char* payload, uint8_t qos, bool retained);
inline bool publish_P(const char* topic, PGM_P payload, uint8_t qos, bool retained) {
return publish_P(topic, reinterpret_cast<const uint8_t*>(payload), payload ? strlen_P(payload) : 0, qos, retained);
}
/**
* @brief Publishes a message stored in PROGMEM to the specified topic.
* @param topic The topic from __FlashStringHelper to publish to.
* @param payload The message to publish.
* @param qos The quality of service (\ref group_qos) to publish at. [0, 1, 2].
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish_P(const __FlashStringHelper* topic, PGM_P payload, uint8_t qos, bool retained) {
return publish_P(topic, reinterpret_cast<const uint8_t*>(payload), payload ? strlen_P(payload) : 0, qos, retained);
}
/**
* @brief Publishes a message stored in PROGMEM to the specified topic using QoS 0.
@@ -589,7 +666,9 @@ class PubSubClient : public Print {
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish_P(const char* topic, const uint8_t* payload, size_t plength, bool retained);
inline bool publish_P(const char* topic, const uint8_t* payload, size_t plength, bool retained) {
return publish_P(topic, payload, plength, MQTT_QOS0, retained);
}
/**
* @brief Publishes a message stored in PROGMEM to the specified topic.
@@ -603,6 +682,18 @@ class PubSubClient : public Print {
*/
bool publish_P(const char* topic, const uint8_t* payload, size_t plength, uint8_t qos, bool retained);
/**
* @brief Publishes a message stored in PROGMEM to the specified topic.
* @param topic The topic from __FlashStringHelper to publish to.
* @param payload The message from PROGMEM to publish.
* @param plength The length of the payload.
* @param qos The quality of service (\ref group_qos) to publish at. [0, 1, 2].
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish_P(const __FlashStringHelper* topic, const uint8_t* payload, size_t plength, uint8_t qos, bool retained);
/**
* @brief Start to publish a message using QoS 0.
* This API:
@@ -617,7 +708,9 @@ class PubSubClient : public Print {
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool beginPublish(const char* topic, size_t plength, bool retained);
inline bool beginPublish(const char* topic, size_t plength, bool retained) {
return beginPublishImpl(false, topic, plength, MQTT_QOS0, retained);
}
/**
* @brief Start to publish a message.
@@ -634,7 +727,48 @@ class PubSubClient : public Print {
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool beginPublish(const char* topic, size_t plength, uint8_t qos, bool retained);
inline bool beginPublish(const char* topic, size_t plength, uint8_t qos, bool retained) {
return beginPublishImpl(false, topic, plength, qos, retained);
}
/**
* @brief Start to publish a message using a topic from __FlashStringHelper F().
* This API:
* beginPublish(...)
* one or more calls to write(...)
* endPublish()
* Allows for arbitrarily large payloads to be sent without them having to be copied into
* a new buffer and held in memory at one time.
* @param topic The topic from __FlashStringHelper to publish to.
* @param plength The length of the payload.
* @param qos The quality of service (\ref group_qos) to publish at. [0, 1, 2].
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
inline bool beginPublish(const __FlashStringHelper* topic, size_t plength, uint8_t qos, bool retained) {
// convert FlashStringHelper in PROGMEM-pointer
return beginPublishImpl(true, reinterpret_cast<const char*>(topic), plength, qos, retained);
}
/**
* @brief Start to publish a message using a topic in PROGMEM.
* This API:
* beginPublish_P(...)
* one or more calls to write(...)
* endPublish()
* Allows for arbitrarily large payloads to be sent without them having to be copied into
* a new buffer and held in memory at one time.
* @param topic The topic in PROGMEM to publish to.
* @param plength The length of the payload.
* @param qos The quality of service (\ref group_qos) to publish at. [0, 1, 2].
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
inline bool beginPublish_P(PGM_P topic, size_t plength, uint8_t qos, bool retained) {
return beginPublishImpl(true, reinterpret_cast<const char*>(topic), plength, qos, retained);
}
/**
* @brief Finish sending a message that was started with a call to beginPublish.
@@ -645,21 +779,43 @@ class PubSubClient : public Print {
/**
* @brief Writes a single byte as a component of a publish started with a call to beginPublish.
* For performance reasons, this will be appended to the internal buffer,
* For performance reasons, this will be appended to the internal buffer,
* which will be flushed when full or on a call to endPublish().
* @param data A byte to write to the publish payload.
* @return The number of bytes written.
* @return The number of bytes written (0 or 1). If 0 is returned a write error occurred.
*/
virtual size_t write(uint8_t data);
/**
* @brief Writes an array of bytes as a component of a publish started with a call to beginPublish.
* For performance reasons, this will be appended to the internal buffer,
* which will be flushed when full or on a call to endPublish(). * @param buffer The bytes to write.
* For performance reasons, this will be appended to the internal buffer,
* which will be flushed when full or on a call to endPublish().
* @param buf The bytes to write.
* @param size The length of the payload to be sent.
* @return The number of bytes written.
* @return The number of bytes written. If return value is != size a write error occurred.
*/
virtual size_t write(const uint8_t* buffer, size_t size);
virtual size_t write(const uint8_t* buf, size_t size);
/**
* @brief Writes a string in PROGMEM as a component of a publish started with a call to beginPublish.
* For performance reasons, this will be appended to the internal buffer,
* which will be flushed when full or on a call to endPublish().
* @param string The message to write.
* @return The number of bytes written. If return value is != string length a write error occurred.
*/
inline size_t write_P(PGM_P string) {
return write_P(reinterpret_cast<const uint8_t*>(string), strlen_P(string));
}
/**
* @brief Writes an array of progmem bytes as a component of a publish started with a call to beginPublish.
* For performance reasons, this will be appended to the internal buffer,
* which will be flushed when full or on a call to endPublish().
* @param buf The bytes to write.
* @param size The length of the payload to be sent.
* @return The number of bytes written. If return value is != size a write error occurred.
*/
size_t write_P(const uint8_t* buf, size_t size);
/**
* @brief Subscribes to messages published to the specified topic using QoS 0.
@@ -667,7 +823,30 @@ class PubSubClient : public Print {
* @return true If sending the subscribe succeeded.
* false If sending the subscribe failed, either connection lost or message too large.
*/
bool subscribe(const char* topic);
inline bool subscribe(const char* topic) {
return subscribeImpl(false, topic, MQTT_QOS0);
}
/**
* @brief Subscribes to messages published to the specified topic from __FlashStringHelper using QoS 0.
* @param topic The topic from __FlashStringHelper to subscribe to.
* @return true If sending the subscribe succeeded.
* false If sending the subscribe failed, either connection lost or message too large.
*/
inline bool subscribe(const __FlashStringHelper* topic) {
// convert FlashStringHelper in PROGMEM-pointer
return subscribeImpl(true, reinterpret_cast<const char*>(topic), MQTT_QOS0);
}
/**
* @brief Subscribes to messages published to the specified topic in PROGMEM using QoS 0.
* @param topic The topic in PROGMEM to subscribe to.
* @return true If sending the subscribe succeeded.
* false If sending the subscribe failed, either connection lost or message too large.
*/
inline bool subscribe_P(PGM_P topic) {
return subscribeImpl(true, reinterpret_cast<const char*>(topic), MQTT_QOS0);
}
/**
* @brief Subscribes to messages published to the specified topic.
@@ -676,7 +855,32 @@ class PubSubClient : public Print {
* @return true If sending the subscribe succeeded.
* false If sending the subscribe failed, either connection lost or message too large.
*/
bool subscribe(const char* topic, uint8_t qos);
inline bool subscribe(const char* topic, uint8_t qos) {
return subscribeImpl(false, topic, qos);
}
/**
* @brief Subscribes to messages published to the specified topic from __FlashStringHelper.
* @param topic The topic from __FlashStringHelper to subscribe to.
* @param qos The qos to subscribe at. [0, 1].
* @return true If sending the subscribe succeeded.
* false If sending the subscribe failed, either connection lost or message too large.
*/
inline bool subscribe(const __FlashStringHelper* topic, uint8_t qos) {
// convert FlashStringHelper in PROGMEM-pointer
return subscribeImpl(true, reinterpret_cast<const char*>(topic), qos);
}
/**
* @brief Subscribes to messages published to the specified topic in PROGMEM.
* @param topic The topic in PROGMEM to subscribe to.
* @param qos The qos to subscribe at. [0, 1].
* @return true If sending the subscribe succeeded.
* false If sending the subscribe failed, either connection lost or message too large.
*/
inline bool subscribe_P(PGM_P topic, uint8_t qos) {
return subscribeImpl(true, reinterpret_cast<const char*>(topic), qos);
}
/**
* @brief Unsubscribes from the specified topic.
@@ -684,7 +888,30 @@ class PubSubClient : public Print {
* @return true If sending the unsubscribe succeeded.
* false If sending the unsubscribe failed, either connection lost or message too large.
*/
bool unsubscribe(const char* topic);
inline bool unsubscribe(const char* topic) {
return unsubscribeImpl(false, topic);
}
/**
* @brief Unsubscribes from the specified topic from __FlashStringHelper.
* @param topic The topic from __FlashStringHelper to unsubscribe from.
* @return true If sending the unsubscribe succeeded.
* false If sending the unsubscribe failed, either connection lost or message too large.
*/
inline bool unsubscribe(const __FlashStringHelper* topic) {
// convert FlashStringHelper in PROGMEM-pointer
return unsubscribeImpl(true, reinterpret_cast<const char*>(topic));
}
/**
* @brief Unsubscribes from the specified topic in PROGMEM.
* @param topic The topic in PROGMEM to unsubscribe from.
* @return true If sending the unsubscribe succeeded.
* false If sending the unsubscribe failed, either connection lost or message too large.
*/
inline bool unsubscribe_P(PGM_P topic) {
return unsubscribeImpl(true, reinterpret_cast<const char*>(topic));
}
/**
* @brief This should be called regularly to allow the client to process incoming messages and maintain its connection to the server.
@@ -20,9 +20,14 @@ extern void loop(void);
unsigned long millis(void);
}
class __FlashStringHelper;
#define PROGMEM
#define PGM_P const char*
#define memcpy_P memcpy
#define strlen_P strlen
#define strnlen_P strnlen
#define pgm_read_byte_near(x) *(x)
#define F(x) (reinterpret_cast<const __FlashStringHelper*>(x))
#define yield(x) {}
+167 -8
View File
@@ -13,6 +13,7 @@ int test_publish_bytes();
int test_publish_retained();
int test_publish_retained_2();
int test_publish_not_connected();
int test_publish_long();
int test_publish_too_long();
int test_publish_P();
int test_publish_P_too_long();
@@ -22,6 +23,10 @@ int test_publish_qos1();
int test_publish_qos2();
int test_publish_P_qos1();
int test_publish_P_qos2();
int test_publish_FlashStringHelper();
int test_publish_FlashStringHelper2();
int test_publish_P_FlashStringHelper();
int test_publish_P_P();
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t plength) {
// handle message arrived
@@ -139,6 +144,49 @@ int test_publish_not_connected() {
END_IT
}
int test_publish_long() {
IT("publishes with long payload message (> buffer size)");
ShimClient shimClient;
shimClient.setAllowConnect(true);
// buffer size 64 bytes - 5 bytes header - 2 bytes topic length = max. 57 bytes topic
// 0 1 2 3 4 5 6 7 8 9 0 1 2
char topic[] = "123456789012345678901234567890123456789012345678901234567";
// 0 1 2 3 4 5 6 7 8 9 0 1 2
char payload[] = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
size_t plength = strlen(payload);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
PubSubClient client(server, 1883, callback, shimClient);
client.setBufferSize(64);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[256];
publish[0] = 0x30; // PUBLISH, QoS 0, no retain
publish[1] = 0xb3; // Remaining length byte 1: 2 + 57 + 120 bytes (topic length bytes + topic length + payload length = 179)
publish[2] = 0x01; // Remaining length byte 2
publish[3] = 0x00; // Topic length MSB
publish[4] = 0x39; // Topic length LSB (57 bytes)
memcpy(&publish[5], topic, sizeof(topic) - 1);
memcpy(&publish[5 + sizeof(topic) - 1], payload, sizeof(payload) - 1);
shimClient.expect(publish, 5 + sizeof(topic) - 1 + sizeof(payload) - 1);
rc = client.beginPublish(topic, plength, 0, false);
IS_TRUE(rc);
plength = client.write((uint8_t*)payload, plength);
IS_EQUAL(plength, strlen(payload));
rc = client.endPublish();
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_publish_too_long() {
IT("publish fails when topic/payload are too long");
ShimClient shimClient;
@@ -167,7 +215,7 @@ int test_publish_too_long() {
}
int test_publish_P() {
IT("publishes using PROGMEM");
IT("publishes using PROGMEM payload");
ShimClient shimClient;
shimClient.setAllowConnect(true);
@@ -193,7 +241,7 @@ int test_publish_P() {
}
int test_publish_P_too_long() {
IT("publish using PROGMEM fails when topic is too long");
IT("publish using PROGMEM payload fails when topic is too long");
ShimClient shimClient;
shimClient.setAllowConnect(true);
@@ -219,6 +267,112 @@ int test_publish_P_too_long() {
END_IT
}
int test_publish_FlashStringHelper() {
IT("publishes using FlashStringHelper topic");
ShimClient shimClient;
shimClient.setAllowConnect(true);
char payload[] = "12345";
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x31, 0x0c, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', '1', '2', '3', '4', '5'};
shimClient.expect(publish, sizeof(publish));
rc = client.publish(F("topic"), payload, MQTT_QOS0, true);
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_publish_FlashStringHelper2() {
IT("publishes using FlashStringHelper topic and payload");
ShimClient shimClient;
shimClient.setAllowConnect(true);
char payload[] = "12345";
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x31, 0x0c, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', '1', '2', '3', '4', '5'};
shimClient.expect(publish, sizeof(publish));
rc = client.publish(F("topic"), F(payload), MQTT_QOS0, true);
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_publish_P_FlashStringHelper() {
IT("publishes using FlashStringHelper topic and PROGMEM payload");
ShimClient shimClient;
shimClient.setAllowConnect(true);
char payload[] PROGMEM = "12345";
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x31, 0x0c, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', '1', '2', '3', '4', '5'};
shimClient.expect(publish, sizeof(publish));
rc = client.publish_P(F("topic"), payload, MQTT_QOS0, true);
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_publish_P_P() {
IT("publishes using PROGMEM topic and PROGMEM payload");
ShimClient shimClient;
shimClient.setAllowConnect(true);
char topic[] PROGMEM = "topic";
char payload[] PROGMEM = "12345";
size_t length = strlen_P(payload);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x31, 0x0c, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', '1', '2', '3', '4', '5'};
shimClient.expect(publish, sizeof(publish));
rc = client.beginPublish_P(topic, length, MQTT_QOS0, true);
IS_TRUE(rc);
length = client.write_P(payload);
IS_EQUAL(length, strlen_P(payload));
rc = client.endPublish();
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_publish_empty_topic() {
IT("publish fails when topic is empty");
ShimClient shimClient;
@@ -275,7 +429,7 @@ int test_publish_qos1() {
IS_TRUE(rc);
// Example publish packet for QoS 1 (0x32)
byte publish[] = {0x32, 0x10, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00, 0x02};
byte publish[] = {0x32, 0x10, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 0x00, 0x02, 'p', 'a', 'y', 'l', 'o', 'a', 'd'};
shimClient.expect(publish, sizeof(publish));
rc = client.publish("topic", "payload", MQTT_QOS1, false);
@@ -299,7 +453,7 @@ int test_publish_qos2() {
IS_TRUE(rc);
// Example publish packet for QoS 2 (0x34)
byte publish[] = {0x34, 0x10, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00, 0x02};
byte publish[] = {0x34, 0x10, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 0x00, 0x02, 'p', 'a', 'y', 'l', 'o', 'a', 'd'};
shimClient.expect(publish, sizeof(publish));
rc = client.publish("topic", "payload", MQTT_QOS2, false);
@@ -311,7 +465,7 @@ int test_publish_qos2() {
}
int test_publish_P_qos1() {
IT("publishes using PROGMEM with QoS 1 retained");
IT("publishes using PROGMEM payload with QoS 1 retained");
ShimClient shimClient;
shimClient.setAllowConnect(true);
@@ -325,7 +479,7 @@ int test_publish_P_qos1() {
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x33, 0x0e, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x02};
byte publish[] = {0x33, 0x0e, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 0x00, 0x02, 0x01, 0x02, 0x03, 0x04, 0x05};
shimClient.expect(publish, sizeof(publish));
rc = client.publish_P("topic", payload, length, MQTT_QOS1, true);
@@ -337,7 +491,7 @@ int test_publish_P_qos1() {
}
int test_publish_P_qos2() {
IT("publishes using PROGMEM with QoS 2 retained");
IT("publishes using PROGMEM payload with QoS 2 retained");
ShimClient shimClient;
shimClient.setAllowConnect(true);
@@ -351,7 +505,7 @@ int test_publish_P_qos2() {
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x35, 0x0e, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x02};
byte publish[] = {0x35, 0x0e, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 0x00, 0x02, 0x01, 0x02, 0x03, 0x04, 0x05};
shimClient.expect(publish, sizeof(publish));
rc = client.publish_P("topic", payload, length, MQTT_QOS2, true);
@@ -371,6 +525,7 @@ int main() {
test_publish_qos1();
test_publish_qos2();
test_publish_null_payload();
test_publish_long();
test_publish_not_connected();
test_publish_empty_topic();
test_publish_too_long();
@@ -378,6 +533,10 @@ int main() {
test_publish_P_qos1();
test_publish_P_qos2();
test_publish_P_too_long();
test_publish_FlashStringHelper();
test_publish_FlashStringHelper2();
test_publish_P_FlashStringHelper();
test_publish_P_P();
FINISH
}
@@ -28,6 +28,7 @@ int test_receive_oversized_message();
int test_resize_buffer();
int test_receive_oversized_stream_message();
int test_receive_qos1();
int test_receive_qos2();
void reset_callback() {
callback_called = false;
@@ -330,6 +331,57 @@ int test_receive_qos1() {
END_IT
}
int test_receive_qos2() {
IT("receives a qos2 message - responds PUBREC then PUBCOMP");
reset_callback();
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
// QoS 2 PUBLISH from broker (0x34 = MQTTPUBLISH | QoS2 bits)
// Fixed header 0x34, remaining length 0x10 (16), topic len 0x0005, topic "topic",
// msgId 0x1234, payload "payload"
byte publish[] = {0x34, 0x10, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x34, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64};
shimClient.respond(publish, 18);
// Client must respond with PUBREC (0x50), remaining length 2, msgId 0x1234
byte pubrec[] = {0x50, 0x02, 0x12, 0x34};
shimClient.expect(pubrec, 4);
rc = client.loop();
IS_TRUE(rc);
IS_TRUE(callback_called);
IS_TRUE(strcmp(lastTopic, "topic") == 0);
IS_TRUE(memcmp(lastPayload, "payload", 7) == 0);
IS_TRUE(lastLength == 7);
IS_FALSE(shimClient.error());
reset_callback();
// Broker sends PUBREL (0x62 = MQTTPUBREL | bit1), remaining length 2, msgId 0x1234
byte pubrel[] = {0x62, 0x02, 0x12, 0x34};
shimClient.respond(pubrel, 4);
// Client must respond with PUBCOMP (0x70), remaining length 2, msgId 0x1234
byte pubcomp[] = {0x70, 0x02, 0x12, 0x34};
shimClient.expect(pubcomp, 4);
rc = client.loop();
IS_TRUE(rc);
IS_FALSE(callback_called); // callback must NOT fire again on PUBREL
IS_FALSE(shimClient.error());
END_IT
}
int main() {
SUITE("Receive");
test_receive_callback();
@@ -340,6 +392,7 @@ int main() {
test_resize_buffer();
test_receive_oversized_stream_message();
test_receive_qos1();
test_receive_qos2();
FINISH
}
@@ -10,6 +10,10 @@ byte server[] = {172, 16, 0, 2};
void callback(char* topic, uint8_t* payload, size_t plength);
int test_subscribe_no_qos();
int test_subscribe_qos_1();
int test_subscribe_P();
int test_subscribe_P_qos_1();
int test_subscribe_FlashStringHelper();
int test_subscribe_FlashStringHelper_qos_1();
int test_subscribe_not_connected();
int test_subscribe_invalid_qos();
int test_subscribe_too_long();
@@ -70,6 +74,108 @@ int test_subscribe_qos_1() {
END_IT
}
int test_subscribe_P() {
IT("subscribe using PROGMEM");
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte subscribe[] = {0x82, 0xa, 0x0, 0x2, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x0};
shimClient.expect(subscribe, 12);
byte suback[] = {0x90, 0x3, 0x0, 0x2, 0x0};
shimClient.respond(suback, 5);
char topic[] PROGMEM = "topic";
rc = client.subscribe_P(topic);
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_subscribe_P_qos_1() {
IT("subscribe using PROGMEM with QoS 1");
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte subscribe[] = {0x82, 0xa, 0x0, 0x2, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x1};
shimClient.expect(subscribe, 12);
byte suback[] = {0x90, 0x3, 0x0, 0x2, 0x1};
shimClient.respond(suback, 5);
char topic[] PROGMEM = "topic";
rc = client.subscribe_P(topic, MQTT_QOS1);
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_subscribe_FlashStringHelper() {
IT("subscribe using FlashStringHelper");
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte subscribe[] = {0x82, 0xa, 0x0, 0x2, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x0};
shimClient.expect(subscribe, 12);
byte suback[] = {0x90, 0x3, 0x0, 0x2, 0x0};
shimClient.respond(suback, 5);
rc = client.subscribe(F("topic"));
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_subscribe_FlashStringHelper_qos_1() {
IT("subscribe using FlashStringHelper with QoS 1");
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte subscribe[] = {0x82, 0xa, 0x0, 0x2, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x1};
shimClient.expect(subscribe, 12);
byte suback[] = {0x90, 0x3, 0x0, 0x2, 0x1};
shimClient.respond(suback, 5);
rc = client.subscribe(F("topic"), MQTT_QOS1);
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_subscribe_not_connected() {
IT("subscribe fails when not connected");
ShimClient shimClient;
@@ -176,6 +282,10 @@ int main() {
SUITE("Subscribe");
test_subscribe_no_qos();
test_subscribe_qos_1();
test_subscribe_P();
test_subscribe_P_qos_1();
test_subscribe_FlashStringHelper();
test_subscribe_FlashStringHelper_qos_1();
test_subscribe_not_connected();
test_subscribe_invalid_qos();
test_subscribe_too_long();
+2 -2
View File
@@ -190,8 +190,8 @@ extra_scripts = ${esp82xx_common.extra_scripts}
;platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55_gcc152
;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2904-2115-5.5/framework-arduinoespressif32-release_v5.5-f2a3fa2b.tar.xz
platform = https://github.com/tasmota/platform-espressif32/releases/download/2026.04.50/platform-espressif32.zip
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/0405-1702-5.5/framework-arduinoespressif32-release_v5.5-f2a3fa2b.tar.xz
platform = https://github.com/Jason2866/platform-espressif32.git#Arduino/IDF55_gcc152
platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1205-1404-5.5/framework-arduinoespressif32-release_v5.5-65012b38.tar.xz
custom_remove_include = true
@@ -1,13 +1,14 @@
#include "../DataStructs/NWPluginData_base.h"
#include "../../../src/DataStructs/ESPEasy_EventStruct.h"
#include "../../../src/Globals/Settings.h"
#include "../../../src/Helpers/StringConverter.h"
#include "../../../src/Helpers/Misc.h"
#include "../../../src/Helpers/Networking.h"
#if FEATURE_STORE_NETWORK_INTERFACE_SETTINGS
# include "../../../src/Helpers/_ESPEasy_key_value_store.h"
#include "../_NWPlugin_Helper.h"
#endif
# include "../_NWPlugin_Helper.h"
#endif // if FEATURE_STORE_NETWORK_INTERFACE_SETTINGS
#ifdef ESP32
# include <esp_netif.h>
# include <esp_netif_types.h>
@@ -46,8 +47,11 @@ NWPluginData_base::NWPluginData_base(
NWPluginData_base::~NWPluginData_base()
{
#if FEATURE_NETWORK_STATS
delete _plugin_stats_array;
_plugin_stats_array = nullptr;
if (_plugin_stats_array) {
delete _plugin_stats_array;
_plugin_stats_array = nullptr;
}
#endif // if FEATURE_NETWORK_STATS
#if FEATURE_STORE_NETWORK_INTERFACE_SETTINGS
@@ -58,6 +62,7 @@ NWPluginData_base::~NWPluginData_base()
}
#ifdef ESP32
bool NWPluginData_base::isDefaultRoute() const {
if (_netif) {
return _netif->isDefault();
@@ -65,14 +70,14 @@ bool NWPluginData_base::isDefaultRoute() const {
return false;
}
#endif
#endif // ifdef ESP32
bool NWPluginData_base::getStaticIPAddresses(IPAddress & ip, IPAddress & gateway, IPAddress & subnetmask, IPAddress & dns ) const
bool NWPluginData_base::getStaticIPAddresses(IPAddress& ip, IPAddress& gateway, IPAddress& subnetmask, IPAddress& dns) const
{
getStaticIPAddress(IPAddressType::IP, ip);
getStaticIPAddress(IPAddressType::Gateway, gateway);
getStaticIPAddress(IPAddressType::IP, ip);
getStaticIPAddress(IPAddressType::Gateway, gateway);
getStaticIPAddress(IPAddressType::Subnetmask, subnetmask);
getStaticIPAddress(IPAddressType::DNS, dns);
getStaticIPAddress(IPAddressType::DNS, dns);
return IPAddressSet(ip) && IPAddressSet(gateway) && IPAddressSet(subnetmask);
}
@@ -116,31 +121,35 @@ void NWPluginData_base::initPluginStats(
float errorValue,
const PluginStats_Config_t& displayConfig)
{
if (networkStatsVarIndex < INVALID_NETWORK_STATS_VAR_INDEX) {
if (_plugin_stats_array == nullptr) {
constexpr unsigned size = sizeof(PluginStats_array);
void *ptr = special_calloc(1, size);
if (!Settings.getNetworkCollectStats(_networkIndex) ||
(networkStatsVarIndex >= INVALID_NETWORK_STATS_VAR_INDEX)) {
return;
}
if (ptr != nullptr) {
_plugin_stats_array = new (ptr) PluginStats_array();
}
}
if (_plugin_stats_array == nullptr) {
constexpr unsigned size = sizeof(PluginStats_array);
void *ptr = special_calloc(1, size);
if (_plugin_stats_array != nullptr) {
_plugin_stats_array->initPluginStats(
networkStatsVarIndex,
label,
nrDecimals,
errorValue,
displayConfig);
if (ptr != nullptr) {
_plugin_stats_array = new (ptr) PluginStats_array();
}
}
if (_plugin_stats_array != nullptr) {
_plugin_stats_array->initPluginStats(
networkStatsVarIndex,
label,
nrDecimals,
errorValue,
displayConfig);
}
}
# if FEATURE_NETWORK_TRAFFIC_COUNT
void NWPluginData_base::initPluginStats_trafficCount(networkStatsVarIndex_t networkStatsVarIndex, bool isTX)
{
if (!Settings.getNetworkCollectStats(_networkIndex)) { return; }
PluginStats_Config_t displayConfig;
displayConfig.setAxisPosition(PluginStats_Config_t::AxisPosition::Right);
@@ -160,13 +169,14 @@ bool NWPluginData_base::initPluginStats()
{
# if FEATURE_NETWORK_TRAFFIC_COUNT
// Virtual function has no override in derived class, so only init traffic count
initPluginStats_trafficCount(0, true); // TX
initPluginStats_trafficCount(1, false); // RX
return true;
# else // if FEATURE_NETWORK_TRAFFIC_COUNT
return false;
if (Settings.getNetworkCollectStats(_networkIndex)) {
// Virtual function has no override in derived class, so only init traffic count
initPluginStats_trafficCount(0, true); // TX
initPluginStats_trafficCount(1, false); // RX
return true;
}
# endif // if FEATURE_NETWORK_TRAFFIC_COUNT
return false;
}
void NWPluginData_base::clearPluginStats(networkStatsVarIndex_t networkStatsVarIndex)
@@ -334,9 +344,9 @@ bool NWPluginData_base::handle_priority_route_changed()
if ((_netif != nullptr) && _netif->isDefault()) {
auto cache = getNWPluginData_static_runtime();
if (!cache) {
if (NWPlugin::forceDHCP_request(_netif)) {
return true;
if (!cache) {
if (NWPlugin::forceDHCP_request(_netif)) {
return true;
}
}
@@ -404,12 +414,13 @@ PluginStats * NWPluginData_base::getPluginStats(networkStatsVarIndex_t networkSt
#endif // if FEATURE_NETWORK_STATS
#ifdef ESP32
/*
bool NWPluginData_base::_restore_DNS_cache()
{
bool res{};
if ((_netif != nullptr) && _netif->isDefault()) {
/*
bool NWPluginData_base::_restore_DNS_cache()
{
bool res{};
if ((_netif != nullptr) && _netif->isDefault()) {
if (NWPlugin::forceDHCP_request(_netif)) { return true; }
auto cache = getNWPluginData_static_runtime();
@@ -433,24 +444,18 @@ bool NWPluginData_base::_restore_DNS_cache()
res = true;
}
}
}
return res;
}
*/
}
return res;
}
*/
#endif // ifdef ESP32
#if FEATURE_STORE_NETWORK_INTERFACE_SETTINGS
bool NWPluginData_base::_load()
{
return load_nwpluginTaskData_KVS(_kvs, _networkIndex, _nw_data_pluginID);
}
bool NWPluginData_base::_load() { return load_nwpluginTaskData_KVS(_kvs, _networkIndex, _nw_data_pluginID); }
bool NWPluginData_base::_store()
{
return store_nwpluginTaskData_KVS(_kvs, _networkIndex, _nw_data_pluginID);
}
bool NWPluginData_base::_store() { return store_nwpluginTaskData_KVS(_kvs, _networkIndex, _nw_data_pluginID); }
#endif // if FEATURE_STORE_NETWORK_INTERFACE_SETTINGS
@@ -6,6 +6,7 @@
#include "../../../src/Globals/Settings.h"
#include "../../../src/Globals/ESPEasy_Scheduler.h"
//#include "../../../src/Helpers/Misc.h"
#include "../../../src/Helpers/Networking.h"
#include "../../../src/Helpers/StringConverter.h"
#include "../Globals/NWPlugins.h"
@@ -2137,6 +2138,9 @@ bool do_NWPluginCall(networkDriverIndex_t networkDriverIndex, NWPlugin::
// addLog(LOG_LEVEL_ERROR, strformat(F("Network %d was not (yet) initialized"), event->NetworkIndex + 1));
return false;
}
#if FEATURE_ESPEASY_P2P
stopUDPport();
#endif
}
@@ -99,13 +99,14 @@ bool NW001_data_struct_WiFi_STA::init(EventStruct *event)
{
auto runtime_data = getNWPluginData_static_runtime();
if (runtime_data) {
IPAddress ip, gateway, sn, dns;
getStaticIPAddresses(ip, gateway, sn, dns);
runtime_data->setStaticIP(ip, gateway, sn, dns);
}
}
ESPEasy::net::wifi::initWiFi();
return true;
@@ -171,6 +172,7 @@ bool NW001_data_struct_WiFi_STA::handle_priority_route_changed()
bool NW001_data_struct_WiFi_STA::initPluginStats()
{
if (!Settings.getNetworkCollectStats(_networkIndex)) { return false; }
networkStatsVarIndex_t networkStatsVarIndex{};
PluginStats_Config_t displayConfig;
@@ -93,6 +93,7 @@ bool NW002_data_struct_WiFi_AP::init(EventStruct *event)
{
{
auto runtime_data = getNWPluginData_static_runtime();
if (runtime_data) {
IPAddress ip, gateway, sn, dns;
getStaticIPAddresses(ip, gateway, sn, dns);
@@ -146,26 +147,27 @@ NWPluginData_static_runtime * NW002_data_struct_WiFi_AP::getNWPluginData_static_
bool NW002_data_struct_WiFi_AP::getStaticIPAddress(IPAddressType addressType, IPAddress& ip) const
{
// TODO TD-er: Implement for AP
/*
IPAddress res;
switch (addressType)
{
case IPAddressType::IP: res = IPAddress(Settings.IP);
break;
case IPAddressType::Gateway: res = IPAddress(Settings.Gateway);
break;
case IPAddressType::Subnetmask: res = IPAddress(Settings.Subnet);
break;
case IPAddressType::DNS: res = IPAddress(Settings.DNS);
break;
}
/*
IPAddress res;
if (IPAddressSet(res)) {
ip = res;
return true;
}
*/
switch (addressType)
{
case IPAddressType::IP: res = IPAddress(Settings.IP);
break;
case IPAddressType::Gateway: res = IPAddress(Settings.Gateway);
break;
case IPAddressType::Subnetmask: res = IPAddress(Settings.Subnet);
break;
case IPAddressType::DNS: res = IPAddress(Settings.DNS);
break;
}
if (IPAddressSet(res)) {
ip = res;
return true;
}
*/
return false;
}
@@ -180,6 +182,7 @@ bool NW002_data_struct_WiFi_AP::handle_priority_route_changed() { return NW002_u
bool NW002_data_struct_WiFi_AP::initPluginStats()
{
if (!Settings.getNetworkCollectStats(_networkIndex)) { return false; }
networkStatsVarIndex_t networkStatsVarIndex{};
PluginStats_Config_t displayConfig;
@@ -16,7 +16,7 @@
# include "../../../src/WebServer/ESPEasy_key_value_store_webform.h"
# if FEATURE_TASKVALUE_UNIT_OF_MEASURE
# include "../../../src/Helpers/ESPEasy_UnitOfMeasure.h"
# include "../../../src/Helpers/ESPEasy_UnitOfMeasure.h"
# endif // if FEATURE_TASKVALUE_UNIT_OF_MEASURE
@@ -875,7 +875,8 @@ void NW005_begin_modem_task(void *parameter)
NW_PLUGIN_INTERFACE.cmd(F("AT&D1"), 9000);
digitalWrite(modem_task_data->dtrPin, HIGH);
}
if (!NW_PLUGIN_INTERFACE.attached()) modem_task_data->modem_init_failed = true;
if (!NW_PLUGIN_INTERFACE.attached()) { modem_task_data->modem_init_failed = true; }
} else {
modem_task_data->modem_init_failed = true;
}
@@ -1047,6 +1048,7 @@ bool NW005_data_struct_PPP_modem::check_connect_failed()
{
_modem_task_data.modem_init_failed = false;
auto stats = getNWPluginData_static_runtime();
if (stats) {
stats->mark_connect_failed();
}
@@ -1059,6 +1061,7 @@ bool NW005_data_struct_PPP_modem::check_connect_failed()
bool NW005_data_struct_PPP_modem::initPluginStats()
{
if (!Settings.getNetworkCollectStats(_networkIndex)) { return false; }
networkStatsVarIndex_t networkStatsVarIndex{};
PluginStats_Config_t displayConfig;
@@ -1108,13 +1111,13 @@ bool NW005_data_struct_PPP_modem::record_stats()
NWPluginData_static_runtime * NW005_data_struct_PPP_modem::getNWPluginData_static_runtime() { return &stats_and_cache; }
bool NW005_data_struct_PPP_modem::getStaticIPAddress(IPAddressType addressType, IPAddress & ip) const
bool NW005_data_struct_PPP_modem::getStaticIPAddress(IPAddressType addressType, IPAddress& ip) const
{
// No static IP for PPP modem
return false;
return false;
}
void NW005_data_struct_PPP_modem::onEvent(arduino_event_id_t event, arduino_event_info_t info) {
void NW005_data_struct_PPP_modem::onEvent(arduino_event_id_t event, arduino_event_info_t info) {
// TODO TD-er: Must store flags from events in static (or global) object to act on it later.
switch (event)
{
+3 -1
View File
@@ -58,7 +58,9 @@ bool initNWPluginData(ESPEasy::net::networkIndex_t networkIndex, NWPluginData_ba
#endif // if FEATURE_STORE_NETWORK_INTERFACE_SETTINGS
#if FEATURE_NETWORK_STATS
NWPlugin_task_data[networkIndex]->initPluginStats();
if (Settings.getNetworkCollectStats(networkIndex)) {
NWPlugin_task_data[networkIndex]->initPluginStats();
}
#endif // if FEATURE_NETWORK_STATS
} else {
+7 -1
View File
@@ -394,7 +394,13 @@
#define DEFAULT_ENABLE_TIMING_STATS false
#endif
#ifndef DEFAULT_NETWORK_COLLECT_STATS_BITS
#ifdef PLUGIN_BUILD_MAX_ESP32
#define DEFAULT_NETWORK_COLLECT_STATS_BITS 0xFF
#else
#define DEFAULT_NETWORK_COLLECT_STATS_BITS 0
#endif
#endif
// --- Advanced Settings ---------------------------------------------------------------------------------
#if defined(ESP32)
+8 -1
View File
@@ -506,6 +506,13 @@ public:
void setNetworkInterfaceStartupDelay(ESPEasy::net::networkIndex_t index, uint32_t delay_ms);
# if FEATURE_NETWORK_STATS
bool getNetworkCollectStats(ESPEasy::net::networkIndex_t index) const;
void setNetworkCollectStats(ESPEasy::net::networkIndex_t index, bool enabled);
#endif
uint32_t PID = 0;
int Version = 0;
int16_t Build = 0;
@@ -581,7 +588,7 @@ public:
uint32_t ConnectionFailuresThreshold = 0;
int16_t TimeZone = 0;
boolean MQTTRetainFlag_unused = false;
uint8_t NetworkCollectStats_bits = DEFAULT_NETWORK_COLLECT_STATS_BITS;
uint8_t InitSPI = 0; //0 = disabled, 1= enabled but for ESP32 there is option 2= SPI2 9 = User defined, see src/src/WebServer/HardwarePage.h enum SPI_Options_e
// FIXME TD-er: Must change to cpluginID_t, but then also another check must be added since changing the pluginID_t will also render settings incompatible
uint8_t Protocol[CONTROLLER_MAX] = {0};
+23 -1
View File
@@ -747,7 +747,9 @@ void SettingsStruct_tmpl<N_TASKS>::clearMisc() {
SyslogPort = 514;
VariousBits_3._all_bits = 0;
ConnectionFailuresThreshold = 0;
MQTTRetainFlag_unused = false;
#if FEATURE_NETWORK_STATS
NetworkCollectStats_bits = DEFAULT_NETWORK_COLLECT_STATS_BITS;
#endif
InitSPI = DEFAULT_SPI;
deepSleepOnFail = false;
UseValueLogger = false;
@@ -1621,4 +1623,24 @@ void SettingsStruct_tmpl<N_TASKS>::setNetworkInterfaceStartupDelay(ESPEasy::net:
}
# if FEATURE_NETWORK_STATS
template<uint32_t N_TASKS>
bool SettingsStruct_tmpl<N_TASKS>::getNetworkCollectStats(ESPEasy::net::networkIndex_t index) const
{
if (validNetworkIndex(index)) { return bitRead(NetworkCollectStats_bits, index); }
return false;
}
template<uint32_t N_TASKS>
void SettingsStruct_tmpl<N_TASKS>::setNetworkCollectStats(ESPEasy::net::networkIndex_t index, bool enabled)
{
if (validNetworkIndex(index)) {
bitWrite(NetworkCollectStats_bits, index, enabled);
}
}
# endif // if FEATURE_NETWORK_STATS
#endif // ifndef DATASTRUCTS_SETTINGSSTRUCT_CPP
+1
View File
@@ -65,6 +65,7 @@ extern bool MQTTclient_must_send_LWT_connected;
extern bool MQTTclient_connected;
extern int mqtt_reconnect_count;
extern LongTermTimer MQTTclient_next_connect_attempt;
#endif // if FEATURE_MQTT
#ifdef USES_P037
+4 -1
View File
@@ -295,10 +295,13 @@ void ResetFactory(bool formatFS)
// advanced Settings
// Settings.UseRules = DEFAULT_USE_RULES;
Settings.ControllerEnabled[0] = DEFAULT_CONTROLLER_ENABLED;
Settings.MQTTRetainFlag_unused = DEFAULT_MQTT_RETAIN;
Settings.MessageDelay_unused = DEFAULT_MQTT_DELAY;
Settings.MQTTUseUnitNameAsClientId_unused = DEFAULT_MQTT_USE_UNITNAME_AS_CLIENTID;
#if FEATURE_NETWORK_STATS
Settings.NetworkCollectStats_bits = DEFAULT_NETWORK_COLLECT_STATS_BITS;
#endif
// allow to set default latitude and longitude
#ifdef DEFAULT_LATITUDE
Settings.Latitude = DEFAULT_LATITUDE;
+1 -1
View File
@@ -392,7 +392,7 @@ bool BuildFixes()
safe_strncpy(ControllerSettings->ClientID, clientid, sizeof(ControllerSettings->ClientID));
ControllerSettings->mqtt_uniqueMQTTclientIdReconnect(Settings.uniqueMQTTclientIdReconnect_unused());
ControllerSettings->mqtt_retainFlag(Settings.MQTTRetainFlag_unused);
ControllerSettings->mqtt_retainFlag(DEFAULT_MQTT_RETAIN);
SaveControllerSettings(controller_idx, *ControllerSettings);
}
}
+1 -1
View File
@@ -509,7 +509,7 @@ bool ESPEasy_time::systemTimePresent() const {
bool ESPEasy_time::getNtpTime(double& unixTime_d)
{
if (!Settings.UseNTP() || !ESPEasy::net::NetworkConnected()) {
if (!Settings.UseNTP() || !ESPEasy::net::NetworkConnected(true)) {
return false;
}
+2
View File
@@ -9,6 +9,8 @@
#include "../Helpers/Hardware_I2C.h"
#include "../Helpers/StringConverter.h"
#include "../Helpers/I2C_access.h"
#if FEATURE_I2C_MULTIPLE
# include "../WebServer/Markup_Forms.h"
#endif // if FEATURE_I2C_MULTIPLE
+13 -2
View File
@@ -154,9 +154,19 @@ void sendUDP(uint8_t unit, const uint8_t *data, uint8_t size)
/*********************************************************************************************\
Update UDP port (ESPEasy propiertary protocol)
\*********************************************************************************************/
uint16_t lastUsedUDPPort = 0;
void stopUDPport()
{
if (lastUsedUDPPort == 0) return;
if (ESPEasy::net::NetworkConnected(true)) {
portUDP.stop();
}
lastUsedUDPPort = 0;
}
void updateUDPport(bool force)
{
static uint16_t lastUsedUDPPort = 0;
if (!force && (Settings.UDPPort == lastUsedUDPPort)) {
return;
@@ -169,7 +179,8 @@ void updateUDPport(bool force)
//const bool connected = ESPEasy::net::NetworkConnected();
if (!connected || (Settings.UDPPort != lastUsedUDPPort)) {
if (lastUsedUDPPort != 0) {
portUDP.stop();
if (connected)
portUDP.stop();
lastUsedUDPPort = 0;
#ifndef BUILD_NO_DEBUG
addLogMove(LOG_LEVEL_INFO, concat(F("UDP : Stop listening on port "), Settings.UDPPort));
+1
View File
@@ -38,6 +38,7 @@
/*********************************************************************************************\
Update UDP port (ESPEasy propiertary protocol)
\*********************************************************************************************/
void stopUDPport();
void updateUDPport(bool force);
+2 -2
View File
@@ -408,7 +408,7 @@ void processMQTTdelayQueue() {
}
void updateMQTTclient_connected() {
const bool actual_MQTTclient_connected = ESPEasy::net::NetworkConnected() && MQTTclient.connected();
const bool actual_MQTTclient_connected = ESPEasy::net::NetworkConnected(true) && MQTTclient.connected();
if (MQTTclient_connected != actual_MQTTclient_connected) {
MQTTclient_connected = actual_MQTTclient_connected;
if (!actual_MQTTclient_connected) mqtt.stop(); // Make sure PubSubClient isn't trying to do a graceful disconnect
@@ -456,7 +456,7 @@ void updateMQTTclient_connected() {
void runPeriodicalMQTT() {
START_TIMER
// MQTT_KEEPALIVE = 15 seconds.
if (!NetworkConnected(10)) {
if (!ESPEasy::net::NetworkConnected()) {
updateMQTTclient_connected();
return;
}
-16
View File
@@ -107,10 +107,6 @@ void handle_advanced() {
Settings.ArduinoOTAEnable = isFormItemChecked(F("arduinootaenable"));
Settings.UseRTOSMultitasking = isFormItemChecked(F("usertosmultitasking"));
// MQTT settings now moved to the controller settings.
// Settings.MQTTRetainFlag_unused = isFormItemChecked(F("mqttretainflag"));
// Settings.MQTTUseUnitNameAsClientId = isFormItemChecked(F("mqttuseunitnameasclientid"));
// Settings.uniqueMQTTclientIdReconnect(isFormItemChecked(F("uniquemqttclientidreconnect")));
Settings.Latitude = getFormItemFloat(F("latitude"));
Settings.Longitude = getFormItemFloat(F("longitude"));
#ifdef WEBSERVER_NEW_RULES
@@ -199,18 +195,6 @@ void handle_advanced() {
addFormCheckBox(F("SendToHTTP wait for ack"), F("sendtohttp_ack"), Settings.SendToHttp_ack());
addFormCheckBox(F("SendToHTTP Follow Redirects"), F("sendtohttp_redir"), Settings.SendToHTTP_follow_redirects());
/*
// MQTT settings now moved to the controller settings.
addFormSubHeader(F("Controller Settings"));
addFormNumericBox(F("Message Interval"), F("messagedelay"), Settings.MessageDelay_unused, 0, INT_MAX);
addUnit(F("ms"));
addFormCheckBox(F("MQTT Retain Msg"), F("mqttretainflag"), Settings.MQTTRetainFlag_unused);
addFormCheckBox(F("MQTT use unit name as ClientId"), F("mqttuseunitnameasclientid"), Settings.MQTTUseUnitNameAsClientId);
addFormCheckBox(F("MQTT change ClientId at reconnect"), F("uniquemqttclientidreconnect"), Settings.uniqueMQTTclientIdReconnect_unused());
*/
addFormSubHeader(F("Time Source"));
addFormCheckBox(F("Use NTP"), F("usentp"), Settings.UseNTP());
+9 -2
View File
@@ -172,6 +172,9 @@ void handle_networks_CopySubmittedSettings_NWPluginCall(ESPEasy::net::networkInd
# if FEATURE_USE_IPV6
Settings.setNetworkEnabled_IPv6(networkindex, isFormItemChecked(F("en_ipv6")));
# endif
# if FEATURE_NETWORK_STATS
Settings.setNetworkCollectStats(networkindex, isFormItemChecked(F("collect_netw_stats")));
# endif
Settings.setNetworkInterfaceStartupDelay(networkindex, getFormItemInt(F("delay_start")));
String dummy;
@@ -197,9 +200,9 @@ void handle_networks_ShowAllNetworksTable()
html_table_header(F("Hostname/SSID"));
html_table_header(F("HW Address"));
html_table_header(F("IP"));
# ifdef ESP32
# ifdef ESP32
html_table_header(F("Port"));
# endif
# endif
for (ESPEasy::net::networkIndex_t x = 0; x < MAX_NR_NETWORKS_IN_TABLE; x++)
{
@@ -415,6 +418,10 @@ void handle_networks_NetworkSettingsPage(ESPEasy::net::networkIndex_t networkind
}
# endif // if FEATURE_USE_IPV6
# if FEATURE_NETWORK_STATS
addFormCheckBox(F("Collect Network Stats"), F("collect_netw_stats"), Settings.getNetworkCollectStats(networkindex));
# endif // if FEATURE_NETWORK_STATS
String str;
ESPEasy::net::NWPluginCall(NWPlugin::Function::NWPLUGIN_WEBFORM_LOAD, &TempEvent, str);