126 Commits

Author SHA1 Message Date
proddy
7eb1f061b7 Merge remote-tracking branch 'origin/dev' for 3.2.0 release 2021-08-06 12:06:08 +02:00
proddy
5e4f5916f2 prep for 3.2.0 release 2021-08-06 12:01:42 +02:00
Proddy
1450737d94 make boiler id first in device registry, so it's first in MQTT payload 2021-08-03 13:28:04 +02:00
Proddy
bfd20e559e minor changes, make cppcheck happy 2021-08-03 13:23:33 +02:00
Proddy
98a7932dee optimizations 2021-08-03 13:23:09 +02:00
Proddy
19e26d0d64 don't show commands in web or console 2021-08-03 13:22:45 +02:00
Proddy
1715218864 update to b3 2021-08-03 13:22:13 +02:00
Proddy
e503c6cd79 remove msg moves 2021-08-03 13:22:02 +02:00
Proddy
9515e3d00b text changes 2021-08-03 13:21:43 +02:00
proddy
53e25ae213 lint warning changes 2021-08-01 23:44:40 +02:00
proddy
4863ecc329 add KB195i 2021-08-01 11:55:12 +02:00
proddy
b5892f5b5e text changes 2021-08-01 11:34:55 +02:00
proddy
d16502c872 auto-formatting 2021-08-01 11:34:48 +02:00
proddy
e29fb9ba8a updated 3.2.0b2 2021-07-29 16:55:36 +02:00
proddy
2ee0411582 text changes 2021-07-29 16:54:22 +02:00
proddy
f210466cb1 download buttons for settings 2021-07-29 16:54:08 +02:00
proddy
6af28b1c29 download button for log 2021-07-29 16:53:42 +02:00
proddy
049be2484e don't show dallas in system/info as its not an ems device 2021-07-29 16:53:06 +02:00
proddy
8f438e8045 rename add_json() 2021-07-29 16:52:33 +02:00
proddy
a8382dd6ce bump version 2021-07-29 16:52:06 +02:00
proddy
c55385d6d8 update mock data 2021-07-28 18:00:26 +02:00
proddy
87e6691433 remove comment 2021-07-28 18:00:14 +02:00
proddy
aa9ba65f70 comment changes 2021-07-28 10:40:17 +02:00
proddy
39fef48915 Update ArduinoJson to 6.18.3 2021-07-28 10:06:51 +02:00
proddy
362fead7e8 make standalone compile 2021-07-27 21:48:42 +02:00
proddy
e809ed3743 add max messages and make web log dynamic - #71 2021-07-27 21:44:12 +02:00
proddy
dc8c322b42 auto-formatting 2021-07-27 21:43:36 +02:00
proddy
c5688ab632 manually merge in official 0.9.0 version 2021-07-27 21:43:17 +02:00
proddy
d5d75eee63 remove comment 2021-07-27 21:42:37 +02:00
MichaelDvP
6ec16733c3 Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into dev 2021-07-26 11:55:06 +02:00
proddy
ce2b2658ad mention wwactivated fix 2021-07-26 11:49:42 +02:00
proddy
3a866b1aea fix browser warning 2021-07-26 11:46:26 +02:00
MichaelDvP
1cf938e16a Syslog host setting as ipv4 or hostname 2021-07-26 11:41:23 +02:00
MichaelDvP
1df427366f syslog add hostname, rename host_ to ip_, query status 2021-07-26 11:06:23 +02:00
MichaelDvP
f97cdcb4d6 fix #89
Also Norbert have 0xFF on his list.
2021-07-25 11:52:42 +02:00
proddy
15c682cd1e don't show CRC in log (irrelevant to most people) 2021-07-24 15:02:58 +02:00
proddy
008983be26 comment update 2021-07-24 15:02:12 +02:00
proddy
2f01000665 minor debug text changed 2021-07-24 15:01:53 +02:00
proddy
616955daef use system gpio adc 2021-07-24 12:02:45 +02:00
proddy
e22b191a48 comments, fix typos, prep for v3.2 2021-07-24 11:56:39 +02:00
MichaelDvP
8930c52ada analog input use calibrated mV 2021-07-23 12:09:41 +02:00
MichaelDvP
6d94335079 Fix crash on unknown commands (cf==nullptr) 2021-07-22 19:35:27 +02:00
proddy
f2e0b193af Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into dev 2021-07-22 13:52:09 +02:00
proddy
5b55902cd9 sync up with HA MQTT Discovery when dallas sensor changed #84 2021-07-22 13:51:59 +02:00
MichaelDvP
694f647a2c Command returns as enum 2021-07-22 13:00:16 +02:00
MichaelDvP
fc1cb00523 reload values after write and update 2021-07-22 12:54:02 +02:00
proddy
2fda59d7db latest asyncmqttclient dev changes - to safeguard against stuck connections 2021-07-21 16:25:42 +02:00
proddy
a95837404a valiadtion in sensor fields, auto refresh after change #84 2021-07-21 16:00:39 +02:00
proddy
c6db2a1adf label change 2021-07-21 15:59:44 +02:00
proddy
f6d22732a0 formatting 2021-07-21 15:59:29 +02:00
MichaelDvP
220a69938f fix mqtt individual subscriptions 2021-07-21 09:37:46 +02:00
proddy
d438866864 updated with log changes 2021-07-20 23:37:56 +02:00
proddy
2e0ed9ce9f fix error where eventsource wasn't flushed correctly & included the log ID 2021-07-20 23:36:49 +02:00
proddy
5de3b69e2c refresh sync changed from 200 to 300ms 2021-07-20 23:36:16 +02:00
proddy
dfd6798377 added log id and changed format layout 2021-07-20 23:35:52 +02:00
proddy
074ae2a5a1 some refactoring 2021-07-20 21:45:59 +02:00
proddy
77f6a18075 commands take a set of flags, like NEED_ADMIN or HIDDEN 2021-07-20 21:45:29 +02:00
proddy
0762d9e124 bump to b6 2021-07-20 21:43:03 +02:00
proddy
37dae04715 clean up ts 2021-07-20 13:01:56 +02:00
proddy
f299a7ad14 update calls to dallas library 2021-07-20 13:01:45 +02:00
proddy
ba295385ab rename allDevices endpoint to data. improve dallas sensor form 2021-07-20 13:01:22 +02:00
proddy
33adf518ae update 2021-07-20 13:00:01 +02:00
proddy
93885d0dd5 update 2021-07-20 12:59:48 +02:00
proddy
747cda79db rename add_name() to update(). show offset in log msg 2021-07-20 12:59:37 +02:00
proddy
f3cfc38adc update regex for ipv6 #83 2021-07-19 19:21:03 +02:00
proddy
dd3a0a706d auto-formatting 2021-07-19 16:55:41 +02:00
proddy
37d001e7b5 formatting 2021-07-19 16:44:53 +02:00
proddy
add09e5a1c update mock api to work with latest changes 2021-07-19 16:44:46 +02:00
Proddy
561d1c0e55 fix typo 2021-07-18 21:48:18 +02:00
proddy
239ba335b1 changes to make it compile standalone 2021-07-18 21:44:24 +02:00
proddy
ec83123090 rename Makefile 2021-07-18 21:43:25 +02:00
MichaelDvP
4f6d5164a4 Set sensornames from web 2021-07-18 20:42:02 +02:00
MichaelDvP
ae1e2eccd2 minExtTemp for RC300 2021-07-18 20:40:51 +02:00
MichaelDvP
d7bc821bbe calculate dallassensor offset 2021-07-17 06:50:13 +02:00
MichaelDvP
f8579f7c96 formatting 2021-07-16 16:45:38 +02:00
MichaelDvP
046a9ef6f2 show dallas-temperatures always with digit on web 2021-07-16 16:26:58 +02:00
MichaelDvP
64e15542a2 show api type of commands as command instead of unknown 2021-07-16 16:25:20 +02:00
MichaelDvP
7dec674452 moving dallas-setting, cleanup 2021-07-16 16:24:03 +02:00
MichaelDvP
0f48d3e72c add sensorname console command 2021-07-16 10:57:43 +02:00
MichaelDvP
1f793c49ae Move dallas/bool/enum formats to Settings #76 2021-07-16 10:16:32 +02:00
MichaelDvP
e581539cf9 Fix #78 2021-07-15 11:09:59 +02:00
MichaelDvP
736eee79df fix change-check 2021-07-14 18:10:04 +02:00
MichaelDvP
7a0fe3819b reset Settingsflags after update 2021-07-14 17:02:40 +02:00
MichaelDvP
65c9bf7e52 check bufferlength, add formatstrings 2021-07-14 17:00:14 +02:00
MichaelDvP
1e61b5670e delay in emsesp-loop as mentioned in #78 2021-07-11 15:50:15 +02:00
MichaelDvP
6c2bae6296 remove SM10 collector min/max wrong values 2021-07-11 15:19:51 +02:00
MichaelDvP
358d6010b0 Web selectbox for enum commands (like bool) 2021-07-11 15:02:24 +02:00
MichaelDvP
82978a25c5 show wwtapactivated as value 2021-07-11 14:42:12 +02:00
MichaelDvP
3519696bae add boiler ww-hysteresis, maintenance settings 2021-07-11 14:34:18 +02:00
MichaelDvP
bd33df2cc7 Junkers mode/set_mode synchronized 2021-07-11 14:15:39 +02:00
MichaelDvP
5f44eb14ad allow numbers for set_mode 2021-07-11 14:01:24 +02:00
MichaelDvP
fb94cf953a no enum numbers for "hamode" 2021-07-11 13:52:16 +02:00
MichaelDvP
d7486218bc enum start at zero 2021-07-11 13:50:56 +02:00
MichaelDvP
59913cdc4b disable bluetooth, show IPv6 in web, mqtt and console 2021-07-08 18:56:24 +02:00
MichaelDvP
2d7449aeba add network options, IPv6 for mqtt 2021-07-08 10:17:50 +02:00
proddy
3ea53a8012 updated doc and version 2021-07-07 09:19:01 +02:00
MichaelDvP
48cd12ec3d NTP time for weblog 2021-07-06 07:35:39 +02:00
MichaelDvP
7c71ed2dc6 fix mem leak 2021-07-06 07:35:15 +02:00
proddy
24d8ccc52f fix crash with IPv6 and ETH - #83 2021-07-05 22:55:39 +02:00
proddy
05cd96f2be IPv6 support by MichaelDvP - #83 2021-07-05 22:43:08 +02:00
proddy
75795ab1e9 fix shower on/off when using non-default MQTT booleans 2021-07-05 21:44:38 +02:00
proddy
bb1602f179 typo 2021-07-05 21:44:12 +02:00
proddy
ac268f0f73 lower WiFi tx when using -DEMSESP_WIFI_TWEAK 2021-07-05 21:44:04 +02:00
Proddy
d924567e5f include debug target 2021-07-05 16:55:23 +02:00
Proddy
109d8df782 don't show mem updates on EMSESP_DEBUG 2021-07-05 16:54:41 +02:00
Proddy
0aaa35098d remove obsolete scripts 2021-07-05 16:54:15 +02:00
Proddy
6f57beab28 cleanup build 2021-07-05 16:53:57 +02:00
Proddy
5b26e27834 Update to 16.8.1 2021-07-05 16:53:27 +02:00
Proddy
8429f650aa fix lint warnings 2021-07-03 20:32:46 +02:00
proddy
3eb2202117 add test to crash EMS-ESP 2021-07-03 20:20:56 +02:00
proddy
c217a40710 remove CRC in warning message 2021-07-03 20:20:43 +02:00
proddy
4a7308c5bb add linux commands 2021-07-03 20:20:27 +02:00
proddy
5fba51103e cleanup 2021-07-03 20:20:07 +02:00
proddy
95a9808f35 add debug target 2021-07-03 20:19:57 +02:00
proddy
c09e180c48 add linters 2021-07-03 20:19:43 +02:00
proddy
b09b650c1d remove # from dallas in api/system/info 2021-07-03 10:44:15 +02:00
proddy
44a41b963d add upload_sec to api/system/info and removed # from some names to keep consistent with MQTT heartbeat - #80 2021-07-02 16:24:50 +02:00
proddy
0510189f54 slow down MQTT reconnect to 2 seconds 2021-07-01 11:19:00 +02:00
MichaelDvP
16b3cf764d don't count wrong tx-echos as rx-errors 2021-07-01 09:34:34 +02:00
MichaelDvP
c634c39874 3. fix for mqtt enable (#79) 2021-06-30 14:26:46 +02:00
MichaelDvP
ae0846e877 mqtt connect on enable-change (#79) 2021-06-30 13:49:52 +02:00
MichaelDvP
40e7e1b418 always register subscriptions (#79) 2021-06-30 13:13:18 +02:00
proddy
e2a5853dde rename WIFI in System settings to Network 2021-06-29 22:57:21 +02:00
MichaelDvP
e419e67cb0 fix memory leak (#78) 2021-06-29 09:37:05 +02:00
proddy
3356a4ce14 fix v16 for nodejs 2021-06-26 11:14:45 +02:00
proddy
26a4347155 prep for 3.1.2 2021-06-26 11:05:04 +02:00
155 changed files with 4430 additions and 3172 deletions

2
.gitignore vendored
View File

@@ -27,4 +27,4 @@ emsesp
/interface/build /interface/build
node_modules node_modules
/interface/.eslintcache /interface/.eslintcache
test.sh

View File

@@ -5,6 +5,42 @@ 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/), 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/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
# [3.2.0] August 6 2021
## Added
- support for IPv6 (web/api/mqtt, not syslog yet) [#83](https://github.com/emsesp/EMS-ESP32/issues/83)
- System Log in Web UI will show current time if the NTP Service is enabled [#82](https://github.com/emsesp/EMS-ESP32/issues/82)
- Network settings for Tx-power, WiFi-bandwidth, WiFi-sleepmode [#83](https://github.com/emsesp/EMS-ESP32/issues/83)
- optional low CPU clockrate (160 MHz) [#83](https://github.com/emsesp/EMS-ESP32/issues/83)
- select format for enumerated values in web
- settings for water hysteresis on/off
- dallas sensor name editable. `sensorname` console-command, replace sensorid with a unique name [#84](https://github.com/emsesp/EMS-ESP32/issues/84)
- 'restart' system command. Can be invoked via API with authentication. [#87](https://github.com/emsesp/EMS-ESP32/issues/87)
- add Download button in Web UI for log
## Fixed
- set mode allow numbers
- Junkers thermostat shows mode as selected by set_mode
- HA thermostat mode if bool-format: numbers is selected
- Web UI System Log sometimes skipped a few log messages when watching real-time
- fix wwactivated [#89](https://github.com/emsesp/EMS-ESP32/issues/89)
- don't show commands (like reset) as Device values in the Web or Console
## Changed
- removed Rx echo failures counting as incomplete telegrams. Bad telegrams show as Warning and not Errors. [#80](https://github.com/emsesp/EMS-ESP32/issues/80)
- add upload_sec to `api/system/info` and removed # from some names to keep consistent with MQTT heartbeat
- added debug target to PlatformIO build to help hunt down system crashes
- enumerated values always start at zero
- maintenance settings for time/date as extra setting
- move api/mqtt formats to `settings`, add `enum format`
- UI improvements for editing Dallas Sensor details
- RESTful GET commands can also require authentication (via bearer access token) for better security
- Updated AsyncMqttClient to 0.9.0 and ArduinoJson to 6.18.3
- Download buttons for settings and info under the Help tab
# [3.1.1] June 26 2021 # [3.1.1] June 26 2021
## Changed ## Changed

View File

@@ -5,5 +5,3 @@
## Fixed ## Fixed
## Changed ## Changed
## Removed

View File

@@ -24,17 +24,17 @@ This document describes rules that are in effect for this repository, meant for
## Triaging of Issues/PR's ## Triaging of Issues/PR's
1. Any contributor to the project can participate in the triaging process, if he/she chooses to do so. 1. Any contributor to the project can participate in the triaging process, if he/she chooses to do so.
2. An issue that needs to be closed, either due to not complying with this policy, or for other reasons, should be closed by a contributor. 2. An issue that needs to be closed, either due to not complying with this policy, or for other reasons, should be closed by a contributor.
3. Issues that are accepted should be marked with appropriate labels. 3. Issues that are accepted should be marked with appropriate labels.
4. Issues that could impact functionality for many users should be considered severe. 4. Issues that could impact functionality for many users should be considered severe.
5. Issues caused by the SDK or chip should not be marked severe, as there usually isnt much to be done. Common sense should be applied when deciding. Such issues should be documented in the documentation, for reference by users. 5. Issues caused by the SDK or chip should not be marked severe, as there usually isnt much to be done. Common sense should be applied when deciding. Such issues should be documented in the documentation, for reference by users.
6. Issues with feature requests should be discussed for viability/desirability. 6. Issues with feature requests should be discussed for viability/desirability.
7. Feature requests or changes that are meant to address a very specific/limited use case, especially if at the expense of increased code complexity, may be denied, or may be required to be redesigned, generalized, or simplified. 7. Feature requests or changes that are meant to address a very specific/limited use case, especially if at the expense of increased code complexity, may be denied, or may be required to be redesigned, generalized, or simplified.
8. Feature requests that are not accompanied by a PR: 8. Feature requests that are not accompanied by a PR:
* could be closed immediately (denied). - could be closed immediately (denied).
* could be closed after some predetermined period of time (left as candidate for somebody to pick up). - could be closed after some predetermined period of time (left as candidate for somebody to pick up).
9. In some cases, feedback may be requested from the issue reporter, either as additional info for clarification, additional testing, or other. If no feedback is provided, the issue may be closed by a contributor or after 40 days by the STALE bot. 9. In some cases, feedback may be requested from the issue reporter, either as additional info for clarification, additional testing, or other. If no feedback is provided, the issue may be closed by a contributor or after 40 days by the STALE bot.
## Pull requests ## Pull requests
@@ -42,24 +42,24 @@ A Pull Request (PR) is the process where code modifications are managed in GitHu
The process is straight-forward. The process is straight-forward.
- Read [How to get faster PR reviews](https://github.com/kubernetes/community/blob/master/contributors/guide/pull-requests.md#best-practices-for-faster-reviews) by Kubernetes (but skip step 0) - Read [How to get faster PR reviews](https://github.com/kubernetes/community/blob/master/contributors/guide/pull-requests.md#best-practices-for-faster-reviews) by Kubernetes (but skip step 0)
- Fork the EMS-ESP Repository [git repository](https://github.com/emsesp/EMS-ESP32). - Fork the EMS-ESP Repository [git repository](https://github.com/emsesp/EMS-ESP32).
- Write/Change the code in your Fork for a new feature, bug fix, new sensor, optimization, etc. - Write/Change the code in your Fork for a new feature, bug fix, new sensor, optimization, etc.
- Ensure tests work. - Ensure tests work.
- Create a Pull Request against the [**dev**](https://github.com/emsesp/EMS-ESP32/tree/dev) branch of EMS-ESP. - Create a Pull Request against the [**dev**](https://github.com/emsesp/EMS-ESP32/tree/dev) branch of EMS-ESP.
1. All pull requests must be done against the dev branch. 1. All pull requests must be done against the dev branch.
2. Make sure code is formatting per the `.clang-format` 2. Make sure code is formatting per the `.clang-format`.
3. Only relevant files should be touched (Also beware if your editor has auto-formatting feature enabled). 3. Make sure any new code is clearly commented explaining what the function/logic does.
4. Only one feature/fix should be added per PR. 4. Only relevant files should be touched (Also beware if your editor has auto-formatting feature enabled).
5. PRs that don't compile (fail in CI Tests) or cause coding errors will not be merged. Please fix the issue. Same goes for PRs that are raised against older commit in dev - you might need to rebase and resolve conflicts. 5. Only one feature/fix should be added per PR.
6. All pull requests should undergo peer review by at least one contributor other than the creator, excepts for the owner. 6. PRs that don't compile (fail in CI Tests) or cause coding errors will not be merged. Please fix the issue. Same goes for PRs that are raised against older commit in dev - you might need to rebase and resolve conflicts.
7. All pull requests should consider updates to the documentation. 7. All pull requests should undergo peer review by at least one contributor other than the creator, excepts for the owner.
8. Pull requests that address an outstanding issue, particularly an issue deemed to be severe, should be given priority. 8. All pull requests should consider updates to the documentation.
9. If a PR is accepted, then it should undergo review and updated based on the feedback provided, then merged. 9. Pull requests that address an outstanding issue, particularly an issue deemed to be severe, should be given priority.
10. By submitting a PR, it is needed to use the provided PR template and check all boxes, performing the required tasks and accepting the CLA. 10. If a PR is accepted, then it should undergo review and updated based on the feedback provided, then merged.
11. Pull requests that don't meet the above will be denied and closed. 11. By submitting a PR, it is needed to use the provided PR template and check all boxes, performing the required tasks and accepting the CLA.
12. Pull requests that don't meet the above will be denied and closed.
## Semantic Commit Messages ## Semantic Commit Messages
@@ -92,7 +92,7 @@ More Examples:
References: References:
- https://www.conventionalcommits.org/ - <https://www.conventionalcommits.org/>
-------------------------------------- --------------------------------------

View File

@@ -72,9 +72,9 @@ CPPFLAGS += -g3
CPPFLAGS += -Os CPPFLAGS += -Os
CFLAGS += $(CPPFLAGS) CFLAGS += $(CPPFLAGS)
# CFLAGS += -Wall CFLAGS += -Wall
# CFLAGS += -Wno-unused -Wno-restrict CFLAGS += -Wno-unused -Wno-restrict
# CFLAGS += -Wextra CFLAGS += -Wextra
CXXFLAGS += $(CFLAGS) -MMD CXXFLAGS += $(CFLAGS) -MMD

View File

@@ -1,6 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags # Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000, nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000, otadata, data, ota, 0xE000, 0x2000,
app0, app, ota_0, 0x10000, 0x1F0000, app0, app, ota_0, 0x10000, 0x1F0000,
app1, app, ota_1, 0x200000, 0x1F0000, app1, app, ota_1, 0x200000, 0x1F0000,
spiffs, data, spiffs, 0x3F0000,0x10000, spiffs, data, spiffs, 0x3F0000, 0x10000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0xE000 0x2000
4 app0 app ota_0 0x10000 0x1F0000
5 app1 app ota_1 0x200000 0x1F0000
6 spiffs data spiffs 0x3F0000 0x10000

View File

@@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xE000, 0x2000,
app0, app, ota_0, 0x10000, 0x210000,
spiffs, data, spiffs, 0x220000, 0x10000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xE000 0x2000
4 app0 app ota_0 0x10000 0x210000
5 spiffs data spiffs 0x220000 0x10000

View File

@@ -4,6 +4,7 @@ export const PROJECT_PATH = process.env.REACT_APP_PROJECT_PATH!;
export const ENDPOINT_ROOT = calculateEndpointRoot('/rest/'); export const ENDPOINT_ROOT = calculateEndpointRoot('/rest/');
export const WEB_SOCKET_ROOT = calculateWebSocketRoot('/ws/'); export const WEB_SOCKET_ROOT = calculateWebSocketRoot('/ws/');
export const EVENT_SOURCE_ROOT = calculateEndpointRoot('/es/'); export const EVENT_SOURCE_ROOT = calculateEndpointRoot('/es/');
export const API_ENDPOINT_ROOT = calculateEndpointRoot('/api/');
function calculateEndpointRoot(endpointPath: string) { function calculateEndpointRoot(endpointPath: string) {
const httpRoot = process.env.REACT_APP_HTTP_ROOT; const httpRoot = process.env.REACT_APP_HTTP_ROOT;

View File

@@ -109,7 +109,7 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
/> />
<TextField <TextField
name="client_id" name="client_id"
label="Client ID (optional)" label="Client ID"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.client_id} value={data.client_id}
@@ -159,7 +159,7 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
value="clean_session" value="clean_session"
/> />
} }
label="Clean Session" label="Set Clean Session"
/> />
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
@@ -169,7 +169,7 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
value="mqtt_retain" value="mqtt_retain"
/> />
} }
label="Retain Flag" label="Use Retain Flag"
/> />
<br></br> <br></br>
<Typography variant="h6" color="primary"> <Typography variant="h6" color="primary">
@@ -184,34 +184,8 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
onChange={handleValueChange('nested_format')} onChange={handleValueChange('nested_format')}
margin="normal" margin="normal"
> >
<MenuItem value={1}>nested on a single topic</MenuItem> <MenuItem value={1}>Nested on a single topic</MenuItem>
<MenuItem value={2}>as individual topics</MenuItem> <MenuItem value={2}>As individual topics</MenuItem>
</SelectValidator>
<SelectValidator
name="dallas_format"
label="Dallas Sensor Payload Grouping"
value={data.dallas_format}
fullWidth
variant="outlined"
onChange={handleValueChange('dallas_format')}
margin="normal"
>
<MenuItem value={1}>by Sensor ID</MenuItem>
<MenuItem value={2}>by Number</MenuItem>
</SelectValidator>
<SelectValidator
name="bool_format"
label="Boolean Format"
value={data.bool_format}
fullWidth
variant="outlined"
onChange={handleValueChange('bool_format')}
margin="normal"
>
<MenuItem value={1}>"on"/"off"</MenuItem>
<MenuItem value={2}>true/false</MenuItem>
<MenuItem value={3}>1/0</MenuItem>
<MenuItem value={4}>"ON"/"OFF"</MenuItem>
</SelectValidator> </SelectValidator>
<SelectValidator <SelectValidator
name="subscribe_format" name="subscribe_format"
@@ -222,9 +196,9 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
onChange={handleValueChange('subscribe_format')} onChange={handleValueChange('subscribe_format')}
margin="normal" margin="normal"
> >
<MenuItem value={0}>general device topic</MenuItem> <MenuItem value={0}>General device topic</MenuItem>
<MenuItem value={1}>individual topics, main heating circuit</MenuItem> <MenuItem value={1}>Individual topics, main heating circuit</MenuItem>
<MenuItem value={2}>individual topics, all heating circuits</MenuItem> <MenuItem value={2}>Individual topics, all heating circuits</MenuItem>
</SelectValidator> </SelectValidator>
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
@@ -246,9 +220,9 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
onChange={handleValueChange('ha_climate_format')} onChange={handleValueChange('ha_climate_format')}
margin="normal" margin="normal"
> >
<MenuItem value={1}>use Current temperature (default)</MenuItem> <MenuItem value={1}>Use Current temperature</MenuItem>
<MenuItem value={2}>use Setpoint temperature</MenuItem> <MenuItem value={2}>Use Setpoint temperature</MenuItem>
<MenuItem value={3}>Fix to 0</MenuItem> <MenuItem value={3}>Always set to 0</MenuItem>
</SelectValidator> </SelectValidator>
)} )}
<br></br> <br></br>

View File

@@ -34,8 +34,6 @@ export interface MqttSettings {
publish_time_mixer: number; publish_time_mixer: number;
publish_time_other: number; publish_time_other: number;
publish_time_sensor: number; publish_time_sensor: number;
dallas_format: number;
bool_format: number;
mqtt_qos: number; mqtt_qos: number;
mqtt_retain: boolean; mqtt_retain: boolean;
ha_enabled: boolean; ha_enabled: boolean;

View File

@@ -51,7 +51,11 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
ssid: selectedNetwork.ssid, ssid: selectedNetwork.ssid,
password: '', password: '',
hostname: props.data.hostname, hostname: props.data.hostname,
static_ip_config: false static_ip_config: false,
enableIPv6: false,
bandwidth20: false,
tx_power: 20,
nosleep: false
}; };
props.setData(networkSettings); props.setData(networkSettings);
} }
@@ -145,6 +149,53 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
onChange={handleValueChange('hostname')} onChange={handleValueChange('hostname')}
margin="normal" margin="normal"
/> />
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:20']}
errorMessages={[
'Tx Power is required',
'Must be a number',
'Must be greater than 0dBm ',
'Max value is 20dBm'
]}
name="tx_power"
label="WiFi Tx Power (dBm)"
fullWidth
variant="outlined"
value={data.tx_power}
type="number"
onChange={handleValueChange('tx_power')}
margin="normal"
/>
<BlockFormControlLabel
control={
<Checkbox
value="enableIPv6"
checked={data.enableIPv6}
onChange={handleValueChange('enableIPv6')}
/>
}
label="Enable IPv6 support"
/>
<BlockFormControlLabel
control={
<Checkbox
value="bandwidth20"
checked={data.bandwidth20}
onChange={handleValueChange('bandwidth20')}
/>
}
label="Use Lower WiFi Bandwidth"
/>
<BlockFormControlLabel
control={
<Checkbox
value="nosleep"
checked={data.nosleep}
onChange={handleValueChange('nosleep')}
/>
}
label="Disable WiFi Sleep Mode"
/>
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
<Checkbox <Checkbox
@@ -153,7 +204,7 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
onChange={handleValueChange('static_ip_config')} onChange={handleValueChange('static_ip_config')}
/> />
} }
label="Static IP Config" label="Use Static IPs"
/> />
{data.static_ip_config && ( {data.static_ip_config && (
<Fragment> <Fragment>

View File

@@ -40,7 +40,22 @@ class NetworkStatusForm extends Component<NetworkStatusFormProps> {
if (!status.dns_ip_1) { if (!status.dns_ip_1) {
return 'none'; return 'none';
} }
return status.dns_ip_1 + (status.dns_ip_2 ? ',' + status.dns_ip_2 : ''); if (!status.dns_ip_2 || status.dns_ip_2 === '0.0.0.0') {
return status.dns_ip_1;
}
return status.dns_ip_1 + ', ' + status.dns_ip_2;
}
IPs(status: NetworkStatus) {
if (
!status.local_ipv6 ||
status.local_ipv6 === '0000:0000:0000:0000:0000:0000:0000:0000'
) {
return status.local_ip;
}
if (!status.local_ip || status.local_ip === '0.0.0.0') {
return status.local_ipv6;
}
return status.local_ip + ', ' + status.local_ipv6;
} }
createListItems() { createListItems() {
@@ -77,7 +92,7 @@ class NetworkStatusForm extends Component<NetworkStatusFormProps> {
<ListItemAvatar> <ListItemAvatar>
<Avatar>IP</Avatar> <Avatar>IP</Avatar>
</ListItemAvatar> </ListItemAvatar>
<ListItemText primary="IP Address" secondary={data.local_ip} /> <ListItemText primary="IP Address" secondary={this.IPs(data)} />
</ListItem> </ListItem>
<Divider variant="inset" component="li" /> <Divider variant="inset" component="li" />
<ListItem> <ListItem>

View File

@@ -21,6 +21,7 @@ export enum WiFiEncryptionType {
export interface NetworkStatus { export interface NetworkStatus {
status: NetworkConnectionStatus; status: NetworkConnectionStatus;
local_ip: string; local_ip: string;
local_ipv6: string;
mac_address: string; mac_address: string;
rssi: number; rssi: number;
ssid: string; ssid: string;
@@ -37,6 +38,10 @@ export interface NetworkSettings {
password: string; password: string;
hostname: string; hostname: string;
static_ip_config: boolean; static_ip_config: boolean;
enableIPv6: boolean;
bandwidth20: boolean;
nosleep: boolean;
tx_power: number;
local_ip?: string; local_ip?: string;
gateway_ip?: string; gateway_ip?: string;
subnet_mask?: string; subnet_mask?: string;

View File

@@ -8,7 +8,7 @@ import { MenuAppBar } from '../components';
import { AuthenticatedRoute } from '../authentication'; import { AuthenticatedRoute } from '../authentication';
import EMSESPStatusController from './EMSESPStatusController'; import EMSESPStatusController from './EMSESPStatusController';
import EMSESPDevicesController from './EMSESPDevicesController'; import EMSESPDataController from './EMSESPDataController';
import EMSESPHelp from './EMSESPHelp'; import EMSESPHelp from './EMSESPHelp';
class EMSESP extends Component<RouteComponentProps> { class EMSESP extends Component<RouteComponentProps> {
@@ -24,18 +24,15 @@ class EMSESP extends Component<RouteComponentProps> {
onChange={(e, path) => this.handleTabChange(path)} onChange={(e, path) => this.handleTabChange(path)}
variant="fullWidth" variant="fullWidth"
> >
<Tab <Tab value={`/${PROJECT_PATH}/data`} label="Devices &amp; Sensors" />
value={`/${PROJECT_PATH}/devices`}
label="Devices &amp; Sensors"
/>
<Tab value={`/${PROJECT_PATH}/status`} label="EMS Status" /> <Tab value={`/${PROJECT_PATH}/status`} label="EMS Status" />
<Tab value={`/${PROJECT_PATH}/help`} label="EMS-ESP Help" /> <Tab value={`/${PROJECT_PATH}/help`} label="EMS-ESP Help" />
</Tabs> </Tabs>
<Switch> <Switch>
<AuthenticatedRoute <AuthenticatedRoute
exact exact
path={`/${PROJECT_PATH}/devices`} path={`/${PROJECT_PATH}/data`}
component={EMSESPDevicesController} component={EMSESPDataController}
/> />
<AuthenticatedRoute <AuthenticatedRoute
exact exact
@@ -47,7 +44,7 @@ class EMSESP extends Component<RouteComponentProps> {
path={`/${PROJECT_PATH}/help`} path={`/${PROJECT_PATH}/help`}
component={EMSESPHelp} component={EMSESPHelp}
/> />
<Redirect to={`/${PROJECT_PATH}/devices`} /> <Redirect to={`/${PROJECT_PATH}/data`} />
</Switch> </Switch>
</MenuAppBar> </MenuAppBar>
); );

View File

@@ -0,0 +1,35 @@
import React, { Component } from 'react';
import {
restController,
RestControllerProps,
RestFormLoader,
SectionContent
} from '../components';
import { ENDPOINT_ROOT } from '../api';
import EMSESPDataForm from './EMSESPDataForm';
import { EMSESPData } from './EMSESPtypes';
export const EMSESP_DATA_ENDPOINT = ENDPOINT_ROOT + 'data';
type EMSESPDataControllerProps = RestControllerProps<EMSESPData>;
class EMSESPDataController extends Component<EMSESPDataControllerProps> {
componentDidMount() {
this.props.loadData();
}
render() {
return (
<SectionContent title="Devices &amp; Sensors">
<RestFormLoader
{...this.props}
render={(formProps) => <EMSESPDataForm {...formProps} />}
/>
</SectionContent>
);
}
}
export default restController(EMSESP_DATA_ENDPOINT, EMSESPDataController);

View File

@@ -40,21 +40,24 @@ import {
import { RestFormProps, FormButton, extractEventValue } from '../components'; import { RestFormProps, FormButton, extractEventValue } from '../components';
import { import {
EMSESPDevices, EMSESPData,
EMSESPDeviceData, EMSESPDeviceData,
Device, Device,
DeviceValue, DeviceValue,
DeviceValueUOM, DeviceValueUOM,
DeviceValueUOM_s DeviceValueUOM_s,
Sensor
} from './EMSESPtypes'; } from './EMSESPtypes';
import ValueForm from './ValueForm'; import ValueForm from './ValueForm';
import SensorForm from './SensorForm';
import { ENDPOINT_ROOT } from '../api'; import { ENDPOINT_ROOT } from '../api';
export const SCANDEVICES_ENDPOINT = ENDPOINT_ROOT + 'scanDevices'; export const SCANDEVICES_ENDPOINT = ENDPOINT_ROOT + 'scanDevices';
export const DEVICE_DATA_ENDPOINT = ENDPOINT_ROOT + 'deviceData'; export const DEVICE_DATA_ENDPOINT = ENDPOINT_ROOT + 'deviceData';
export const WRITE_VALUE_ENDPOINT = ENDPOINT_ROOT + 'writeValue'; export const WRITE_VALUE_ENDPOINT = ENDPOINT_ROOT + 'writeValue';
export const WRITE_SENSOR_ENDPOINT = ENDPOINT_ROOT + 'writeSensor';
const StyledTableCell = withStyles((theme: Theme) => const StyledTableCell = withStyles((theme: Theme) =>
createStyles({ createStyles({
@@ -88,15 +91,16 @@ function compareDevices(a: Device, b: Device) {
return 0; return 0;
} }
interface EMSESPDevicesFormState { interface EMSESPDataFormState {
confirmScanDevices: boolean; confirmScanDevices: boolean;
processing: boolean; processing: boolean;
deviceData?: EMSESPDeviceData; deviceData?: EMSESPDeviceData;
selectedDevice?: number; selectedDevice?: number;
edit_devicevalue?: DeviceValue; edit_devicevalue?: DeviceValue;
edit_Sensor?: Sensor;
} }
type EMSESPDevicesFormProps = RestFormProps<EMSESPDevices> & type EMSESPDataFormProps = RestFormProps<EMSESPData> &
AuthenticatedContextProps & AuthenticatedContextProps &
WithWidthProps; WithWidthProps;
@@ -118,18 +122,27 @@ export const formatDuration = (duration_min: number) => {
const pluralize = (count: number, noun: string, suffix = 's') => const pluralize = (count: number, noun: string, suffix = 's') =>
` ${count} ${noun}${count !== 1 ? suffix : ''} `; ` ${count} ${noun}${count !== 1 ? suffix : ''} `;
function formatValue(value: any, uom: number) { function formatValue(value: any, uom: number, digit: number) {
switch (uom) { switch (uom) {
case DeviceValueUOM.HOURS: case DeviceValueUOM.HOURS:
return value ? formatDuration(value * 60) : '0 hours'; return value ? formatDuration(value * 60) : '0 hours';
case DeviceValueUOM.MINUTES: case DeviceValueUOM.MINUTES:
return value ? formatDuration(value) : '0 minutes'; return value ? formatDuration(value) : '0 minutes';
case DeviceValueUOM.NONE: case DeviceValueUOM.NONE:
case DeviceValueUOM.LIST:
return value; return value;
case DeviceValueUOM.NUM: case DeviceValueUOM.NUM:
return new Intl.NumberFormat().format(value); return new Intl.NumberFormat().format(value);
case DeviceValueUOM.BOOLEAN: case DeviceValueUOM.BOOLEAN:
return value ? 'on' : 'off'; return value ? 'on' : 'off';
case DeviceValueUOM.DEGREES:
return (
new Intl.NumberFormat(undefined, {
minimumFractionDigits: digit
}).format(value) +
' ' +
DeviceValueUOM_s[uom]
);
default: default:
return ( return (
new Intl.NumberFormat().format(value) + ' ' + DeviceValueUOM_s[uom] new Intl.NumberFormat().format(value) + ' ' + DeviceValueUOM_s[uom]
@@ -137,16 +150,16 @@ function formatValue(value: any, uom: number) {
} }
} }
class EMSESPDevicesForm extends Component< class EMSESPDataForm extends Component<
EMSESPDevicesFormProps, EMSESPDataFormProps,
EMSESPDevicesFormState EMSESPDataFormState
> { > {
state: EMSESPDevicesFormState = { state: EMSESPDataFormState = {
confirmScanDevices: false, confirmScanDevices: false,
processing: false processing: false
}; };
handleValueChange = (name: keyof DeviceValue) => ( handleDeviceValueChange = (name: keyof DeviceValue) => (
event: React.ChangeEvent<HTMLInputElement> event: React.ChangeEvent<HTMLInputElement>
) => { ) => {
this.setState({ this.setState({
@@ -157,11 +170,11 @@ class EMSESPDevicesForm extends Component<
}); });
}; };
cancelEditingValue = () => { cancelEditingDeviceValue = () => {
this.setState({ edit_devicevalue: undefined }); this.setState({ edit_devicevalue: undefined });
}; };
doneEditingValue = () => { doneEditingDeviceValue = () => {
const { edit_devicevalue, selectedDevice } = this.state; const { edit_devicevalue, selectedDevice } = this.state;
redirectingAuthorizedFetch(WRITE_VALUE_ENDPOINT, { redirectingAuthorizedFetch(WRITE_VALUE_ENDPOINT, {
@@ -179,6 +192,7 @@ class EMSESPDevicesForm extends Component<
this.props.enqueueSnackbar('Write command sent to device', { this.props.enqueueSnackbar('Write command sent to device', {
variant: 'success' variant: 'success'
}); });
this.handleRowClick(selectedDevice);
} else if (response.status === 204) { } else if (response.status === 204) {
this.props.enqueueSnackbar('Write command failed', { this.props.enqueueSnackbar('Write command failed', {
variant: 'error' variant: 'error'
@@ -206,6 +220,72 @@ class EMSESPDevicesForm extends Component<
this.setState({ edit_devicevalue: dv }); this.setState({ edit_devicevalue: dv });
}; };
handleSensorChange = (name: keyof Sensor) => (
event: React.ChangeEvent<HTMLInputElement>
) => {
this.setState({
edit_Sensor: {
...this.state.edit_Sensor!,
[name]: extractEventValue(event)
}
});
};
cancelEditingSensor = () => {
this.setState({ edit_Sensor: undefined });
};
doneEditingSensor = () => {
const { edit_Sensor } = this.state;
redirectingAuthorizedFetch(WRITE_SENSOR_ENDPOINT, {
method: 'POST',
body: JSON.stringify({
// because input field with type=number doens't like negative values, force it here
sensor: {
no: edit_Sensor?.no,
id: edit_Sensor?.id,
temp: edit_Sensor?.temp,
offset: Number(edit_Sensor?.offset)
}
}),
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => {
if (response.status === 200) {
this.props.enqueueSnackbar('Sensor updated', {
variant: 'success'
});
this.props.loadData();
} else if (response.status === 204) {
this.props.enqueueSnackbar('Sensor change failed', {
variant: 'error'
});
} else if (response.status === 403) {
this.props.enqueueSnackbar('Write access denied', {
variant: 'error'
});
} else {
throw Error('Unexpected response code: ' + response.status);
}
})
.catch((error) => {
this.props.enqueueSnackbar(error.message || 'Problem writing value', {
variant: 'error'
});
});
if (edit_Sensor) {
this.setState({ edit_Sensor: undefined });
}
};
sendSensor = (sn: Sensor) => {
this.setState({ edit_Sensor: sn });
};
noDevices = () => { noDevices = () => {
return this.props.data.devices.length === 0; return this.props.data.devices.length === 0;
}; };
@@ -236,7 +316,7 @@ class EMSESPDevicesForm extends Component<
<TableRow <TableRow
hover hover
key={device.id} key={device.id}
onClick={() => this.handleRowClick(device)} onClick={() => this.handleRowClick(device.id)}
> >
<TableCell> <TableCell>
<CustomTooltip <CustomTooltip
@@ -289,30 +369,49 @@ class EMSESPDevicesForm extends Component<
renderSensorItems() { renderSensorItems() {
const { data } = this.props; const { data } = this.props;
const me = this.props.authenticatedContext.me;
return ( return (
<TableContainer> <TableContainer>
<p></p> <p></p>
<Typography variant="h6" color="primary" paragraph> <Typography variant="h6" color="primary" paragraph>
Dallas Sensors Sensors
</Typography> </Typography>
{!this.noSensors() && ( {!this.noSensors() && (
<Table size="small" padding="default"> <Table size="small" padding="default">
<TableHead> <TableHead>
<TableRow> <TableRow>
<StyledTableCell
padding="checkbox"
style={{ width: 18 }}
></StyledTableCell>
<StyledTableCell>Sensor #</StyledTableCell> <StyledTableCell>Sensor #</StyledTableCell>
<StyledTableCell align="center">ID</StyledTableCell> <StyledTableCell align="left">ID / Name</StyledTableCell>
<StyledTableCell align="right">Temperature</StyledTableCell> <StyledTableCell align="right">Temperature</StyledTableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{data.sensors.map((sensorData) => ( {data.sensors.map((sensorData) => (
<TableRow key={sensorData.no}> <TableRow key={sensorData.no} hover>
<TableCell padding="checkbox" style={{ width: 18 }}>
{me.admin && (
<CustomTooltip title="edit" placement="left-end">
<IconButton
edge="start"
size="small"
aria-label="Edit"
onClick={() => this.sendSensor(sensorData)}
>
<EditIcon color="primary" fontSize="small" />
</IconButton>
</CustomTooltip>
)}
</TableCell>
<TableCell component="th" scope="row"> <TableCell component="th" scope="row">
{sensorData.no} {sensorData.no}
</TableCell> </TableCell>
<TableCell align="center">{sensorData.id}</TableCell> <TableCell align="left">{sensorData.id}</TableCell>
<TableCell align="right"> <TableCell align="right">
{formatValue(sensorData.temp, DeviceValueUOM.DEGREES)} {formatValue(sensorData.temp, DeviceValueUOM.DEGREES, 1)}
</TableCell> </TableCell>
</TableRow> </TableRow>
))} ))}
@@ -322,7 +421,7 @@ class EMSESPDevicesForm extends Component<
{this.noSensors() && ( {this.noSensors() && (
<Box color="warning.main" p={0} mt={0} mb={0}> <Box color="warning.main" p={0} mt={0} mb={0}>
<Typography variant="body1"> <Typography variant="body1">
<i>no external temperature sensors were detected</i> <i>no connected Dallas temperature sensors were detected</i>
</Typography> </Typography>
</Box> </Box>
)} )}
@@ -330,6 +429,34 @@ class EMSESPDevicesForm extends Component<
); );
} }
renderAnalog() {
const { data } = this.props;
return (
<TableContainer>
{data.analog > 0 && (
<Table size="small" padding="default">
<TableHead>
<TableRow>
<StyledTableCell>Sensortype</StyledTableCell>
<StyledTableCell align="right">Value</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell component="th" scope="row">
Analog Input
</TableCell>
<TableCell align="right">
{formatValue(data.analog, DeviceValueUOM.MV, 0)}
</TableCell>
</TableRow>
</TableBody>
</Table>
)}
</TableContainer>
);
}
renderScanDevicesDialog() { renderScanDevicesDialog() {
return ( return (
<Dialog <Dialog
@@ -396,10 +523,10 @@ class EMSESPDevicesForm extends Component<
}; };
handleRowClick = (device: any) => { handleRowClick = (device: any) => {
this.setState({ selectedDevice: device.id, deviceData: undefined }); this.setState({ selectedDevice: device, deviceData: undefined });
redirectingAuthorizedFetch(DEVICE_DATA_ENDPOINT, { redirectingAuthorizedFetch(DEVICE_DATA_ENDPOINT, {
method: 'POST', method: 'POST',
body: JSON.stringify({ id: device.id }), body: JSON.stringify({ id: device }),
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
@@ -475,7 +602,7 @@ class EMSESPDevicesForm extends Component<
{item.n} {item.n}
</TableCell> </TableCell>
<TableCell padding="none" align="right"> <TableCell padding="none" align="right">
{formatValue(item.v, item.u)} {formatValue(item.v, item.u, 0)}
</TableCell> </TableCell>
</TableRow> </TableRow>
))} ))}
@@ -495,13 +622,14 @@ class EMSESPDevicesForm extends Component<
} }
render() { render() {
const { edit_devicevalue } = this.state; const { edit_devicevalue, edit_Sensor } = this.state;
return ( return (
<Fragment> <Fragment>
<br></br> <br></br>
{this.renderDeviceItems()} {this.renderDeviceItems()}
{this.renderDeviceData()} {this.renderDeviceData()}
{this.renderSensorItems()} {this.renderSensorItems()}
{this.renderAnalog()}
<br></br> <br></br>
<Box display="flex" flexWrap="wrap"> <Box display="flex" flexWrap="wrap">
<Box flexGrow={1} padding={1}> <Box flexGrow={1} padding={1}>
@@ -528,9 +656,17 @@ class EMSESPDevicesForm extends Component<
{edit_devicevalue && ( {edit_devicevalue && (
<ValueForm <ValueForm
devicevalue={edit_devicevalue} devicevalue={edit_devicevalue}
onDoneEditing={this.doneEditingValue} onDoneEditing={this.doneEditingDeviceValue}
onCancelEditing={this.cancelEditingValue} onCancelEditing={this.cancelEditingDeviceValue}
handleValueChange={this.handleValueChange} handleValueChange={this.handleDeviceValueChange}
/>
)}
{edit_Sensor && (
<SensorForm
sensor={edit_Sensor}
onDoneEditing={this.doneEditingSensor}
onCancelEditing={this.cancelEditingSensor}
handleSensorChange={this.handleSensorChange}
/> />
)} )}
</Fragment> </Fragment>
@@ -538,4 +674,4 @@ class EMSESPDevicesForm extends Component<
} }
} }
export default withAuthenticatedContext(withWidth()(EMSESPDevicesForm)); export default withAuthenticatedContext(withWidth()(EMSESPDataForm));

View File

@@ -1,35 +0,0 @@
import React, { Component } from 'react';
import {
restController,
RestControllerProps,
RestFormLoader,
SectionContent
} from '../components';
import { ENDPOINT_ROOT } from '../api';
import EMSESPDevicesForm from './EMSESPDevicesForm';
import { EMSESPDevices } from './EMSESPtypes';
export const EMSESP_DEVICES_ENDPOINT = ENDPOINT_ROOT + 'allDevices';
type EMSESPDevicesControllerProps = RestControllerProps<EMSESPDevices>;
class EMSESPDevicesController extends Component<EMSESPDevicesControllerProps> {
componentDidMount() {
this.props.loadData();
}
render() {
return (
<SectionContent title="Devices &amp; Sensors">
<RestFormLoader
{...this.props}
render={(formProps) => <EMSESPDevicesForm {...formProps} />}
/>
</SectionContent>
);
}
}
export default restController(EMSESP_DEVICES_ENDPOINT, EMSESPDevicesController);

View File

@@ -1,4 +1,4 @@
import React, { Component } from 'react'; import { Component } from 'react';
import { import {
Typography, Typography,
Box, Box,
@@ -14,14 +14,40 @@ import CommentIcon from '@material-ui/icons/CommentTwoTone';
import MenuBookIcon from '@material-ui/icons/MenuBookTwoTone'; import MenuBookIcon from '@material-ui/icons/MenuBookTwoTone';
import GitHubIcon from '@material-ui/icons/GitHub'; import GitHubIcon from '@material-ui/icons/GitHub';
import StarIcon from '@material-ui/icons/Star'; import StarIcon from '@material-ui/icons/Star';
import ImportExportIcon from '@material-ui/icons/ImportExport'; import DownloadIcon from '@material-ui/icons/GetApp';
import BugReportIcon from '@material-ui/icons/BugReportTwoTone';
export const WebAPISystemSettings = import { FormButton } from '../components';
window.location.origin + '/api/system/settings';
export const WebAPISystemInfo = window.location.origin + '/api/system/info'; import { API_ENDPOINT_ROOT } from '../api';
import { redirectingAuthorizedFetch } from '../authentication';
class EMSESPHelp extends Component { class EMSESPHelp extends Component {
onDownload = (endpoint: string) => {
redirectingAuthorizedFetch(API_ENDPOINT_ROOT + 'system/' + endpoint)
.then((response) => {
if (response.status === 200) {
return response.json();
}
throw Error(
'Device returned unexpected response code: ' + response.status
);
})
.then((json) => {
const a = document.createElement('a');
const filename = 'emsesp_system_' + endpoint + '.txt';
a.href = URL.createObjectURL(
new Blob([JSON.stringify(json, null, 2)], {
type: 'text/plain'
})
);
a.setAttribute('download', filename);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
};
render() { render() {
return ( return (
<SectionContent title="EMS-ESP Help" titleGutter> <SectionContent title="EMS-ESP Help" titleGutter>
@@ -31,9 +57,9 @@ class EMSESPHelp extends Component {
<MenuBookIcon /> <MenuBookIcon />
</ListItemAvatar> </ListItemAvatar>
<ListItemText> <ListItemText>
For the latest news and updates go to the{' '} For help and information on the latest updates visit the{' '}
<Link href="https://emsesp.github.io/docs" color="primary"> <Link href="https://emsesp.github.io/docs" color="primary">
{'official documentation'}&nbsp;website {'online documentation'}
</Link> </Link>
</ListItemText> </ListItemText>
</ListItem> </ListItem>
@@ -55,41 +81,36 @@ class EMSESPHelp extends Component {
<GitHubIcon /> <GitHubIcon />
</ListItemAvatar> </ListItemAvatar>
<ListItemText> <ListItemText>
To report an issue or feature request go to{' '} To report an issue or request a feature go to{' '}
<Link <Link
href="https://github.com/emsesp/EMS-ESP32/issues/new/choose" href="https://github.com/emsesp/EMS-ESP32/issues/new/choose"
color="primary" color="primary"
> >
{'click here'} {'GitHub'}
</Link>
</ListItemText>
</ListItem>
<ListItem>
<ListItemAvatar>
<ImportExportIcon />
</ListItemAvatar>
<ListItemText>
To export your system settings{' '}
<Link target="_blank" href={WebAPISystemSettings} color="primary">
{'click here'}
</Link>
</ListItemText>
</ListItem>
<ListItem>
<ListItemAvatar>
<BugReportIcon />
</ListItemAvatar>
<ListItemText>
To export the current status of EMS-ESP{' '}
<Link target="_blank" href={WebAPISystemInfo} color="primary">
{'click here'}
</Link> </Link>
</ListItemText> </ListItemText>
</ListItem> </ListItem>
</List> </List>
<Box flexWrap="none" padding={1} whiteSpace="nowrap">
<FormButton
startIcon={<DownloadIcon />}
variant="contained"
color="primary"
onClick={() => this.onDownload('info')}
>
download system info
</FormButton>
<FormButton
startIcon={<DownloadIcon />}
variant="contained"
color="primary"
onClick={() => this.onDownload('settings')}
>
download all settings
</FormButton>
</Box>
<Box bgcolor="info.main" border={1} p={3} mt={1} mb={0}> <Box bgcolor="info.main" border={1} p={3} mt={1} mb={0}>
<Typography variant="h6"> <Typography variant="h6">
EMS-ESP is free and open-source. EMS-ESP is free and open-source.

View File

@@ -32,7 +32,7 @@ import {
BlockFormControlLabel BlockFormControlLabel
} from '../components'; } from '../components';
import { isIP, optional } from '../validators'; import { isIPv4, optional, isHostname, or } from '../validators';
import { EMSESPSettings } from './EMSESPtypes'; import { EMSESPSettings } from './EMSESPtypes';
@@ -55,7 +55,10 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
}; };
componentDidMount() { componentDidMount() {
ValidatorForm.addValidationRule('isOptionalIP', optional(isIP)); ValidatorForm.addValidationRule(
'isOptionalIPorHost',
optional(or(isIPv4, isHostname))
);
} }
changeBoardProfile = (event: React.ChangeEvent<HTMLSelectElement>) => { changeBoardProfile = (event: React.ChangeEvent<HTMLSelectElement>) => {
@@ -109,15 +112,17 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
<ValidatorForm onSubmit={saveData}> <ValidatorForm onSubmit={saveData}>
<Box bgcolor="info.main" p={2} mt={2} mb={2}> <Box bgcolor="info.main" p={2} mt={2} mb={2}>
<Typography variant="body1"> <Typography variant="body1">
Adjust any of the EMS-ESP settings here. For help refer to the{' '} <i>
<Link Refer to the
target="_blank" <Link
href="https://emsesp.github.io/docs/#/Configure-firmware32?id=ems-esp-settings" target="_blank"
color="primary" href="https://emsesp.github.io/docs/#/Configure-firmware32?id=ems-esp-settings"
> color="primary"
{'online documentation'} >
</Link> {' documentation'}
. </Link>
&nbsp;for information on each setting
</i>
</Typography> </Typography>
</Box> </Box>
@@ -202,7 +207,7 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
<Typography variant="body2"> <Typography variant="body2">
<i> <i>
Select a pre-configured board layout to automatically set the GPIO Select a pre-configured board layout to automatically set the GPIO
pins, or set your own custom configuration pins. Select "Custom..." to view or manually edit the values.
</i> </i>
</Typography> </Typography>
</Box> </Box>
@@ -365,7 +370,7 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
<br></br> <br></br>
<Typography variant="h6" color="primary"> <Typography variant="h6" color="primary">
Options General Options
</Typography> </Typography>
{data.led_gpio !== 0 && ( {data.led_gpio !== 0 && (
@@ -390,20 +395,10 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
value="dallas_parasite" value="dallas_parasite"
/> />
} }
label="Enable Dallas parasite mode" label="Use Dallas Sensor parasite power"
/> />
)} )}
<BlockFormControlLabel
control={
<Checkbox
checked={data.notoken_api}
onChange={handleValueChange('notoken_api')}
value="notoken_api"
/>
}
label="Bypass Access Token authorization on API calls"
/>
<BlockFormControlLabel <BlockFormControlLabel
control={ control={
<Checkbox <Checkbox
@@ -414,6 +409,26 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
} }
label="Enable ADC" label="Enable ADC"
/> />
<BlockFormControlLabel
control={
<Checkbox
checked={data.low_clock}
onChange={handleValueChange('low_clock')}
value="low_clock"
/>
}
label="Run at a lower CPU clock speed"
/>
<BlockFormControlLabel
control={
<Checkbox
checked={data.notoken_api}
onChange={handleValueChange('notoken_api')}
value="notoken_api"
/>
}
label="Bypass Access Token authorization on API calls"
/>
<Grid <Grid
container container
spacing={0} spacing={0}
@@ -443,6 +458,65 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
/> />
</Grid> </Grid>
<br></br>
<Typography variant="h6" color="primary">
Formatting Options
</Typography>
<Grid
container
spacing={1}
direction="row"
justify="flex-start"
alignItems="flex-start"
>
<Grid item xs={4}>
<SelectValidator
name="bool_format"
label="Boolean Format"
value={data.bool_format}
fullWidth
variant="outlined"
onChange={handleValueChange('bool_format')}
margin="normal"
>
<MenuItem value={1}>"on"/"off"</MenuItem>
<MenuItem value={2}>"ON"/"OFF"</MenuItem>
<MenuItem value={3}>true/false</MenuItem>
<MenuItem value={4}>1/0</MenuItem>
</SelectValidator>
</Grid>
<Grid item xs={4}>
<SelectValidator
name="enum_format"
label="Enum Format"
value={data.enum_format}
fullWidth
variant="outlined"
onChange={handleValueChange('enum_format')}
margin="normal"
>
<MenuItem value={1}>Text</MenuItem>
<MenuItem value={2}>Number</MenuItem>
</SelectValidator>
</Grid>
<Grid item xs={4}>
<SelectValidator
name="dallas_format"
label="Dallas Sensor Format"
value={data.dallas_format}
fullWidth
variant="outlined"
onChange={handleValueChange('dallas_format')}
margin="normal"
>
<MenuItem value={1}>ID</MenuItem>
<MenuItem value={2}>Number</MenuItem>
<MenuItem value={3}>Name</MenuItem>
</SelectValidator>
</Grid>
</Grid>
<br></br> <br></br>
<Typography variant="h6" color="primary"> <Typography variant="h6" color="primary">
Syslog Syslog
@@ -469,10 +543,10 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
> >
<Grid item xs={5}> <Grid item xs={5}>
<TextValidator <TextValidator
validators={['isOptionalIP']} validators={['isOptionalIPorHost']}
errorMessages={['Not a valid IP address']} errorMessages={['Not a valid IPv4 address or hostname']}
name="syslog_host" name="syslog_host"
label="IP" label="Host"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.syslog_host} value={data.syslog_host}
@@ -537,7 +611,7 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
'Max value is 10' 'Max value is 10'
]} ]}
name="syslog_mark_interval" name="syslog_mark_interval"
label="Mark Interval seconds (0=off)" label="Mark Interval (seconds, 0=off)"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.syslog_mark_interval} value={data.syslog_mark_interval}
@@ -554,7 +628,7 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
value="trace_raw" value="trace_raw"
/> />
} }
label="Output EMS telegrams in raw format" label="Output EMS telegrams as hexadecimal bytes"
/> />
</Grid> </Grid>
)} )}

View File

@@ -16,11 +16,15 @@ export interface EMSESPSettings {
dallas_parasite: boolean; dallas_parasite: boolean;
led_gpio: number; led_gpio: number;
hide_led: boolean; hide_led: boolean;
low_clock: boolean;
notoken_api: boolean; notoken_api: boolean;
analog_enabled: boolean; analog_enabled: boolean;
pbutton_gpio: number; pbutton_gpio: number;
trace_raw: boolean; trace_raw: boolean;
board_profile: string; board_profile: string;
bool_format: number;
dallas_format: number;
enum_format: number;
} }
export enum busConnectionStatus { export enum busConnectionStatus {
@@ -50,12 +54,14 @@ export interface Device {
export interface Sensor { export interface Sensor {
no: number; no: number;
id: string; id: string;
temp: string; temp: number;
offset: number;
} }
export interface EMSESPDevices { export interface EMSESPData {
devices: Device[]; devices: Device[];
sensors: Sensor[]; sensors: Sensor[];
analog: number;
} }
export interface DeviceValue { export interface DeviceValue {
@@ -63,6 +69,7 @@ export interface DeviceValue {
u: number; u: number;
n: string; n: string;
c: string; c: string;
l: string[];
} }
export interface EMSESPDeviceData { export interface EMSESPDeviceData {
@@ -87,7 +94,9 @@ export enum DeviceValueUOM {
SECONDS, SECONDS,
DBM, DBM,
NUM, NUM,
BOOLEAN BOOLEAN,
LIST,
MV
} }
export const DeviceValueUOM_s = [ export const DeviceValueUOM_s = [
@@ -107,5 +116,7 @@ export const DeviceValueUOM_s = [
'seconds', 'seconds',
'dBm', 'dBm',
'number', 'number',
'on/off' 'on/off',
'',
'mV'
]; ];

View File

@@ -23,7 +23,7 @@ class ProjectMenu extends Component<ProjectProps> {
to="/ems-esp/" to="/ems-esp/"
selected={ selected={
path.startsWith('/ems-esp/status') || path.startsWith('/ems-esp/status') ||
path.startsWith('/ems-esp/devices') || path.startsWith('/ems-esp/data') ||
path.startsWith('/ems-esp/help') path.startsWith('/ems-esp/help')
} }
button button

View File

@@ -0,0 +1,101 @@
import React, { RefObject } from 'react';
import { ValidatorForm, TextValidator } from 'react-material-ui-form-validator';
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions
} from '@material-ui/core';
import { FormButton } from '../components';
import { Sensor } from './EMSESPtypes';
interface SensorFormProps {
sensor: Sensor;
onDoneEditing: () => void;
onCancelEditing: () => void;
handleSensorChange: (
data: keyof Sensor
) => (event: React.ChangeEvent<HTMLInputElement>) => void;
}
class SensorForm extends React.Component<SensorFormProps> {
formRef: RefObject<any> = React.createRef();
submit = () => {
this.formRef.current.submit();
};
render() {
const {
sensor,
handleSensorChange,
onDoneEditing,
onCancelEditing
} = this.props;
return (
<ValidatorForm onSubmit={onDoneEditing} ref={this.formRef}>
<Dialog
maxWidth="xs"
onClose={onCancelEditing}
aria-labelledby="user-form-dialog-title"
open
>
<DialogTitle id="user-form-dialog-title">
Editing Sensor #{sensor.no}
</DialogTitle>
<DialogContent dividers>
<TextValidator
validators={['matchRegexp:^([a-zA-Z0-9_.-]{0,19})$']}
errorMessages={['Not a valid name']}
fullWidth
variant="outlined"
value={sensor.id}
onChange={handleSensorChange('id')}
margin="normal"
label="Name"
name="id"
/>
<TextValidator
validators={['isFloat', 'minFloat:-5', 'maxFloat:5']}
errorMessages={[
'Must be a number',
'Must be greater than -5',
'Max value is +5'
]}
label="Custom Offset (°C)"
name="offset"
type="number"
value={sensor.offset}
fullWidth
variant="outlined"
InputProps={{ inputProps: { min: '-5', max: '5', step: '0.1' } }}
margin="normal"
onChange={handleSensorChange('offset')}
/>
</DialogContent>
<DialogActions>
<FormButton
variant="contained"
color="secondary"
onClick={onCancelEditing}
>
Cancel
</FormButton>
<FormButton
variant="contained"
color="primary"
type="submit"
onClick={this.submit}
>
Done
</FormButton>
</DialogActions>
</Dialog>
</ValidatorForm>
);
}
}
export default SensorForm;

View File

@@ -51,27 +51,39 @@ class ValueForm extends React.Component<ValueFormProps> {
> >
<DialogTitle id="user-form-dialog-title">Change Value</DialogTitle> <DialogTitle id="user-form-dialog-title">Change Value</DialogTitle>
<DialogContent dividers> <DialogContent dividers>
{devicevalue.u !== DeviceValueUOM.BOOLEAN && ( {devicevalue.u === DeviceValueUOM.LIST && (
<OutlinedInput <TextField
id="outlined-adornment-value" id="outlined-select-value"
select
value={devicevalue.v} value={devicevalue.v}
autoFocus autoFocus
fullWidth fullWidth
onChange={handleValueChange('v')} onChange={handleValueChange('v')}
endAdornment={ variant="outlined"
<InputAdornment position="end"> >
{DeviceValueUOM_s[devicevalue.u]} {devicevalue.l.map((val) => (
</InputAdornment> <MenuItem value={val}>{val}</MenuItem>
} ))}
aria-describedby="outlined-value-helper-text" </TextField>
inputProps={{
'aria-label': 'value'
}}
/>
)} )}
{devicevalue.u !== DeviceValueUOM.BOOLEAN &&
devicevalue.u !== DeviceValueUOM.LIST && (
<OutlinedInput
id="value"
value={devicevalue.v}
autoFocus
fullWidth
onChange={handleValueChange('v')}
endAdornment={
<InputAdornment position="end">
{DeviceValueUOM_s[devicevalue.u]}
</InputAdornment>
}
/>
)}
{devicevalue.u === DeviceValueUOM.BOOLEAN && ( {devicevalue.u === DeviceValueUOM.BOOLEAN && (
<TextField <TextField
id="outlined-select-value" id="selected-value"
select select
value={devicevalue.v} value={devicevalue.v}
autoFocus autoFocus
@@ -83,9 +95,7 @@ class ValueForm extends React.Component<ValueFormProps> {
<MenuItem value="false">off</MenuItem> <MenuItem value="false">off</MenuItem>
</TextField> </TextField>
)} )}
<FormHelperText id="outlined-value-helper-text"> <FormHelperText>{devicevalue.n}</FormHelperText>
{devicevalue.n}
</FormHelperText>
<Box color="warning.main" p={0} pl={0} pr={0} mt={4} mb={0}> <Box color="warning.main" p={0} pl={0} pr={0} mt={4} mb={0}>
<Typography variant="body2"> <Typography variant="body2">
<i> <i>

View File

@@ -44,7 +44,6 @@ class GenerateToken extends React.Component<
} }
}) })
.then((generatedToken) => { .then((generatedToken) => {
// console.log(generatedToken);
this.setState({ token: generatedToken.token }); this.setState({ token: generatedToken.token });
}) })
.catch((error) => { .catch((error) => {

View File

@@ -6,6 +6,8 @@ import { useWindowSize } from '../components';
interface LogEventConsoleProps { interface LogEventConsoleProps {
events: LogEvent[]; events: LogEvent[];
compact: boolean;
level: number;
} }
interface Offsets { interface Offsets {
@@ -63,7 +65,9 @@ const useStyles = makeStyles((theme: Theme) => ({
const LogEventConsole: FC<LogEventConsoleProps> = (props) => { const LogEventConsole: FC<LogEventConsoleProps> = (props) => {
useWindowSize(); useWindowSize();
const classes = useStyles({ topOffset, leftOffset }); const classes = useStyles({ topOffset, leftOffset });
const { events } = props; const { events, compact, level } = props;
const filter_events = events.filter((e) => e.l <= level);
const styleLevel = (level: LogLevel) => { const styleLevel = (level: LogLevel) => {
switch (level) { switch (level) {
@@ -103,23 +107,34 @@ const LogEventConsole: FC<LogEventConsoleProps> = (props) => {
} }
}; };
const paddedLevelLabel = (level: LogLevel) => { const paddedLevelLabel = (level: LogLevel, compact: boolean) => {
const label = levelLabel(level); const label = levelLabel(level);
return label.padStart(8, '\xa0'); return compact ? ' ' + label[0] : label.padStart(8, '\xa0');
}; };
const paddedNameLabel = (name: string) => { const paddedNameLabel = (name: string, compact: boolean) => {
const label = '[' + name + ']'; const label = '[' + name + ']';
return label.padStart(8, '\xa0'); return compact ? label : label.padEnd(12, '\xa0');
};
const paddedIDLabel = (id: number, compact: boolean) => {
const label = id + ':';
return compact ? label : label.padEnd(7, '\xa0');
}; };
return ( return (
<Box id="log-window" className={classes.console}> <Box id="log-window" className={classes.console}>
{events.map((e) => ( {filter_events.map((e) => (
<div className={classes.entry}> <div className={classes.entry} key={e.i}>
<span>{e.t}</span> <span>{e.t}</span>
<span className={styleLevel(e.l)}>{paddedLevelLabel(e.l)} </span> {compact && <span>{paddedLevelLabel(e.l, compact)} </span>}
<span>{paddedNameLabel(e.n)} </span> {!compact && (
<span className={styleLevel(e.l)}>
{paddedLevelLabel(e.l, compact)}{' '}
</span>
)}
<span>{paddedIDLabel(e.i, compact)} </span>
<span>{paddedNameLabel(e.n, compact)} </span>
<span>{e.m}</span> <span>{e.m}</span>
</div> </div>
))} ))}

View File

@@ -3,22 +3,38 @@ import { Component } from 'react';
import { import {
restController, restController,
RestControllerProps, RestControllerProps,
RestFormLoader, SectionContent,
SectionContent BlockFormControlLabel
} from '../components'; } from '../components';
import { addAccessTokenParameter } from '../authentication'; import {
ValidatorForm,
SelectValidator
} from 'react-material-ui-form-validator';
import {
Grid,
Slider,
FormLabel,
Checkbox,
MenuItem,
Button
} from '@material-ui/core';
import {
addAccessTokenParameter,
redirectingAuthorizedFetch
} from '../authentication';
import DownloadIcon from '@material-ui/icons/GetApp';
import { ENDPOINT_ROOT, EVENT_SOURCE_ROOT } from '../api'; import { ENDPOINT_ROOT, EVENT_SOURCE_ROOT } from '../api';
export const FETCH_LOG_ENDPOINT = ENDPOINT_ROOT + 'fetchLog'; export const FETCH_LOG_ENDPOINT = ENDPOINT_ROOT + 'fetchLog';
export const LOG_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'logSettings'; export const LOG_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'logSettings';
export const LOG_EVENT_EVENT_SOURCE_URL = EVENT_SOURCE_ROOT + 'log'; export const LOG_EVENT_EVENT_SOURCE_URL = EVENT_SOURCE_ROOT + 'log';
import LogEventForm from './LogEventForm';
import LogEventConsole from './LogEventConsole'; import LogEventConsole from './LogEventConsole';
import { LogEvent, LogSettings, LogLevel } from './types';
import { LogEvent, LogSettings } from './types';
import { Decoder } from '@msgpack/msgpack'; import { Decoder } from '@msgpack/msgpack';
const decoder = new Decoder(); const decoder = new Decoder();
@@ -26,6 +42,9 @@ const decoder = new Decoder();
interface LogEventControllerState { interface LogEventControllerState {
eventSource?: EventSource; eventSource?: EventSource;
events: LogEvent[]; events: LogEvent[];
compact: boolean;
level: number;
max_messages: number;
} }
type LogEventControllerProps = RestControllerProps<LogSettings>; type LogEventControllerProps = RestControllerProps<LogSettings>;
@@ -40,12 +59,15 @@ class LogEventController extends Component<
constructor(props: LogEventControllerProps) { constructor(props: LogEventControllerProps) {
super(props); super(props);
this.state = { this.state = {
events: [] events: [],
compact: false,
level: 6,
max_messages: 25
}; };
} }
componentDidMount() { componentDidMount() {
this.props.loadData(); this.fetchValues();
this.fetchLog(); this.fetchLog();
this.configureEventSource(); this.configureEventSource();
} }
@@ -59,6 +81,15 @@ class LogEventController extends Component<
} }
} }
changeCompact = (
event: React.ChangeEvent<HTMLInputElement>,
checked: boolean
) => {
this.setState({
compact: checked
});
};
fetchLog = () => { fetchLog = () => {
fetch(FETCH_LOG_ENDPOINT) fetch(FETCH_LOG_ENDPOINT)
.then((response) => { .then((response) => {
@@ -78,6 +109,25 @@ class LogEventController extends Component<
}); });
}; };
fetchValues = () => {
redirectingAuthorizedFetch(LOG_SETTINGS_ENDPOINT)
.then((response) => {
if (response.status === 200) {
return response.json();
}
throw Error('Unexpected status code: ' + response.status);
})
.then((json) => {
this.setState({ level: json.level, max_messages: json.max_messages });
})
.catch((error) => {
const errorMessage = error.message || 'Unknown error';
this.props.enqueueSnackbar('Problem fetching: ' + errorMessage, {
variant: 'error'
});
});
};
configureEventSource = () => { configureEventSource = () => {
this.eventSource = new EventSource( this.eventSource = new EventSource(
addAccessTokenParameter(LOG_EVENT_EVENT_SOURCE_URL) addAccessTokenParameter(LOG_EVENT_EVENT_SOURCE_URL)
@@ -102,14 +152,172 @@ class LogEventController extends Component<
} }
}; };
changeMaxMessages = (
event: React.ChangeEvent<{}>,
value: number | number[]
) => {
this.setState({
max_messages: value as number
});
this.send_data(this.state.level, value as number);
};
changeLevel = (event: React.ChangeEvent<HTMLSelectElement>) => {
this.setState({
level: parseInt(event.target.value)
});
this.send_data(parseInt(event.target.value), this.state.max_messages);
};
send_data = (level: number, max_messages: number) => {
redirectingAuthorizedFetch(LOG_SETTINGS_ENDPOINT, {
method: 'POST',
body: JSON.stringify({
level: level,
max_messages: max_messages
}),
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => {
if (response.status !== 200) {
throw Error('Unexpected response code: ' + response.status);
}
})
.catch((error) => {
this.props.enqueueSnackbar(
error.message || 'Problem applying log settings',
{ variant: 'warning' }
);
});
};
levelLabel = (level: LogLevel) => {
switch (level) {
case LogLevel.ERROR:
return 'E';
case LogLevel.WARNING:
return 'W';
case LogLevel.NOTICE:
return 'N';
case LogLevel.INFO:
return 'I';
case LogLevel.DEBUG:
return 'D';
case LogLevel.TRACE:
return 'TRACE';
default:
return '';
}
};
onDownload = () => {
const { events, level } = this.state;
let result = '';
for (const i in events) {
if (events[i].l <= level) {
result +=
events[i].t +
' ' +
this.levelLabel(events[i].l) +
' ' +
events[i].i +
': [' +
events[i].n +
'] ' +
events[i].m +
'\n';
}
}
const a = document.createElement('a');
a.setAttribute(
'href',
'data:text/plain;charset=utf-8,' + encodeURIComponent(result)
);
a.setAttribute('download', 'log.txt');
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
};
render() { render() {
const { saveData } = this.props;
return ( return (
<SectionContent title="System Log" id="log-window"> <SectionContent title="System Log" id="log-window">
<RestFormLoader <ValidatorForm onSubmit={saveData}>
{...this.props} <Grid
render={(formProps) => <LogEventForm {...formProps} />} container
spacing={3}
direction="row"
justify="flex-start"
alignItems="center"
>
<Grid item xs={2}>
<SelectValidator
name="level"
label="Log Level"
value={this.state.level}
fullWidth
variant="outlined"
onChange={this.changeLevel}
margin="normal"
>
<MenuItem value={3}>ERROR</MenuItem>
<MenuItem value={4}>WARNING</MenuItem>
<MenuItem value={5}>NOTICE</MenuItem>
<MenuItem value={6}>INFO</MenuItem>
<MenuItem value={7}>DEBUG</MenuItem>
<MenuItem value={8}>ALL</MenuItem>
</SelectValidator>
</Grid>
<Grid item xs={2}>
<FormLabel>Buffer size</FormLabel>
<Slider
value={this.state.max_messages}
valueLabelDisplay="auto"
name="max_messages"
marks={[
{ value: 25, label: '25' },
{ value: 50, label: '50' },
{ value: 75, label: '75' }
]}
step={25}
min={25}
max={75}
onChange={this.changeMaxMessages}
/>
</Grid>
<Grid item xs={4}>
<BlockFormControlLabel
control={
<Checkbox
checked={this.state.compact}
onChange={this.changeCompact}
value="compact"
/>
}
label="Compact Layout"
/>
</Grid>
<Grid item md>
<Button
startIcon={<DownloadIcon />}
variant="contained"
color="primary"
onClick={this.onDownload}
>
Download
</Button>
</Grid>
</Grid>
</ValidatorForm>
<LogEventConsole
level={this.state.level}
compact={this.state.compact}
events={this.state.events}
/> />
<LogEventConsole events={this.state.events} />
</SectionContent> </SectionContent>
); );
} }

View File

@@ -1,107 +0,0 @@
import { Component } from 'react';
import {
ValidatorForm,
SelectValidator
} from 'react-material-ui-form-validator';
import { Typography, Grid } from '@material-ui/core';
import MenuItem from '@material-ui/core/MenuItem';
import {
redirectingAuthorizedFetch,
withAuthenticatedContext,
AuthenticatedContextProps
} from '../authentication';
import { RestFormProps } from '../components';
import { LogSettings } from './types';
import { ENDPOINT_ROOT } from '../api';
export const LOG_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'logSettings';
type LogEventFormProps = AuthenticatedContextProps & RestFormProps<LogSettings>;
class LogEventForm extends Component<LogEventFormProps> {
changeLevel = (event: React.ChangeEvent<HTMLSelectElement>) => {
const { data, setData } = this.props;
setData({
...data,
level: parseInt(event.target.value)
});
redirectingAuthorizedFetch(LOG_SETTINGS_ENDPOINT, {
method: 'POST',
body: JSON.stringify({ level: event.target.value }),
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => {
if (response.status === 200) {
return response.json();
}
throw Error('Unexpected response code: ' + response.status);
})
.then((json) => {
this.props.enqueueSnackbar('Log settings changed', {
variant: 'success'
});
setData({
...data,
level: json.level
});
})
.catch((error) => {
this.props.enqueueSnackbar(
error.message || 'Problem changing log settings',
{ variant: 'warning' }
);
});
};
render() {
const { data, saveData } = this.props;
return (
<ValidatorForm onSubmit={saveData}>
<Grid
container
spacing={0}
direction="row"
justify="flex-start"
alignItems="center"
>
<Grid item xs={2}>
<SelectValidator
name="level"
label="Log Level"
value={data.level}
variant="outlined"
onChange={this.changeLevel}
margin="normal"
>
<MenuItem value={-1}>OFF</MenuItem>
<MenuItem value={3}>ERROR</MenuItem>
<MenuItem value={4}>WARNING</MenuItem>
<MenuItem value={5}>NOTICE</MenuItem>
<MenuItem value={6}>INFO</MenuItem>
<MenuItem value={7}>DEBUG</MenuItem>
<MenuItem value={8}>ALL</MenuItem>
</SelectValidator>
</Grid>
<Grid item md>
<Typography color="primary" variant="body2">
<i>
(the last {data.max_messages} messages are buffered and new log
events are shown in real time)
</i>
</Typography>
</Grid>
</Grid>
</ValidatorForm>
);
}
}
export default withAuthenticatedContext(LogEventForm);

View File

@@ -50,6 +50,7 @@ export enum LogLevel {
export interface LogEvent { export interface LogEvent {
t: string; t: string;
l: LogLevel; l: LogLevel;
i: number;
n: string; n: string;
m: string; m: string;
} }

View File

@@ -3,3 +3,4 @@ export { default as isIP } from './isIP';
export { default as optional } from './optional'; export { default as optional } from './optional';
export { default as or } from './or'; export { default as or } from './or';
export { default as isPath } from './isPath'; export { default as isPath } from './isPath';
export { default as isIPv4 } from './isIPv4';

View File

@@ -1,4 +1,4 @@
const ipAddressRegexp = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; const ipAddressRegexp = /((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))/;
export default function isIp(ipAddress: string) { export default function isIp(ipAddress: string) {
return ipAddressRegexp.test(ipAddress); return ipAddressRegexp.test(ipAddress);

View File

@@ -0,0 +1,5 @@
const ipv4AddressRegexp = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
export default function isIpv4(ipAddress: string) {
return ipv4AddressRegexp.test(ipAddress);
}

View File

@@ -1,6 +1,31 @@
ArduinoJson: change log ArduinoJson: change log
======================= =======================
v6.18.3 (2021-07-27)
-------
* Changed return type of `convertToJson()` and `Converter<T>::toJson()` to `void`
* Added `as<std::string_view>()` and `is<std::string_view>()`
v6.18.2 (2021-07-19)
-------
* Removed a symlink because the Arduino Library Specification forbids it
v6.18.1 (2021-07-03)
-------
* Fixed support for `volatile float` and `volatile double` (issue #1557)
* Fixed error `[Pe070]: incomplete type is not allowed` on IAR (issue #1560)
* Fixed `serializeJson(doc, String)` when allocation fails (issue #1572)
* Fixed clang-tidy warnings (issue #1574, PR #1577 by @armandas)
* Added fake class `InvalidConversion<T1,T2>` to easily identify invalid conversions (issue #1585)
* Added support for `std::string_view` (issue #1578, PR #1554 by @0xFEEDC0DE64)
* Fixed warning `definition of implicit copy constructor for 'MsgPackDeserializer' is deprecated because it has a user-declared copy assignment operator`
* Added `JsonArray::clear()` (issue #1597)
* Fixed `JsonVariant::as<unsigned>()` (issue #1601)
* Added support for ESP-IDF component build (PR #1562 by @qt1, PR #1599 by @andreaskuster)
v6.18.0 (2021-05-05) v6.18.0 (2021-05-05)
------- -------

View File

@@ -2,7 +2,7 @@
--- ---
[![arduino-library-badge](https://www.ardu-badge.com/badge/ArduinoJson.svg?version=6.18.0)](https://www.ardu-badge.com/ArduinoJson/6.18.0) [![arduino-library-badge](https://www.ardu-badge.com/badge/ArduinoJson.svg?version=6.18.3)](https://www.ardu-badge.com/ArduinoJson/6.18.3)
[![Continuous Integration](https://github.com/bblanchon/ArduinoJson/workflows/Continuous%20Integration/badge.svg?branch=6.x)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x) [![Continuous Integration](https://github.com/bblanchon/ArduinoJson/workflows/Continuous%20Integration/badge.svg?branch=6.x)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x)
[![Continuous Integration](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x) [![Continuous Integration](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
@@ -33,15 +33,15 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
* [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/?utm_source=github&utm_medium=readme) * [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/?utm_source=github&utm_medium=readme)
* Deduplicates strings * Deduplicates strings
* Versatile * Versatile
* [Supports custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/?utm_source=github&utm_medium=readme) * Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/?utm_source=github&utm_medium=readme)
* Supports [Arduino's `String`](https://arduinojson.org/v6/api/config/enable_arduino_string/?utm_source=github&utm_medium=readme) and [STL's `std::string`](https://arduinojson.org/v6/api/config/enable_std_string/?utm_source=github&utm_medium=readme) * Supports [`String`](https://arduinojson.org/v6/api/config/enable_arduino_string/?utm_source=github&utm_medium=readme), [`std::string`](https://arduinojson.org/v6/api/config/enable_std_string/?utm_source=github&utm_medium=readme) and [`std::string_view`](https://arduinojson.org/v6/api/config/enable_string_view/?utm_source=github&utm_medium=readme)
* Supports [Arduino's `Stream`](https://arduinojson.org/v6/api/config/enable_arduino_stream/?utm_source=github&utm_medium=readme) and [STL's `std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/?utm_source=github&utm_medium=readme) * Supports [`Stream`](https://arduinojson.org/v6/api/config/enable_arduino_stream/?utm_source=github&utm_medium=readme) and [`std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/?utm_source=github&utm_medium=readme)
* [Supports Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/?utm_source=github&utm_medium=readme) * Supports [Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/?utm_source=github&utm_medium=readme)
* Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/?utm_source=github&utm_medium=readme#custom-writer) * Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/?utm_source=github&utm_medium=readme#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/?utm_source=github&utm_medium=readme#custom-writer)
* Supports custom converters * Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/?utm_source=github&utm_medium=readme)
* Portable * Portable
* Usable on any C++ project (not limited to Arduino) * Usable on any C++ project (not limited to Arduino)
* Compatible with C++98 * Compatible with C++98, C++11, C++14 and C++17
* Zero warnings with `-Wall -Wextra -pedantic` and `/W4` * Zero warnings with `-Wall -Wextra -pedantic` and `/W4`
* [Header-only library](https://en.wikipedia.org/wiki/Header-only) * [Header-only library](https://en.wikipedia.org/wiki/Header-only)
* Works with virtually any board * Works with virtually any board
@@ -81,15 +81,17 @@ ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
* [GCC 4.4, 4.6, 4.7, 4.8, 4.9, 5, 6, 7, 8, 9, 10](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22) * [GCC 4.4, 4.6, 4.7, 4.8, 4.9, 5, 6, 7, 8, 9, 10](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
* [Clang 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 5.0, 6.0, 7, 8, 9, 10](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22) * [Clang 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 5.0, 6.0, 7, 8, 9, 10](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
* [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson) * [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
* Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/)
* Well documented * Well documented
* [Tutorials](https://arduinojson.org/v6/doc/deserialization/?utm_source=github&utm_medium=readme) * [Tutorials](https://arduinojson.org/v6/doc/deserialization/?utm_source=github&utm_medium=readme)
* [Examples](https://arduinojson.org/v6/example/?utm_source=github&utm_medium=readme) * [Examples](https://arduinojson.org/v6/example/?utm_source=github&utm_medium=readme)
* [How-tos](https://arduinojson.org/v6/example/?utm_source=github&utm_medium=readme) * [How-tos](https://arduinojson.org/v6/example/?utm_source=github&utm_medium=readme)
* [FAQ](https://arduinojson.org/v6/faq/?utm_source=github&utm_medium=readme) * [FAQ](https://arduinojson.org/v6/faq/?utm_source=github&utm_medium=readme)
* [Troubleshooter](https://arduinojson.org/v6/troubleshooter/?utm_source=github&utm_medium=readme)
* [Book](https://arduinojson.org/book/?utm_source=github&utm_medium=readme) * [Book](https://arduinojson.org/book/?utm_source=github&utm_medium=readme)
* [Changelog](CHANGELOG.md) * [Changelog](CHANGELOG.md)
* Vibrant user community * Vibrant user community
* Most popular of all Arduino libraries on [GitHub](https://github.com/search?o=desc&q=arduino+library&s=stars&type=Repositories) and [PlatformIO](https://platformio.org/lib/search) * Most popular of all Arduino libraries on [GitHub](https://github.com/search?o=desc&q=arduino+library&s=stars&type=Repositories)
* [Used in hundreds of projects](https://www.hackster.io/search?i=projects&q=arduinojson) * [Used in hundreds of projects](https://www.hackster.io/search?i=projects&q=arduinojson)
* [Responsive support](https://github.com/bblanchon/ArduinoJson/issues?q=is%3Aissue+is%3Aclosed) * [Responsive support](https://github.com/bblanchon/ArduinoJson/issues?q=is%3Aissue+is%3Aclosed)
@@ -132,9 +134,11 @@ serializeJson(doc, Serial);
See the [tutorial on arduinojson.org](https://arduinojson.org/doc/encoding/?utm_source=github&utm_medium=readme) See the [tutorial on arduinojson.org](https://arduinojson.org/doc/encoding/?utm_source=github&utm_medium=readme)
## Support the project ## Support the project ❤️
Do you like this library? Please [star this project on GitHub](https://github.com/bblanchon/ArduinoJson/stargazers)! Do you like this library?
Please [star this project on GitHub](https://github.com/bblanchon/ArduinoJson/stargazers)!
What? You don't like it but you *love* it? What? You don't like it but you *love* it?
We don't take donations anymore, but [we sell a book](https://arduinojson.org/book/?utm_source=github&utm_medium=readme), so you can help and learn at the same time. You can support the project by [purchasing my book](https://arduinojson.org/book/?utm_source=github&utm_medium=readme).
Alternatively, you can make a recurring donation via [GitHub Sponsors](https://github.com/sponsors/bblanchon).

View File

@@ -7,11 +7,11 @@
#include "ArduinoJson/Configuration.hpp" #include "ArduinoJson/Configuration.hpp"
#if !ARDUINOJSON_DEBUG #if !ARDUINOJSON_DEBUG
#ifdef __clang__ # ifdef __clang__
#pragma clang system_header # pragma clang system_header
#elif defined __GNUC__ # elif defined __GNUC__
#pragma GCC system_header # pragma GCC system_header
#endif # endif
#endif #endif
#include "ArduinoJson/Array/ArrayRef.hpp" #include "ArduinoJson/Array/ArrayRef.hpp"

View File

@@ -161,14 +161,20 @@ class ArrayRef : public ArrayRefBase<CollectionData>,
_data->removeElement(index); _data->removeElement(index);
} }
void clear() const {
if (!_data)
return;
_data->clear();
}
private: private:
MemoryPool* _pool; MemoryPool* _pool;
}; };
template <> template <>
struct Converter<ArrayConstRef> { struct Converter<ArrayConstRef> {
static bool toJson(VariantConstRef src, VariantRef dst) { static void toJson(VariantConstRef src, VariantRef dst) {
return variantCopyFrom(getData(dst), getData(src), getPool(dst)); variantCopyFrom(getData(dst), getData(src), getPool(dst));
} }
static ArrayConstRef fromJson(VariantConstRef src) { static ArrayConstRef fromJson(VariantConstRef src) {
@@ -183,8 +189,8 @@ struct Converter<ArrayConstRef> {
template <> template <>
struct Converter<ArrayRef> { struct Converter<ArrayRef> {
static bool toJson(VariantConstRef src, VariantRef dst) { static void toJson(VariantConstRef src, VariantRef dst) {
return variantCopyFrom(getData(dst), getData(src), getPool(dst)); variantCopyFrom(getData(dst), getData(src), getPool(dst));
} }
static ArrayRef fromJson(VariantRef src) { static ArrayRef fromJson(VariantRef src) {
@@ -193,6 +199,8 @@ struct Converter<ArrayRef> {
return ArrayRef(pool, data != 0 ? data->asArray() : 0); return ArrayRef(pool, data != 0 ? data->asArray() : 0);
} }
static InvalidConversion<VariantConstRef, ArrayRef> fromJson(VariantConstRef);
static bool checkJson(VariantConstRef) { static bool checkJson(VariantConstRef) {
return false; return false;
} }

View File

@@ -10,8 +10,8 @@
#include <ArduinoJson/Variant/VariantTo.hpp> #include <ArduinoJson/Variant/VariantTo.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) # pragma warning(push)
#pragma warning(disable : 4522) # pragma warning(disable : 4522)
#endif #endif
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@@ -178,8 +178,8 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
return _array.getOrAddElement(_index); return _array.getOrAddElement(_index);
} }
friend bool convertToJson(const this_type& src, VariantRef dst) { friend void convertToJson(const this_type& src, VariantRef dst) {
return dst.set(src.getUpstreamElement()); dst.set(src.getUpstreamElement());
} }
TArray _array; TArray _array;
@@ -189,5 +189,5 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) # pragma warning(pop)
#endif #endif

View File

@@ -62,9 +62,9 @@ inline bool CollectionData::copyFrom(const CollectionData& src,
VariantData* var; VariantData* var;
if (s->key() != 0) { if (s->key() != 0) {
if (s->ownsKey()) if (s->ownsKey())
var = addMember(RamStringAdapter(s->key()), pool); var = addMember(adaptString(const_cast<char*>(s->key())), pool);
else else
var = addMember(ConstRamStringAdapter(s->key()), pool); var = addMember(adaptString(s->key()), pool);
} else { } else {
var = addElement(pool); var = addElement(pool);
} }
@@ -107,7 +107,7 @@ template <typename TAdaptedString>
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const { inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
VariantSlot* slot = _head; VariantSlot* slot = _head;
while (slot) { while (slot) {
if (key.equals(slot->key())) if (key.compare(slot->key()) == 0)
break; break;
slot = slot->next(); slot = slot->next();
} }

View File

@@ -5,251 +5,269 @@
#pragma once #pragma once
#if __cplusplus >= 201103L #if __cplusplus >= 201103L
#define ARDUINOJSON_HAS_LONG_LONG 1 # define ARDUINOJSON_HAS_LONG_LONG 1
#define ARDUINOJSON_HAS_NULLPTR 1 # define ARDUINOJSON_HAS_RVALUE_REFERENCES 1
#define ARDUINOJSON_HAS_RVALUE_REFERENCES 1
#else #else
#define ARDUINOJSON_HAS_LONG_LONG 0 # define ARDUINOJSON_HAS_LONG_LONG 0
#define ARDUINOJSON_HAS_NULLPTR 0 # define ARDUINOJSON_HAS_RVALUE_REFERENCES 0
#define ARDUINOJSON_HAS_RVALUE_REFERENCES 0 #endif
#ifndef ARDUINOJSON_HAS_NULLPTR
# if __cplusplus >= 201103L
# define ARDUINOJSON_HAS_NULLPTR 1
# else
# define ARDUINOJSON_HAS_NULLPTR 0
# endif
#endif #endif
#if defined(_MSC_VER) && !ARDUINOJSON_HAS_LONG_LONG #if defined(_MSC_VER) && !ARDUINOJSON_HAS_LONG_LONG
#define ARDUINOJSON_HAS_INT64 1 # define ARDUINOJSON_HAS_INT64 1
#else #else
#define ARDUINOJSON_HAS_INT64 0 # define ARDUINOJSON_HAS_INT64 0
#endif #endif
// Small or big machine? // Small or big machine?
#ifndef ARDUINOJSON_EMBEDDED_MODE #ifndef ARDUINOJSON_EMBEDDED_MODE
#if defined(ARDUINO) /* Arduino*/ \ # if defined(ARDUINO) /* Arduino*/ \
|| defined(__IAR_SYSTEMS_ICC__) /* IAR Embedded Workbench */ \ || defined(__IAR_SYSTEMS_ICC__) /* IAR Embedded Workbench */ \
|| defined(__XC) /* MPLAB XC compiler */ \ || defined(__XC) /* MPLAB XC compiler */ \
|| defined(__ARMCC_VERSION) /* Keil ARM Compiler */ \ || defined(__ARMCC_VERSION) /* Keil ARM Compiler */ \
|| defined(__AVR) /* Atmel AVR8/GNU C Compiler */ || defined(__AVR) /* Atmel AVR8/GNU C Compiler */
#define ARDUINOJSON_EMBEDDED_MODE 1 # define ARDUINOJSON_EMBEDDED_MODE 1
#else # else
#define ARDUINOJSON_EMBEDDED_MODE 0 # define ARDUINOJSON_EMBEDDED_MODE 0
#endif # endif
#endif #endif
// Auto enable std::stream if the right headers are here and no conflicting // Auto enable std::stream if the right headers are here and no conflicting
// macro is defined // macro is defined
#if !defined(ARDUINOJSON_ENABLE_STD_STREAM) && defined(__has_include) #if !defined(ARDUINOJSON_ENABLE_STD_STREAM) && defined(__has_include)
#if __has_include(<istream>) && \ # if __has_include(<istream>) && \
__has_include(<ostream>) && \ __has_include(<ostream>) && \
!defined(min) && \ !defined(min) && \
!defined(max) !defined(max)
#define ARDUINOJSON_ENABLE_STD_STREAM 1 # define ARDUINOJSON_ENABLE_STD_STREAM 1
#else # else
#define ARDUINOJSON_ENABLE_STD_STREAM 0 # define ARDUINOJSON_ENABLE_STD_STREAM 0
#endif # endif
#endif #endif
// Auto enable std::string if the right header is here and no conflicting // Auto enable std::string if the right header is here and no conflicting
// macro is defined // macro is defined
#if !defined(ARDUINOJSON_ENABLE_STD_STRING) && defined(__has_include) #if !defined(ARDUINOJSON_ENABLE_STD_STRING) && defined(__has_include)
#if __has_include(<string>) && !defined(min) && !defined(max) # if __has_include(<string>) && !defined(min) && !defined(max)
#define ARDUINOJSON_ENABLE_STD_STRING 1 # define ARDUINOJSON_ENABLE_STD_STRING 1
#else # else
#define ARDUINOJSON_ENABLE_STD_STRING 0 # define ARDUINOJSON_ENABLE_STD_STRING 0
# endif
#endif #endif
#ifndef ARDUINOJSON_ENABLE_STRING_VIEW
# ifdef __has_include
# if __has_include(<string_view>) && __cplusplus >= 201703L
# define ARDUINOJSON_ENABLE_STRING_VIEW 1
# endif
# endif
#endif
#ifndef ARDUINOJSON_ENABLE_STRING_VIEW
# define ARDUINOJSON_ENABLE_STRING_VIEW 0
#endif #endif
#if ARDUINOJSON_EMBEDDED_MODE #if ARDUINOJSON_EMBEDDED_MODE
// Store floats by default to reduce the memory usage (issue #134) // Store floats by default to reduce the memory usage (issue #134)
#ifndef ARDUINOJSON_USE_DOUBLE # ifndef ARDUINOJSON_USE_DOUBLE
#define ARDUINOJSON_USE_DOUBLE 0 # define ARDUINOJSON_USE_DOUBLE 0
#endif # endif
// Store longs by default, because they usually match the size of a float. // Store longs by default, because they usually match the size of a float.
#ifndef ARDUINOJSON_USE_LONG_LONG # ifndef ARDUINOJSON_USE_LONG_LONG
#define ARDUINOJSON_USE_LONG_LONG 0 # define ARDUINOJSON_USE_LONG_LONG 0
#endif # endif
// Embedded systems usually don't have std::string // Embedded systems usually don't have std::string
#ifndef ARDUINOJSON_ENABLE_STD_STRING # ifndef ARDUINOJSON_ENABLE_STD_STRING
#define ARDUINOJSON_ENABLE_STD_STRING 0 # define ARDUINOJSON_ENABLE_STD_STRING 0
#endif # endif
// Embedded systems usually don't have std::stream // Embedded systems usually don't have std::stream
#ifndef ARDUINOJSON_ENABLE_STD_STREAM # ifndef ARDUINOJSON_ENABLE_STD_STREAM
#define ARDUINOJSON_ENABLE_STD_STREAM 0 # define ARDUINOJSON_ENABLE_STD_STREAM 0
#endif # endif
// Limit nesting as the stack is likely to be small // Limit nesting as the stack is likely to be small
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT # ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10 # define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
#endif # endif
// Number of bits to store the pointer to next node // Number of bits to store the pointer to next node
// (saves RAM but limits the number of values in a document) // (saves RAM but limits the number of values in a document)
#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE # ifndef ARDUINOJSON_SLOT_OFFSET_SIZE
#if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 2 # if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 2
// Address space == 16-bit => max 127 values // Address space == 16-bit => max 127 values
#define ARDUINOJSON_SLOT_OFFSET_SIZE 1 # define ARDUINOJSON_SLOT_OFFSET_SIZE 1
#else # else
// Address space > 16-bit => max 32767 values // Address space > 16-bit => max 32767 values
#define ARDUINOJSON_SLOT_OFFSET_SIZE 2 # define ARDUINOJSON_SLOT_OFFSET_SIZE 2
#endif # endif
#endif # endif
#else // ARDUINOJSON_EMBEDDED_MODE #else // ARDUINOJSON_EMBEDDED_MODE
// On a computer we have plenty of memory so we can use doubles // On a computer we have plenty of memory so we can use doubles
#ifndef ARDUINOJSON_USE_DOUBLE # ifndef ARDUINOJSON_USE_DOUBLE
#define ARDUINOJSON_USE_DOUBLE 1 # define ARDUINOJSON_USE_DOUBLE 1
#endif # endif
// Use long long when available // Use long long when available
#ifndef ARDUINOJSON_USE_LONG_LONG # ifndef ARDUINOJSON_USE_LONG_LONG
#if ARDUINOJSON_HAS_LONG_LONG || ARDUINOJSON_HAS_INT64 # if ARDUINOJSON_HAS_LONG_LONG || ARDUINOJSON_HAS_INT64
#define ARDUINOJSON_USE_LONG_LONG 1 # define ARDUINOJSON_USE_LONG_LONG 1
#else # else
#define ARDUINOJSON_USE_LONG_LONG 0 # define ARDUINOJSON_USE_LONG_LONG 0
#endif # endif
#endif # endif
// On a computer, we can use std::string // On a computer, we can use std::string
#ifndef ARDUINOJSON_ENABLE_STD_STRING # ifndef ARDUINOJSON_ENABLE_STD_STRING
#define ARDUINOJSON_ENABLE_STD_STRING 1 # define ARDUINOJSON_ENABLE_STD_STRING 1
#endif # endif
// On a computer, we can assume std::stream // On a computer, we can assume std::stream
#ifndef ARDUINOJSON_ENABLE_STD_STREAM # ifndef ARDUINOJSON_ENABLE_STD_STREAM
#define ARDUINOJSON_ENABLE_STD_STREAM 1 # define ARDUINOJSON_ENABLE_STD_STREAM 1
#endif # endif
// On a computer, the stack is large so we can increase nesting limit // On a computer, the stack is large so we can increase nesting limit
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT # ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50 # define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50
#endif # endif
// Number of bits to store the pointer to next node // Number of bits to store the pointer to next node
#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE # ifndef ARDUINOJSON_SLOT_OFFSET_SIZE
#define ARDUINOJSON_SLOT_OFFSET_SIZE 4 # define ARDUINOJSON_SLOT_OFFSET_SIZE 4
#endif # endif
#endif // ARDUINOJSON_EMBEDDED_MODE #endif // ARDUINOJSON_EMBEDDED_MODE
#ifdef ARDUINO #ifdef ARDUINO
#include <Arduino.h> # include <Arduino.h>
// Enable support for Arduino's String class // Enable support for Arduino's String class
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING # ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 # define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
#endif # endif
// Enable support for Arduino's Stream class // Enable support for Arduino's Stream class
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM # ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1 # define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
#endif # endif
// Enable support for Arduino's Print class // Enable support for Arduino's Print class
#ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT # ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT
#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1 # define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1
#endif # endif
#else // ARDUINO #else // ARDUINO
// Disable support for Arduino's String class // Disable support for Arduino's String class
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING # ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 # define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
#endif # endif
// Disable support for Arduino's Stream class // Disable support for Arduino's Stream class
#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM # ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0 # define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
#endif # endif
// Disable support for Arduino's Print class // Disable support for Arduino's Print class
#ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT # ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT
#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0 # define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0
#endif # endif
#endif // ARDUINO #endif // ARDUINO
#ifndef ARDUINOJSON_ENABLE_PROGMEM #ifndef ARDUINOJSON_ENABLE_PROGMEM
#if defined(PROGMEM) && defined(pgm_read_byte) && defined(pgm_read_dword) && \ # if defined(PROGMEM) && defined(pgm_read_byte) && defined(pgm_read_dword) && \
defined(pgm_read_ptr) && defined(pgm_read_float) defined(pgm_read_ptr) && defined(pgm_read_float)
#define ARDUINOJSON_ENABLE_PROGMEM 1 # define ARDUINOJSON_ENABLE_PROGMEM 1
#else # else
#define ARDUINOJSON_ENABLE_PROGMEM 0 # define ARDUINOJSON_ENABLE_PROGMEM 0
#endif # endif
#endif #endif
// Convert unicode escape sequence (\u0123) to UTF-8 // Convert unicode escape sequence (\u0123) to UTF-8
#ifndef ARDUINOJSON_DECODE_UNICODE #ifndef ARDUINOJSON_DECODE_UNICODE
#define ARDUINOJSON_DECODE_UNICODE 1 # define ARDUINOJSON_DECODE_UNICODE 1
#endif #endif
// Ignore comments in input // Ignore comments in input
#ifndef ARDUINOJSON_ENABLE_COMMENTS #ifndef ARDUINOJSON_ENABLE_COMMENTS
#define ARDUINOJSON_ENABLE_COMMENTS 0 # define ARDUINOJSON_ENABLE_COMMENTS 0
#endif #endif
// Support NaN in JSON // Support NaN in JSON
#ifndef ARDUINOJSON_ENABLE_NAN #ifndef ARDUINOJSON_ENABLE_NAN
#define ARDUINOJSON_ENABLE_NAN 0 # define ARDUINOJSON_ENABLE_NAN 0
#endif #endif
// Support Infinity in JSON // Support Infinity in JSON
#ifndef ARDUINOJSON_ENABLE_INFINITY #ifndef ARDUINOJSON_ENABLE_INFINITY
#define ARDUINOJSON_ENABLE_INFINITY 0 # define ARDUINOJSON_ENABLE_INFINITY 0
#endif #endif
// Control the exponentiation threshold for big numbers // Control the exponentiation threshold for big numbers
// CAUTION: cannot be more that 1e9 !!!! // CAUTION: cannot be more that 1e9 !!!!
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD #ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
#define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7 # define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
#endif #endif
// Control the exponentiation threshold for small numbers // Control the exponentiation threshold for small numbers
#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD #ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
#define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5 # define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
#endif #endif
#ifndef ARDUINOJSON_LITTLE_ENDIAN #ifndef ARDUINOJSON_LITTLE_ENDIAN
#if defined(_MSC_VER) || \ # if defined(_MSC_VER) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ (defined(__BYTE_ORDER__) && \
defined(__LITTLE_ENDIAN__) || defined(__i386) || defined(__x86_64) __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
#define ARDUINOJSON_LITTLE_ENDIAN 1 defined(__LITTLE_ENDIAN__) || defined(__i386) || defined(__x86_64)
#else # define ARDUINOJSON_LITTLE_ENDIAN 1
#define ARDUINOJSON_LITTLE_ENDIAN 0 # else
#endif # define ARDUINOJSON_LITTLE_ENDIAN 0
# endif
#endif #endif
#ifndef ARDUINOJSON_ENABLE_ALIGNMENT #ifndef ARDUINOJSON_ENABLE_ALIGNMENT
#if defined(__AVR) # if defined(__AVR)
#define ARDUINOJSON_ENABLE_ALIGNMENT 0 # define ARDUINOJSON_ENABLE_ALIGNMENT 0
#else # else
#define ARDUINOJSON_ENABLE_ALIGNMENT 1 # define ARDUINOJSON_ENABLE_ALIGNMENT 1
#endif # endif
#endif #endif
#ifndef ARDUINOJSON_TAB #ifndef ARDUINOJSON_TAB
#define ARDUINOJSON_TAB " " # define ARDUINOJSON_TAB " "
#endif #endif
#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION #ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
#define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1 # define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1
#endif #endif
#ifndef ARDUINOJSON_STRING_BUFFER_SIZE #ifndef ARDUINOJSON_STRING_BUFFER_SIZE
#define ARDUINOJSON_STRING_BUFFER_SIZE 32 # define ARDUINOJSON_STRING_BUFFER_SIZE 32
#endif #endif
#ifndef ARDUINOJSON_DEBUG #ifndef ARDUINOJSON_DEBUG
#ifdef __PLATFORMIO_BUILD_DEBUG__ # ifdef __PLATFORMIO_BUILD_DEBUG__
#define ARDUINOJSON_DEBUG 1 # define ARDUINOJSON_DEBUG 1
#else # else
#define ARDUINOJSON_DEBUG 0 # define ARDUINOJSON_DEBUG 0
#endif # endif
#endif #endif
#if ARDUINOJSON_HAS_NULLPTR && defined(nullptr) #if ARDUINOJSON_HAS_NULLPTR && defined(nullptr)
#error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr # error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr
// See https://github.com/bblanchon/ArduinoJson/issues/1355 // See https://github.com/bblanchon/ArduinoJson/issues/1355
#endif #endif

View File

@@ -9,7 +9,7 @@
#include <ArduinoJson/Polyfills/static_array.hpp> #include <ArduinoJson/Polyfills/static_array.hpp>
#if ARDUINOJSON_ENABLE_STD_STREAM #if ARDUINOJSON_ENABLE_STD_STREAM
#include <ostream> # include <ostream>
#endif #endif
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {

View File

@@ -40,17 +40,17 @@ struct BoundedReader {
#include <ArduinoJson/Deserialization/Readers/VariantReader.hpp> #include <ArduinoJson/Deserialization/Readers/VariantReader.hpp>
#if ARDUINOJSON_ENABLE_ARDUINO_STREAM #if ARDUINOJSON_ENABLE_ARDUINO_STREAM
#include <ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp> # include <ArduinoJson/Deserialization/Readers/ArduinoStreamReader.hpp>
#endif #endif
#if ARDUINOJSON_ENABLE_ARDUINO_STRING #if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp> # include <ArduinoJson/Deserialization/Readers/ArduinoStringReader.hpp>
#endif #endif
#if ARDUINOJSON_ENABLE_PROGMEM #if ARDUINOJSON_ENABLE_PROGMEM
#include <ArduinoJson/Deserialization/Readers/FlashReader.hpp> # include <ArduinoJson/Deserialization/Readers/FlashReader.hpp>
#endif #endif
#if ARDUINOJSON_ENABLE_STD_STREAM #if ARDUINOJSON_ENABLE_STD_STREAM
#include <ArduinoJson/Deserialization/Readers/StdStreamReader.hpp> # include <ArduinoJson/Deserialization/Readers/StdStreamReader.hpp>
#endif #endif

View File

@@ -32,7 +32,7 @@ class JsonDocument : public Visitable {
void clear() { void clear() {
_pool.clear(); _pool.clear();
_data.setNull(); _data.init();
} }
template <typename T> template <typename T>
@@ -304,15 +304,15 @@ class JsonDocument : public Visitable {
protected: protected:
JsonDocument() : _pool(0, 0) { JsonDocument() : _pool(0, 0) {
_data.setNull(); _data.init();
} }
JsonDocument(MemoryPool pool) : _pool(pool) { JsonDocument(MemoryPool pool) : _pool(pool) {
_data.setNull(); _data.init();
} }
JsonDocument(char* buf, size_t capa) : _pool(buf, capa) { JsonDocument(char* buf, size_t capa) : _pool(buf, capa) {
_data.setNull(); _data.init();
} }
~JsonDocument() {} ~JsonDocument() {}
@@ -337,8 +337,8 @@ class JsonDocument : public Visitable {
JsonDocument& operator=(const JsonDocument&); JsonDocument& operator=(const JsonDocument&);
}; };
inline bool convertToJson(const JsonDocument& src, VariantRef dst) { inline void convertToJson(const JsonDocument& src, VariantRef dst) {
return dst.set(src.as<VariantConstRef>()); dst.set(src.as<VariantConstRef>());
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -45,7 +45,8 @@ class Latch {
} }
TReader _reader; TReader _reader;
char _current; char _current; // NOLINT(clang-analyzer-optin.cplusplus.UninitializedObject)
// Not initialized in constructor (+10 bytes on AVR)
bool _loaded; bool _loaded;
#if ARDUINOJSON_DEBUG #if ARDUINOJSON_DEBUG
bool _ended; bool _ended;

View File

@@ -155,7 +155,6 @@ class TextFormatter {
protected: protected:
CountingDecorator<TWriter> _writer; CountingDecorator<TWriter> _writer;
size_t _length;
private: private:
TextFormatter &operator=(const TextFormatter &); // cannot be assigned TextFormatter &operator=(const TextFormatter &); // cannot be assigned

View File

@@ -12,10 +12,10 @@
// we choose to ignore the problem to reduce the size of the code // we choose to ignore the problem to reduce the size of the code
// Garbage in => Garbage out // Garbage in => Garbage out
#if defined(__GNUC__) #if defined(__GNUC__)
#if __GNUC__ >= 7 # if __GNUC__ >= 7
#pragma GCC diagnostic push # pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif # endif
#endif #endif
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@@ -31,7 +31,7 @@ inline bool isLowSurrogate(uint16_t codeunit) {
class Codepoint { class Codepoint {
public: public:
Codepoint() : _highSurrogate(0) {} Codepoint() : _highSurrogate(0), _codepoint(0) {}
bool append(uint16_t codeunit) { bool append(uint16_t codeunit) {
if (isHighSurrogate(codeunit)) { if (isHighSurrogate(codeunit)) {
@@ -61,7 +61,7 @@ class Codepoint {
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#if defined(__GNUC__) #if defined(__GNUC__)
#if __GNUC__ >= 8 # if __GNUC__ >= 8
#pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif # endif
#endif #endif

View File

@@ -7,6 +7,7 @@
#include <ArduinoJson/Memory/Alignment.hpp> #include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Polyfills/assert.hpp> #include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/mpl/max.hpp> #include <ArduinoJson/Polyfills/mpl/max.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantSlot.hpp> #include <ArduinoJson/Variant/VariantSlot.hpp>
#include <string.h> // memmove #include <string.h> // memmove
@@ -37,7 +38,8 @@ class MemoryPool {
} }
void* buffer() { void* buffer() {
return _begin; return _begin; // NOLINT(clang-analyzer-unix.Malloc)
// movePointers() alters this pointer
} }
// Gets the capacity of the memoryPool in bytes // Gets the capacity of the memoryPool in bytes
@@ -63,7 +65,7 @@ class MemoryPool {
return 0; return 0;
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
const char* existingCopy = findString(str.begin()); const char* existingCopy = findString(str);
if (existingCopy) if (existingCopy)
return existingCopy; return existingCopy;
#endif #endif
@@ -85,7 +87,7 @@ class MemoryPool {
const char* saveStringFromFreeZone(size_t len) { const char* saveStringFromFreeZone(size_t len) {
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
const char* dup = findString(_left); const char* dup = findString(adaptString(_left));
if (dup) if (dup)
return dup; return dup;
#endif #endif
@@ -162,16 +164,11 @@ class MemoryPool {
} }
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
template <typename TIterator> template <typename TAdaptedString>
const char* findString(TIterator str) { const char* findString(const TAdaptedString& str) {
for (char* next = _begin; next < _left; ++next) { for (char* next = _begin; next < _left; ++next) {
char* begin = next; if (str.compare(next) == 0)
return next;
// try to match
for (TIterator it = str; *it == *next; ++it) {
if (*next++ == 0)
return begin;
}
// jump to next terminator // jump to next terminator
while (*next) ++next; while (*next) ++next;

View File

@@ -10,17 +10,17 @@
#ifndef ARDUINOJSON_NAMESPACE #ifndef ARDUINOJSON_NAMESPACE
#define ARDUINOJSON_NAMESPACE \ # define ARDUINOJSON_NAMESPACE \
ARDUINOJSON_CONCAT4( \ ARDUINOJSON_CONCAT4( \
ARDUINOJSON_CONCAT4(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \ ARDUINOJSON_CONCAT4(ArduinoJson, ARDUINOJSON_VERSION_MAJOR, \
ARDUINOJSON_VERSION_MINOR, \ ARDUINOJSON_VERSION_MINOR, \
ARDUINOJSON_VERSION_REVISION), \ ARDUINOJSON_VERSION_REVISION), \
_, \ _, \
ARDUINOJSON_HEX_DIGIT(ARDUINOJSON_ENABLE_PROGMEM, \ ARDUINOJSON_HEX_DIGIT( \
ARDUINOJSON_USE_LONG_LONG, ARDUINOJSON_USE_DOUBLE, \ ARDUINOJSON_ENABLE_PROGMEM, ARDUINOJSON_USE_LONG_LONG, \
ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \ ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \
ARDUINOJSON_HEX_DIGIT( \ ARDUINOJSON_HEX_DIGIT( \
ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \ ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \
ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE)) ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE))
#endif #endif

View File

@@ -22,11 +22,11 @@ typedef unsigned long UInt;
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#if ARDUINOJSON_HAS_LONG_LONG && !ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_HAS_LONG_LONG && !ARDUINOJSON_USE_LONG_LONG
#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \ # define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) \
static_assert(sizeof(T) <= sizeof(ARDUINOJSON_NAMESPACE::Integer), \ static_assert(sizeof(T) <= sizeof(ARDUINOJSON_NAMESPACE::Integer), \
"To use 64-bit integers with ArduinoJson, you must set " \ "To use 64-bit integers with ArduinoJson, you must set " \
"ARDUINOJSON_USE_LONG_LONG to 1. See " \ "ARDUINOJSON_USE_LONG_LONG to 1. See " \
"https://arduinojson.org/v6/api/config/use_long_long/"); "https://arduinojson.org/v6/api/config/use_long_long/");
#else #else
#define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T) # define ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T)
#endif #endif

View File

@@ -5,13 +5,13 @@
#pragma once #pragma once
#if defined(__clang__) #if defined(__clang__)
#pragma clang diagnostic push # pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion" # pragma clang diagnostic ignored "-Wconversion"
#elif defined(__GNUC__) #elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic push # pragma GCC diagnostic push
#endif # endif
#pragma GCC diagnostic ignored "-Wconversion" # pragma GCC diagnostic ignored "-Wconversion"
#endif #endif
#include <ArduinoJson/Numbers/Float.hpp> #include <ArduinoJson/Numbers/Float.hpp>
@@ -71,9 +71,23 @@ canConvertNumber(TIn) {
} }
// int32 -> uint32 // int32 -> uint32
// int32 -> uint64
template <typename TOut, typename TIn> template <typename TOut, typename TIn>
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value && typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
is_integral<TOut>::value && is_unsigned<TOut>::value, is_integral<TOut>::value && is_unsigned<TOut>::value &&
sizeof(TOut) >= sizeof(TIn),
bool>::type
canConvertNumber(TIn value) {
if (value < 0)
return false;
return TOut(value) <= numeric_limits<TOut>::highest();
}
// int32 -> uint16
template <typename TOut, typename TIn>
typename enable_if<is_integral<TIn>::value && is_signed<TIn>::value &&
is_integral<TOut>::value && is_unsigned<TOut>::value &&
sizeof(TOut) < sizeof(TIn),
bool>::type bool>::type
canConvertNumber(TIn value) { canConvertNumber(TIn value) {
if (value < 0) if (value < 0)
@@ -99,9 +113,9 @@ TOut convertNumber(TIn value) {
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#if defined(__clang__) #if defined(__clang__)
#pragma clang diagnostic pop # pragma clang diagnostic pop
#elif defined(__GNUC__) #elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif # endif
#endif #endif

View File

@@ -12,8 +12,8 @@
#include <ArduinoJson/Variant/VariantTo.hpp> #include <ArduinoJson/Variant/VariantTo.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) # pragma warning(push)
#pragma warning(disable : 4522) # pragma warning(disable : 4522)
#endif #endif
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@@ -187,8 +187,8 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
return _object.getOrAddMember(_key); return _object.getOrAddMember(_key);
} }
friend bool convertToJson(const this_type &src, VariantRef dst) { friend void convertToJson(const this_type &src, VariantRef dst) {
return dst.set(src.getUpstreamMember()); dst.set(src.getUpstreamMember());
} }
TObject _object; TObject _object;
@@ -198,5 +198,5 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) # pragma warning(pop)
#endif #endif

View File

@@ -239,8 +239,8 @@ class ObjectRef : public ObjectRefBase<CollectionData>,
template <> template <>
struct Converter<ObjectConstRef> { struct Converter<ObjectConstRef> {
static bool toJson(VariantConstRef src, VariantRef dst) { static void toJson(VariantConstRef src, VariantRef dst) {
return variantCopyFrom(getData(dst), getData(src), getPool(dst)); variantCopyFrom(getData(dst), getData(src), getPool(dst));
} }
static ObjectConstRef fromJson(VariantConstRef src) { static ObjectConstRef fromJson(VariantConstRef src) {
@@ -255,8 +255,8 @@ struct Converter<ObjectConstRef> {
template <> template <>
struct Converter<ObjectRef> { struct Converter<ObjectRef> {
static bool toJson(VariantConstRef src, VariantRef dst) { static void toJson(VariantConstRef src, VariantRef dst) {
return variantCopyFrom(getData(dst), getData(src), getPool(dst)); variantCopyFrom(getData(dst), getData(src), getPool(dst));
} }
static ObjectRef fromJson(VariantRef src) { static ObjectRef fromJson(VariantRef src) {
@@ -265,6 +265,9 @@ struct Converter<ObjectRef> {
return ObjectRef(pool, data != 0 ? data->asObject() : 0); return ObjectRef(pool, data != 0 ? data->asObject() : 0);
} }
static InvalidConversion<VariantConstRef, ObjectRef> fromJson(
VariantConstRef);
static bool checkJson(VariantConstRef) { static bool checkJson(VariantConstRef) {
return false; return false;
} }

View File

@@ -7,8 +7,8 @@
#include <ArduinoJson/Configuration.hpp> #include <ArduinoJson/Configuration.hpp>
#if ARDUINOJSON_DEBUG #if ARDUINOJSON_DEBUG
#include <assert.h> # include <assert.h>
#define ARDUINOJSON_ASSERT(X) assert(X) # define ARDUINOJSON_ASSERT(X) assert(X)
#else #else
#define ARDUINOJSON_ASSERT(X) ((void)0) # define ARDUINOJSON_ASSERT(X) ((void)0)
#endif #endif

View File

@@ -6,49 +6,49 @@
#ifdef _MSC_VER // Visual Studio #ifdef _MSC_VER // Visual Studio
#define FORCE_INLINE // __forceinline causes C4714 when returning std::string # define FORCE_INLINE // __forceinline causes C4714 when returning std::string
#define NO_INLINE __declspec(noinline) # define NO_INLINE __declspec(noinline)
#ifndef ARDUINOJSON_DEPRECATED # ifndef ARDUINOJSON_DEPRECATED
#define ARDUINOJSON_DEPRECATED(msg) __declspec(deprecated(msg)) # define ARDUINOJSON_DEPRECATED(msg) __declspec(deprecated(msg))
#endif # endif
#elif defined(__GNUC__) // GCC or Clang #elif defined(__GNUC__) // GCC or Clang
#define FORCE_INLINE __attribute__((always_inline)) # define FORCE_INLINE __attribute__((always_inline))
#define NO_INLINE __attribute__((noinline)) # define NO_INLINE __attribute__((noinline))
#ifndef ARDUINOJSON_DEPRECATED # ifndef ARDUINOJSON_DEPRECATED
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
#define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated(msg))) # define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated(msg)))
#else # else
#define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated)) # define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated))
#endif # endif
#endif # endif
#else // Other compilers #else // Other compilers
#define FORCE_INLINE # define FORCE_INLINE
#define NO_INLINE # define NO_INLINE
#ifndef ARDUINOJSON_DEPRECATED # ifndef ARDUINOJSON_DEPRECATED
#define ARDUINOJSON_DEPRECATED(msg) # define ARDUINOJSON_DEPRECATED(msg)
#endif # endif
#endif #endif
#if __cplusplus >= 201103L #if __cplusplus >= 201103L
#define NOEXCEPT noexcept # define NOEXCEPT noexcept
#else #else
#define NOEXCEPT throw() # define NOEXCEPT throw()
#endif #endif
#if defined(__has_attribute) #if defined(__has_attribute)
#if __has_attribute(no_sanitize) # if __has_attribute(no_sanitize)
#define ARDUINOJSON_NO_SANITIZE(check) __attribute__((no_sanitize(check))) # define ARDUINOJSON_NO_SANITIZE(check) __attribute__((no_sanitize(check)))
# else
# define ARDUINOJSON_NO_SANITIZE(check)
# endif
#else #else
#define ARDUINOJSON_NO_SANITIZE(check) # define ARDUINOJSON_NO_SANITIZE(check)
#endif
#else
#define ARDUINOJSON_NO_SANITIZE(check)
#endif #endif

View File

@@ -7,8 +7,8 @@
#include "type_traits.hpp" #include "type_traits.hpp"
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) # pragma warning(push)
#pragma warning(disable : 4310) # pragma warning(disable : 4310)
#endif #endif
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@@ -41,5 +41,5 @@ struct numeric_limits<
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) # pragma warning(pop)
#endif #endif

View File

@@ -8,27 +8,27 @@
#if ARDUINOJSON_ENABLE_PROGMEM #if ARDUINOJSON_ENABLE_PROGMEM
#include <ArduinoJson/Polyfills/pgmspace_generic.hpp> # include <ArduinoJson/Polyfills/pgmspace_generic.hpp>
#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY # ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY
#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ # define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \
static type const name[] PROGMEM = value; static type const name[] PROGMEM = value;
#endif # endif
#ifndef ARDUINOJSON_READ_STATIC_ARRAY # ifndef ARDUINOJSON_READ_STATIC_ARRAY
#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) \ # define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) \
pgm_read<type>(name + index) pgm_read<type>(name + index)
#endif # endif
#else // i.e. ARDUINOJSON_ENABLE_PROGMEM == 0 #else // i.e. ARDUINOJSON_ENABLE_PROGMEM == 0
#ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY # ifndef ARDUINOJSON_DEFINE_STATIC_ARRAY
#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \ # define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \
static type const name[] = value; static type const name[] = value;
#endif # endif
#ifndef ARDUINOJSON_READ_STATIC_ARRAY # ifndef ARDUINOJSON_READ_STATIC_ARRAY
#define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) name[index] # define ARDUINOJSON_READ_STATIC_ARRAY(type, name, index) name[index]
#endif # endif
#endif #endif

View File

@@ -20,5 +20,6 @@
#include "type_traits/is_signed.hpp" #include "type_traits/is_signed.hpp"
#include "type_traits/is_unsigned.hpp" #include "type_traits/is_unsigned.hpp"
#include "type_traits/make_unsigned.hpp" #include "type_traits/make_unsigned.hpp"
#include "type_traits/make_void.hpp"
#include "type_traits/remove_const.hpp" #include "type_traits/remove_const.hpp"
#include "type_traits/remove_reference.hpp" #include "type_traits/remove_reference.hpp"

View File

@@ -7,9 +7,9 @@
#include "declval.hpp" #include "declval.hpp"
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) # pragma warning(push)
// conversion from 'T' to 'To', possible loss of data // conversion from 'T' to 'To', possible loss of data
#pragma warning(disable : 4244) # pragma warning(disable : 4244)
#endif #endif
// clang-format off // clang-format off
@@ -37,7 +37,7 @@ struct is_convertible {
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) # pragma warning(pop)
#endif #endif
// clang-format off // clang-format off

View File

@@ -5,15 +5,16 @@
#pragma once #pragma once
#include "integral_constant.hpp" #include "integral_constant.hpp"
#include "is_same.hpp"
#include "remove_cv.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename> template <class T>
struct is_floating_point : false_type {}; struct is_floating_point
: integral_constant<
bool, //
is_same<float, typename remove_cv<T>::type>::value ||
is_same<double, typename remove_cv<T>::type>::value> {};
template <>
struct is_floating_point<float> : true_type {};
template <>
struct is_floating_point<double> : true_type {};
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,29 +5,33 @@
#pragma once #pragma once
#include <ArduinoJson/Configuration.hpp> #include <ArduinoJson/Configuration.hpp>
#include "integral_constant.hpp"
#include "is_same.hpp" #include "is_same.hpp"
#include "remove_cv.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
// A meta-function that returns true if T is an integral type. // clang-format off
template <typename T> template <typename T>
struct is_integral { struct is_integral : integral_constant<bool,
static const bool value = is_same<typename remove_cv<T>::type, signed char>::value ||
is_same<T, signed char>::value || is_same<T, unsigned char>::value || is_same<typename remove_cv<T>::type, unsigned char>::value ||
is_same<T, signed short>::value || is_same<T, unsigned short>::value || is_same<typename remove_cv<T>::type, signed short>::value ||
is_same<T, signed int>::value || is_same<T, unsigned int>::value || is_same<typename remove_cv<T>::type, unsigned short>::value ||
is_same<T, signed long>::value || is_same<T, unsigned long>::value || is_same<typename remove_cv<T>::type, signed int>::value ||
is_same<typename remove_cv<T>::type, unsigned int>::value ||
is_same<typename remove_cv<T>::type, signed long>::value ||
is_same<typename remove_cv<T>::type, unsigned long>::value ||
#if ARDUINOJSON_HAS_LONG_LONG #if ARDUINOJSON_HAS_LONG_LONG
is_same<T, signed long long>::value || is_same<typename remove_cv<T>::type, signed long long>::value ||
is_same<T, unsigned long long>::value || is_same<typename remove_cv<T>::type, unsigned long long>::value ||
#endif #endif
#if ARDUINOJSON_HAS_INT64 #if ARDUINOJSON_HAS_INT64
is_same<T, signed __int64>::value || is_same<typename remove_cv<T>::type, signed __int64>::value ||
is_same<T, unsigned __int64>::value || is_same<typename remove_cv<T>::type, unsigned __int64>::value ||
#endif #endif
is_same<T, char>::value || is_same<T, bool>::value; is_same<typename remove_cv<T>::type, char>::value ||
}; is_same<typename remove_cv<T>::type, bool>::value> {};
// clang-format on
template <typename T>
struct is_integral<const T> : is_integral<T> {};
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,39 +5,26 @@
#pragma once #pragma once
#include "integral_constant.hpp" #include "integral_constant.hpp"
#include "is_same.hpp"
#include "remove_cv.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename> // clang-format off
struct is_signed : false_type {}; template <typename T>
struct is_signed : integral_constant<bool,
template <> is_same<typename remove_cv<T>::type, char>::value ||
struct is_signed<char> : true_type {}; is_same<typename remove_cv<T>::type, signed char>::value ||
is_same<typename remove_cv<T>::type, signed short>::value ||
template <> is_same<typename remove_cv<T>::type, signed int>::value ||
struct is_signed<signed char> : true_type {}; is_same<typename remove_cv<T>::type, signed long>::value ||
template <>
struct is_signed<signed short> : true_type {};
template <>
struct is_signed<signed int> : true_type {};
template <>
struct is_signed<signed long> : true_type {};
template <>
struct is_signed<float> : true_type {};
template <>
struct is_signed<double> : true_type {};
#if ARDUINOJSON_HAS_LONG_LONG #if ARDUINOJSON_HAS_LONG_LONG
template <> is_same<typename remove_cv<T>::type, signed long long>::value ||
struct is_signed<signed long long> : true_type {};
#endif #endif
#if ARDUINOJSON_HAS_INT64 #if ARDUINOJSON_HAS_INT64
template <> is_same<typename remove_cv<T>::type, signed __int64>::value ||
struct is_signed<signed __int64> : true_type {};
#endif #endif
is_same<typename remove_cv<T>::type, float>::value ||
is_same<typename remove_cv<T>::type, double>::value> {};
// clang-format on
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,33 +5,24 @@
#pragma once #pragma once
#include "integral_constant.hpp" #include "integral_constant.hpp"
#include "is_same.hpp"
#include "remove_cv.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename> // clang-format off
struct is_unsigned : false_type {}; template <typename T>
struct is_unsigned : integral_constant<bool,
template <> is_same<typename remove_cv<T>::type, unsigned char>::value ||
struct is_unsigned<bool> : true_type {}; is_same<typename remove_cv<T>::type, unsigned short>::value ||
is_same<typename remove_cv<T>::type, unsigned int>::value ||
template <> is_same<typename remove_cv<T>::type, unsigned long>::value ||
struct is_unsigned<unsigned char> : true_type {};
template <>
struct is_unsigned<unsigned short> : true_type {};
template <>
struct is_unsigned<unsigned int> : true_type {};
template <>
struct is_unsigned<unsigned long> : true_type {};
#if ARDUINOJSON_HAS_INT64 #if ARDUINOJSON_HAS_INT64
template <> is_same<typename remove_cv<T>::type, unsigned __int64>::value ||
struct is_unsigned<unsigned __int64> : true_type {};
#endif #endif
#if ARDUINOJSON_HAS_LONG_LONG #if ARDUINOJSON_HAS_LONG_LONG
template <> is_same<typename remove_cv<T>::type, unsigned long long>::value ||
struct is_unsigned<unsigned long long> : true_type {};
#endif #endif
is_same<typename remove_cv<T>::type, bool>::value> {};
// clang-format on
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,14 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
namespace ARDUINOJSON_NAMESPACE {
template <class = void>
struct make_void {
typedef void type;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,27 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename T>
struct remove_cv {
typedef T type;
};
template <typename T>
struct remove_cv<const T> {
typedef T type;
};
template <typename T>
struct remove_cv<volatile T> {
typedef T type;
};
template <typename T>
struct remove_cv<const volatile T> {
typedef T type;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -31,17 +31,17 @@ class Writer {
#include <ArduinoJson/Serialization/Writers/StaticStringWriter.hpp> #include <ArduinoJson/Serialization/Writers/StaticStringWriter.hpp>
#if ARDUINOJSON_ENABLE_STD_STRING #if ARDUINOJSON_ENABLE_STD_STRING
#include <ArduinoJson/Serialization/Writers/StdStringWriter.hpp> # include <ArduinoJson/Serialization/Writers/StdStringWriter.hpp>
#endif #endif
#if ARDUINOJSON_ENABLE_ARDUINO_STRING #if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp> # include <ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp>
#endif #endif
#if ARDUINOJSON_ENABLE_STD_STREAM #if ARDUINOJSON_ENABLE_STD_STREAM
#include <ArduinoJson/Serialization/Writers/StdStreamWriter.hpp> # include <ArduinoJson/Serialization/Writers/StdStreamWriter.hpp>
#endif #endif
#if ARDUINOJSON_ENABLE_ARDUINO_PRINT #if ARDUINOJSON_ENABLE_ARDUINO_PRINT
#include <ArduinoJson/Serialization/Writers/PrintWriter.hpp> # include <ArduinoJson/Serialization/Writers/PrintWriter.hpp>
#endif #endif

View File

@@ -22,10 +22,10 @@ class Writer< ::String, void> {
} }
size_t write(uint8_t c) { size_t write(uint8_t c) {
ARDUINOJSON_ASSERT(_size < bufferCapacity);
_buffer[_size++] = static_cast<char>(c);
if (_size + 1 >= bufferCapacity) if (_size + 1 >= bufferCapacity)
flush(); if (flush() != 0)
return 0;
_buffer[_size++] = static_cast<char>(c);
return 1; return 1;
} }
@@ -36,14 +36,15 @@ class Writer< ::String, void> {
return n; return n;
} }
private: size_t flush() {
void flush() {
ARDUINOJSON_ASSERT(_size < bufferCapacity); ARDUINOJSON_ASSERT(_size < bufferCapacity);
_buffer[_size] = 0; _buffer[_size] = 0;
*_destination += _buffer; if (_destination->concat(_buffer))
_size = 0; _size = 0;
return _size;
} }
private:
::String *_destination; ::String *_destination;
char _buffer[bufferCapacity]; char _buffer[bufferCapacity];
size_t _size; size_t _size;

View File

@@ -55,8 +55,12 @@ class StringCopier {
private: private:
MemoryPool* _pool; MemoryPool* _pool;
// These fields aren't initialized by the constructor but startString()
//
// NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
char* _ptr; char* _ptr;
size_t _size; // NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.UninitializedObject)
size_t _capacity; size_t _size, _capacity;
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -7,14 +7,15 @@
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson/Polyfills/safe_strcmp.hpp> #include <ArduinoJson/Polyfills/safe_strcmp.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class ArduinoStringAdapter { template <>
class StringAdapter< ::String> {
public: public:
ArduinoStringAdapter(const ::String& str) : _str(&str) {} StringAdapter(const ::String& str) : _str(&str) {}
void copyTo(char* p, size_t n) const { void copyTo(char* p, size_t n) const {
memcpy(p, _str->c_str(), n); memcpy(p, _str->c_str(), n);
@@ -31,18 +32,10 @@ class ArduinoStringAdapter {
return safe_strcmp(me, other); return safe_strcmp(me, other);
} }
bool equals(const char* expected) const {
return compare(expected) == 0;
}
size_t size() const { size_t size() const {
return _str->length(); return _str->length();
} }
const char* begin() const {
return _str->c_str();
}
typedef storage_policies::store_by_copy storage_policy; typedef storage_policies::store_by_copy storage_policy;
private: private:
@@ -50,13 +43,10 @@ class ArduinoStringAdapter {
}; };
template <> template <>
struct IsString< ::String> : true_type {}; class StringAdapter< ::StringSumHelper> : public StringAdapter< ::String> {
public:
template <> StringAdapter< ::StringSumHelper>(const ::String& s)
struct IsString< ::StringSumHelper> : true_type {}; : StringAdapter< ::String>(s) {}
};
inline ArduinoStringAdapter adaptString(const ::String& str) {
return ArduinoStringAdapter(str);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -8,23 +8,20 @@
#include <string.h> // strcmp #include <string.h> // strcmp
#include <ArduinoJson/Polyfills/safe_strcmp.hpp> #include <ArduinoJson/Polyfills/safe_strcmp.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class ConstRamStringAdapter { template <>
class StringAdapter<const char*> {
public: public:
ConstRamStringAdapter(const char* str = 0) : _str(str) {} StringAdapter(const char* str = 0) : _str(str) {}
int compare(const char* other) const { int compare(const char* other) const {
return safe_strcmp(_str, other); return safe_strcmp(_str, other);
} }
bool equals(const char* expected) const {
return compare(expected) == 0;
}
bool isNull() const { bool isNull() const {
return !_str; return !_str;
} }
@@ -39,24 +36,16 @@ class ConstRamStringAdapter {
return _str; return _str;
} }
const char* begin() const {
return _str;
}
typedef storage_policies::store_by_address storage_policy; typedef storage_policies::store_by_address storage_policy;
protected: protected:
const char* _str; const char* _str;
}; };
template <>
struct IsString<const char*> : true_type {};
template <int N> template <int N>
struct IsString<const char[N]> : true_type {}; class StringAdapter<const char[N]> : public StringAdapter<const char*> {
public:
inline ConstRamStringAdapter adaptString(const char* str) { StringAdapter<const char[N]>(const char* s) : StringAdapter<const char*>(s) {}
return ConstRamStringAdapter(str); };
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,15 +5,15 @@
#pragma once #pragma once
#include <ArduinoJson/Polyfills/pgmspace.hpp> #include <ArduinoJson/Polyfills/pgmspace.hpp>
#include <ArduinoJson/Strings/FlashStringIterator.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class FlashStringAdapter { template <>
class StringAdapter<const __FlashStringHelper*> {
public: public:
FlashStringAdapter(const __FlashStringHelper* str) : _str(str) {} StringAdapter(const __FlashStringHelper* str) : _str(str) {}
int compare(const char* other) const { int compare(const char* other) const {
if (!other && !_str) if (!other && !_str)
@@ -25,10 +25,6 @@ class FlashStringAdapter {
return -strcmp_P(other, reinterpret_cast<const char*>(_str)); return -strcmp_P(other, reinterpret_cast<const char*>(_str));
} }
bool equals(const char* expected) const {
return compare(expected) == 0;
}
bool isNull() const { bool isNull() const {
return !_str; return !_str;
} }
@@ -43,20 +39,10 @@ class FlashStringAdapter {
return strlen_P(reinterpret_cast<const char*>(_str)); return strlen_P(reinterpret_cast<const char*>(_str));
} }
FlashStringIterator begin() const {
return FlashStringIterator(_str);
}
typedef storage_policies::store_by_copy storage_policy; typedef storage_policies::store_by_copy storage_policy;
private: private:
const __FlashStringHelper* _str; const __FlashStringHelper* _str;
}; };
inline FlashStringAdapter adaptString(const __FlashStringHelper* str) {
return FlashStringAdapter(str);
}
template <>
struct IsString<const __FlashStringHelper*> : true_type {};
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,27 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Strings/Adapters/RamStringAdapter.hpp>
#include <ArduinoJson/Strings/String.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <>
class StringAdapter<String> : public StringAdapter<char*> {
public:
StringAdapter(const String& str)
: StringAdapter<char*>(str.c_str()), _isStatic(str.isStatic()) {}
bool isStatic() const {
return _isStatic;
}
typedef storage_policies::decide_at_runtime storage_policy;
private:
bool _isStatic;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,29 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename TChar>
class StringAdapter<TChar*, false,
typename enable_if<sizeof(TChar) == 1 &&
!is_same<TChar, void>::value>::type>
: public StringAdapter<const char*> {
public:
StringAdapter(const TChar* str)
: StringAdapter<const char*>(reinterpret_cast<const char*>(str)) {}
void copyTo(char* p, size_t n) const {
memcpy(p, _str, n);
}
typedef ARDUINOJSON_NAMESPACE::storage_policies::store_by_copy storage_policy;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,15 +5,15 @@
#pragma once #pragma once
#include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Strings/FlashStringIterator.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class SizedFlashStringAdapter { template <>
class StringAdapter<const __FlashStringHelper*, true> {
public: public:
SizedFlashStringAdapter(const __FlashStringHelper* str, size_t sz) StringAdapter(const __FlashStringHelper* str, size_t sz)
: _str(str), _size(sz) {} : _str(str), _size(sz) {}
int compare(const char* other) const { int compare(const char* other) const {
@@ -26,10 +26,6 @@ class SizedFlashStringAdapter {
return -strncmp_P(other, reinterpret_cast<const char*>(_str), _size); return -strncmp_P(other, reinterpret_cast<const char*>(_str), _size);
} }
bool equals(const char* expected) const {
return compare(expected) == 0;
}
bool isNull() const { bool isNull() const {
return !_str; return !_str;
} }
@@ -42,10 +38,6 @@ class SizedFlashStringAdapter {
return _size; return _size;
} }
FlashStringIterator begin() const {
return FlashStringIterator(_str);
}
typedef storage_policies::store_by_copy storage_policy; typedef storage_policies::store_by_copy storage_policy;
private: private:
@@ -53,8 +45,4 @@ class SizedFlashStringAdapter {
size_t _size; size_t _size;
}; };
inline SizedFlashStringAdapter adaptString(const __FlashStringHelper* str,
size_t sz) {
return SizedFlashStringAdapter(str, sz);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -5,25 +5,22 @@
#pragma once #pragma once
#include <ArduinoJson/Namespace.hpp> #include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp> #include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
#include <string.h> // strcmp #include <string.h> // strcmp
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class SizedRamStringAdapter { template <typename TChar>
class StringAdapter<TChar*, true> {
public: public:
SizedRamStringAdapter(const char* str, size_t n) : _str(str), _size(n) {} StringAdapter(const char* str, size_t n) : _str(str), _size(n) {}
int compare(const char* other) const { int compare(const char* other) const {
return safe_strncmp(_str, other, _size); return safe_strncmp(_str, other, _size);
} }
bool equals(const char* expected) const {
return compare(expected) == 0;
}
bool isNull() const { bool isNull() const {
return !_str; return !_str;
} }
@@ -36,10 +33,6 @@ class SizedRamStringAdapter {
return _size; return _size;
} }
const char* begin() const {
return _str;
}
typedef storage_policies::store_by_copy storage_policy; typedef storage_policies::store_by_copy storage_policy;
private: private:
@@ -47,9 +40,4 @@ class SizedRamStringAdapter {
size_t _size; size_t _size;
}; };
template <typename TChar>
inline SizedRamStringAdapter adaptString(const TChar* str, size_t size) {
return SizedRamStringAdapter(reinterpret_cast<const char*>(str), size);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,46 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
#include <string>
namespace ARDUINOJSON_NAMESPACE {
template <typename TCharTraits, typename TAllocator>
class StringAdapter<std::basic_string<char, TCharTraits, TAllocator> > {
public:
typedef std::basic_string<char, TCharTraits, TAllocator> string_type;
StringAdapter(const string_type& str) : _str(&str) {}
void copyTo(char* p, size_t n) const {
memcpy(p, _str->c_str(), n);
}
bool isNull() const {
return false;
}
int compare(const char* other) const {
if (!other)
return 1;
return _str->compare(other);
}
size_t size() const {
return _str->size();
}
typedef storage_policies::store_by_copy storage_policy;
private:
const string_type* _str;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,44 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Strings/StringAdapter.hpp>
#include <string_view>
namespace ARDUINOJSON_NAMESPACE {
template <>
class StringAdapter<std::string_view> {
public:
StringAdapter(std::string_view str) : _str(str) {}
void copyTo(char* p, size_t n) const {
memcpy(p, _str.data(), n);
}
bool isNull() const {
return false;
}
int compare(const char* other) const {
if (!other)
return 1;
return _str.compare(other);
}
size_t size() const {
return _str.size();
}
typedef storage_policies::store_by_copy storage_policy;
private:
std::string_view _str;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,44 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
namespace ARDUINOJSON_NAMESPACE {
class FlashStringIterator {
public:
explicit FlashStringIterator(const __FlashStringHelper* ptr)
: _ptr(reinterpret_cast<const char*>(ptr)) {}
explicit FlashStringIterator(const char* ptr) : _ptr(ptr) {}
FlashStringIterator operator+(ptrdiff_t d) const {
return FlashStringIterator(_ptr + d);
}
ptrdiff_t operator-(FlashStringIterator other) const {
return _ptr - other._ptr;
}
FlashStringIterator operator++(int) {
return FlashStringIterator(_ptr++);
}
FlashStringIterator operator++() {
return FlashStringIterator(++_ptr);
}
bool operator!=(FlashStringIterator other) const {
return _ptr != other._ptr;
}
char operator*() const {
return char(pgm_read_byte(_ptr));
}
private:
const char* _ptr;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,18 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename>
struct IsString : false_type {};
template <typename T>
struct IsString<const T> : IsString<T> {};
template <typename T>
struct IsString<T&> : IsString<T> {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -8,11 +8,11 @@
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
#if ARDUINOJSON_ENABLE_ARDUINO_STRING #if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <Arduino.h> # include <Arduino.h>
#endif #endif
#if ARDUINOJSON_ENABLE_STD_STRING #if ARDUINOJSON_ENABLE_STD_STRING
#include <string> # include <string>
#endif #endif
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {

View File

@@ -1,43 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Strings/ConstRamStringAdapter.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
namespace ARDUINOJSON_NAMESPACE {
class RamStringAdapter : public ConstRamStringAdapter {
public:
RamStringAdapter(const char* str) : ConstRamStringAdapter(str) {}
void copyTo(char* p, size_t n) const {
memcpy(p, _str, n);
}
typedef ARDUINOJSON_NAMESPACE::storage_policies::store_by_copy storage_policy;
};
template <typename TChar>
inline RamStringAdapter adaptString(const TChar* str) {
return RamStringAdapter(reinterpret_cast<const char*>(str));
}
inline RamStringAdapter adaptString(char* str) {
return RamStringAdapter(str);
}
template <typename TChar>
struct IsString<TChar*> {
static const bool value = sizeof(TChar) == 1;
};
template <>
struct IsString<void*> {
static const bool value = false;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -1,65 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <string>
namespace ARDUINOJSON_NAMESPACE {
template <typename TString>
class StdStringAdapter {
public:
StdStringAdapter(const TString& str) : _str(&str) {}
void copyTo(char* p, size_t n) const {
memcpy(p, _str->c_str(), n);
}
bool isNull() const {
return false;
}
int compare(const char* other) const {
if (!other)
return 1;
return _str->compare(other);
}
bool equals(const char* expected) const {
if (!expected)
return false;
return *_str == expected;
}
size_t size() const {
return _str->size();
}
const char* begin() const {
return _str->c_str();
}
typedef storage_policies::store_by_copy storage_policy;
private:
const TString* _str;
};
template <typename TCharTraits, typename TAllocator>
struct IsString<std::basic_string<char, TCharTraits, TAllocator> > : true_type {
};
template <typename TCharTraits, typename TAllocator>
inline StdStringAdapter<std::basic_string<char, TCharTraits, TAllocator> >
adaptString(const std::basic_string<char, TCharTraits, TAllocator>& str) {
return StdStringAdapter<std::basic_string<char, TCharTraits, TAllocator> >(
str);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -4,10 +4,6 @@
#pragma once #pragma once
#include <ArduinoJson/Strings/ConstRamStringAdapter.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class String { class String {
@@ -53,25 +49,4 @@ class String {
bool _isStatic; bool _isStatic;
}; };
class StringAdapter : public RamStringAdapter {
public:
StringAdapter(const String& str)
: RamStringAdapter(str.c_str()), _isStatic(str.isStatic()) {}
bool isStatic() const {
return _isStatic;
}
typedef storage_policies::decide_at_runtime storage_policy;
private:
bool _isStatic;
};
template <>
struct IsString<String> : true_type {};
inline StringAdapter adaptString(const String& str) {
return StringAdapter(str);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -0,0 +1,32 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/type_traits.hpp>
namespace ARDUINOJSON_NAMESPACE {
template <typename T, bool bounded = false, typename Enable = void>
class StringAdapter;
template <typename T>
inline StringAdapter<T, false> adaptString(const T& str) {
return StringAdapter<T, false>(str);
}
template <typename T>
inline StringAdapter<T, true> adaptString(const T& str, size_t sz) {
return StringAdapter<T, true>(str, sz);
}
template <typename T, typename Enable = void>
struct IsString : false_type {};
template <typename T>
struct IsString<
T, typename make_void<typename StringAdapter<T>::storage_policy>::type>
: true_type {};
} // namespace ARDUINOJSON_NAMESPACE

View File

@@ -4,19 +4,24 @@
#pragma once #pragma once
#include <ArduinoJson/Strings/ConstRamStringAdapter.hpp> #include <ArduinoJson/Strings/Adapters/ConstRamStringAdapter.hpp>
#include <ArduinoJson/Strings/RamStringAdapter.hpp> #include <ArduinoJson/Strings/Adapters/JsonStringAdapter.hpp>
#include <ArduinoJson/Strings/SizedRamStringAdapter.hpp> #include <ArduinoJson/Strings/Adapters/RamStringAdapter.hpp>
#include <ArduinoJson/Strings/Adapters/SizedRamStringAdapter.hpp>
#if ARDUINOJSON_ENABLE_STD_STRING #if ARDUINOJSON_ENABLE_STD_STRING
#include <ArduinoJson/Strings/StdStringAdapter.hpp> # include <ArduinoJson/Strings/Adapters/StdStringAdapter.hpp>
#endif
#if ARDUINOJSON_ENABLE_STRING_VIEW
# include <ArduinoJson/Strings/Adapters/StringViewAdapter.hpp>
#endif #endif
#if ARDUINOJSON_ENABLE_ARDUINO_STRING #if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <ArduinoJson/Strings/ArduinoStringAdapter.hpp> # include <ArduinoJson/Strings/Adapters/ArduinoStringAdapter.hpp>
#endif #endif
#if ARDUINOJSON_ENABLE_PROGMEM #if ARDUINOJSON_ENABLE_PROGMEM
#include <ArduinoJson/Strings/FlashStringAdapter.hpp> # include <ArduinoJson/Strings/Adapters/FlashStringAdapter.hpp>
#include <ArduinoJson/Strings/SizedFlashStringAdapter.hpp> # include <ArduinoJson/Strings/Adapters/SizedFlashStringAdapter.hpp>
#endif #endif

View File

@@ -9,4 +9,9 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename T, typename Enable = void> template <typename T, typename Enable = void>
struct Converter; struct Converter;
// clang-format off
template <typename T1, typename T2>
class InvalidConversion; // Error here? See https://arduinojson.org/v6/invalid-conversion/
// clang-format on
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -12,9 +12,9 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename T, typename Enable> template <typename T, typename Enable>
struct Converter { struct Converter {
static bool toJson(const T& src, VariantRef dst) { static void toJson(const T& src, VariantRef dst) {
// clang-format off // clang-format off
return convertToJson(src, dst); // Error here? See https://arduinojson.org/v6/unsupported-set/ convertToJson(src, dst); // Error here? See https://arduinojson.org/v6/unsupported-set/
// clang-format on // clang-format on
} }
@@ -38,13 +38,11 @@ template <typename T>
struct Converter< struct Converter<
T, typename enable_if<is_integral<T>::value && !is_same<bool, T>::value && T, typename enable_if<is_integral<T>::value && !is_same<bool, T>::value &&
!is_same<char, T>::value>::type> { !is_same<char, T>::value>::type> {
static bool toJson(T src, VariantRef dst) { static void toJson(T src, VariantRef dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
if (!data) if (data)
return false; data->setInteger(src);
data->setInteger(src);
return true;
} }
static T fromJson(VariantConstRef src) { static T fromJson(VariantConstRef src) {
@@ -61,8 +59,8 @@ struct Converter<
template <typename T> template <typename T>
struct Converter<T, typename enable_if<is_enum<T>::value>::type> { struct Converter<T, typename enable_if<is_enum<T>::value>::type> {
static bool toJson(T src, VariantRef dst) { static void toJson(T src, VariantRef dst) {
return dst.set(static_cast<Integer>(src)); dst.set(static_cast<Integer>(src));
} }
static T fromJson(VariantConstRef src) { static T fromJson(VariantConstRef src) {
@@ -78,12 +76,10 @@ struct Converter<T, typename enable_if<is_enum<T>::value>::type> {
template <> template <>
struct Converter<bool> { struct Converter<bool> {
static bool toJson(bool src, VariantRef dst) { static void toJson(bool src, VariantRef dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
if (!data) if (data)
return false; data->setBoolean(src);
data->setBoolean(src);
return true;
} }
static bool fromJson(VariantConstRef src) { static bool fromJson(VariantConstRef src) {
@@ -99,12 +95,10 @@ struct Converter<bool> {
template <typename T> template <typename T>
struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> { struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> {
static bool toJson(T src, VariantRef dst) { static void toJson(T src, VariantRef dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
if (!data) if (data)
return false; data->setFloat(static_cast<Float>(src));
data->setFloat(static_cast<Float>(src));
return true;
} }
static T fromJson(VariantConstRef src) { static T fromJson(VariantConstRef src) {
@@ -120,8 +114,8 @@ struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> {
template <> template <>
struct Converter<const char*> { struct Converter<const char*> {
static bool toJson(const char* src, VariantRef dst) { static void toJson(const char* src, VariantRef dst) {
return variantSetString(getData(dst), adaptString(src), getPool(dst)); variantSetString(getData(dst), adaptString(src), getPool(dst));
} }
static const char* fromJson(VariantConstRef src) { static const char* fromJson(VariantConstRef src) {
@@ -163,12 +157,10 @@ canConvertFromJson(VariantConstRef src, const T&) {
template <> template <>
struct Converter<SerializedValue<const char*> > { struct Converter<SerializedValue<const char*> > {
static bool toJson(SerializedValue<const char*> src, VariantRef dst) { static void toJson(SerializedValue<const char*> src, VariantRef dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
if (!data) if (data)
return false; data->setLinkedRaw(src);
data->setLinkedRaw(src);
return true;
} }
}; };
@@ -178,10 +170,11 @@ struct Converter<SerializedValue<const char*> > {
template <typename T> template <typename T>
struct Converter<SerializedValue<T>, struct Converter<SerializedValue<T>,
typename enable_if<!is_same<const char*, T>::value>::type> { typename enable_if<!is_same<const char*, T>::value>::type> {
static bool toJson(SerializedValue<T> src, VariantRef dst) { static void toJson(SerializedValue<T> src, VariantRef dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
MemoryPool* pool = getPool(dst); MemoryPool* pool = getPool(dst);
return data != 0 && data->setOwnedRaw(src, pool); if (data)
data->setOwnedRaw(src, pool);
} }
}; };
@@ -189,9 +182,8 @@ struct Converter<SerializedValue<T>,
template <> template <>
struct Converter<decltype(nullptr)> { struct Converter<decltype(nullptr)> {
static bool toJson(decltype(nullptr), VariantRef dst) { static void toJson(decltype(nullptr), VariantRef dst) {
variantSetNull(getData(dst)); variantSetNull(getData(dst));
return true;
} }
static decltype(nullptr) fromJson(VariantConstRef) { static decltype(nullptr) fromJson(VariantConstRef) {
return nullptr; return nullptr;
@@ -247,20 +239,33 @@ class MemoryPoolPrint : public Print {
size_t _capacity; size_t _capacity;
}; };
inline bool convertToJson(const ::Printable& src, VariantRef dst) { inline void convertToJson(const ::Printable& src, VariantRef dst) {
MemoryPool* pool = getPool(dst); MemoryPool* pool = getPool(dst);
VariantData* data = getData(dst); VariantData* data = getData(dst);
if (!pool || !data) if (!pool || !data)
return false; return;
MemoryPoolPrint print(pool); MemoryPoolPrint print(pool);
src.printTo(print); src.printTo(print);
if (print.overflowed()) { if (print.overflowed()) {
pool->markAsOverflowed(); pool->markAsOverflowed();
data->setNull(); data->setNull();
return false; return;
} }
data->setStringPointer(print.c_str(), storage_policies::store_by_copy()); data->setStringPointer(print.c_str(), storage_policies::store_by_copy());
return true; }
#endif
#if ARDUINOJSON_ENABLE_STRING_VIEW
inline void convertFromJson(VariantConstRef src, std::string_view& dst) {
const char* str = src.as<const char*>();
if (str) // the standard doesn't allow passing null to the constructor
dst = std::string_view(str);
}
inline bool canConvertFromJson(VariantConstRef src, const std::string_view&) {
return src.is<const char*>();
} }
#endif #endif

View File

@@ -8,7 +8,7 @@
#include <ArduinoJson/Misc/Visitable.hpp> #include <ArduinoJson/Misc/Visitable.hpp>
#include <ArduinoJson/Numbers/arithmeticCompare.hpp> #include <ArduinoJson/Numbers/arithmeticCompare.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/IsString.hpp> #include <ArduinoJson/Strings/StringAdapter.hpp>
#include <ArduinoJson/Variant/Visitor.hpp> #include <ArduinoJson/Variant/Visitor.hpp>
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {

View File

@@ -7,17 +7,17 @@
#include <ArduinoJson/Memory/MemoryPool.hpp> #include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Misc/SerializedValue.hpp> #include <ArduinoJson/Misc/SerializedValue.hpp>
#include <ArduinoJson/Numbers/convertNumber.hpp> #include <ArduinoJson/Numbers/convertNumber.hpp>
#include <ArduinoJson/Strings/RamStringAdapter.hpp> #include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantContent.hpp> #include <ArduinoJson/Variant/VariantContent.hpp>
// VariantData can't have a constructor (to be a POD), so we have no way to fix // VariantData can't have a constructor (to be a POD), so we have no way to fix
// this warning // this warning
#if defined(__GNUC__) #if defined(__GNUC__)
#if __GNUC__ >= 7 # if __GNUC__ >= 7
#pragma GCC diagnostic push # pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#pragma GCC diagnostic ignored "-Wuninitialized" # pragma GCC diagnostic ignored "-Wuninitialized"
#endif # endif
#endif #endif
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@@ -33,7 +33,7 @@ class VariantData {
// - no virtual // - no virtual
// - no inheritance // - no inheritance
void init() { void init() {
_flags = 0; _flags = VALUE_IS_NULL;
} }
template <typename TVisitor> template <typename TVisitor>
@@ -103,7 +103,8 @@ class VariantData {
case VALUE_IS_OBJECT: case VALUE_IS_OBJECT:
return toObject().copyFrom(src._content.asCollection, pool); return toObject().copyFrom(src._content.asCollection, pool);
case VALUE_IS_OWNED_STRING: case VALUE_IS_OWNED_STRING:
return setString(RamStringAdapter(src._content.asString), pool); return setString(adaptString(const_cast<char *>(src._content.asString)),
pool);
case VALUE_IS_OWNED_RAW: case VALUE_IS_OWNED_RAW:
return setOwnedRaw( return setOwnedRaw(
serialized(src._content.asRaw.data, src._content.asRaw.size), pool); serialized(src._content.asRaw.data, src._content.asRaw.size), pool);
@@ -362,7 +363,7 @@ class VariantData {
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#if defined(__GNUC__) #if defined(__GNUC__)
#if __GNUC__ >= 8 # if __GNUC__ >= 8
#pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif # endif
#endif #endif

View File

@@ -140,4 +140,9 @@ inline VariantConstRef operator|(VariantConstRef preferedValue,
VariantConstRef defaultValue) { VariantConstRef defaultValue) {
return preferedValue ? preferedValue : defaultValue; return preferedValue ? preferedValue : defaultValue;
} }
// Out of class definition to avoid #1560
inline bool VariantRef::set(char value) const {
return set<signed char>(value);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@@ -85,18 +85,18 @@ class VariantRef : public VariantRefBase<VariantData>,
template <typename T> template <typename T>
FORCE_INLINE bool set(const T &value) const { FORCE_INLINE bool set(const T &value) const {
return Converter<T>::toJson(value, *this); Converter<T>::toJson(value, *this);
return _pool && !_pool->overflowed();
} }
FORCE_INLINE bool ARDUINOJSON_DEPRECATED( bool ARDUINOJSON_DEPRECATED(
"Support for char is deprecated, use int8_t or uint8_t instead") "Support for char is deprecated, use int8_t or uint8_t instead")
set(char value) const { set(char value) const;
return set<signed char>(value);
}
template <typename T> template <typename T>
FORCE_INLINE bool set(T *value) const { FORCE_INLINE bool set(T *value) const {
return Converter<T *>::toJson(value, *this); Converter<T *>::toJson(value, *this);
return _pool && !_pool->overflowed();
} }
template <typename T> template <typename T>
@@ -341,16 +341,22 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
template <> template <>
struct Converter<VariantRef> { struct Converter<VariantRef> {
static bool toJson(VariantRef src, VariantRef dst) { static void toJson(VariantRef src, VariantRef dst) {
return variantCopyFrom(getData(dst), getData(src), getPool(dst)); variantCopyFrom(getData(dst), getData(src), getPool(dst));
} }
static VariantRef fromJson(VariantRef src) { static VariantRef fromJson(VariantRef src) {
return src; return src;
} }
static InvalidConversion<VariantConstRef, VariantRef> fromJson(
VariantConstRef);
static bool checkJson(VariantRef src) { static bool checkJson(VariantRef src) {
VariantData *data = getData(src); VariantData *data = getData(src);
return !!data; return !!data;
} }
static bool checkJson(VariantConstRef) { static bool checkJson(VariantConstRef) {
return false; return false;
} }
@@ -358,8 +364,8 @@ struct Converter<VariantRef> {
template <> template <>
struct Converter<VariantConstRef> { struct Converter<VariantConstRef> {
static bool toJson(VariantConstRef src, VariantRef dst) { static void toJson(VariantConstRef src, VariantRef dst) {
return variantCopyFrom(getData(dst), getData(src), getPool(dst)); variantCopyFrom(getData(dst), getData(src), getPool(dst));
} }
static VariantConstRef fromJson(VariantConstRef src) { static VariantConstRef fromJson(VariantConstRef src) {

View File

@@ -4,7 +4,7 @@
#pragma once #pragma once
#define ARDUINOJSON_VERSION "6.18.0" #define ARDUINOJSON_VERSION "6.18.3"
#define ARDUINOJSON_VERSION_MAJOR 6 #define ARDUINOJSON_VERSION_MAJOR 6
#define ARDUINOJSON_VERSION_MINOR 18 #define ARDUINOJSON_VERSION_MINOR 18
#define ARDUINOJSON_VERSION_REVISION 0 #define ARDUINOJSON_VERSION_REVISION 3

File diff suppressed because it is too large Load Diff

View File

@@ -23,17 +23,20 @@
#define ASYNCTCP_H_ #define ASYNCTCP_H_
#include "IPAddress.h" #include "IPAddress.h"
#include "IPv6Address.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include <functional> #include <functional>
extern "C" { extern "C" {
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "lwip/pbuf.h" #include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
} }
//If core is not defined, then we are running in Arduino or PIO //If core is not defined, then we are running in Arduino or PIO
#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE #ifndef CONFIG_ASYNC_TCP_RUNNING_CORE
#define CONFIG_ASYNC_TCP_RUNNING_CORE -1 //any available core #define CONFIG_ASYNC_TCP_RUNNING_CORE -1 //any available core
#define CONFIG_ASYNC_TCP_USE_WDT 1 //if enabled, adds between 33us and 200us per event #define CONFIG_ASYNC_TCP_USE_WDT 1 //if enabled, adds between 33us and 200us per event
#endif #endif
class AsyncClient; class AsyncClient;
@@ -42,127 +45,138 @@ class AsyncClient;
#define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given) #define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given)
#define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react. #define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react.
typedef std::function<void(void*, AsyncClient*)> AcConnectHandler; typedef std::function<void(void *, AsyncClient *)> AcConnectHandler;
typedef std::function<void(void*, AsyncClient*, size_t len, uint32_t time)> AcAckHandler; typedef std::function<void(void *, AsyncClient *, size_t len, uint32_t time)> AcAckHandler;
typedef std::function<void(void*, AsyncClient*, int8_t error)> AcErrorHandler; typedef std::function<void(void *, AsyncClient *, int8_t error)> AcErrorHandler;
typedef std::function<void(void*, AsyncClient*, void *data, size_t len)> AcDataHandler; typedef std::function<void(void *, AsyncClient *, void * data, size_t len)> AcDataHandler;
typedef std::function<void(void*, AsyncClient*, struct pbuf *pb)> AcPacketHandler; typedef std::function<void(void *, AsyncClient *, struct pbuf * pb)> AcPacketHandler;
typedef std::function<void(void*, AsyncClient*, uint32_t time)> AcTimeoutHandler; typedef std::function<void(void *, AsyncClient *, uint32_t time)> AcTimeoutHandler;
struct tcp_pcb; struct tcp_pcb;
struct ip_addr; struct ip_addr;
class AsyncClient { class AsyncClient {
public: public:
AsyncClient(tcp_pcb* pcb = 0); AsyncClient(tcp_pcb * pcb = 0);
~AsyncClient(); ~AsyncClient();
AsyncClient & operator=(const AsyncClient &other); AsyncClient & operator=(const AsyncClient & other);
AsyncClient & operator+=(const AsyncClient &other); AsyncClient & operator+=(const AsyncClient & other);
bool operator==(const AsyncClient &other); bool operator==(const AsyncClient & other);
bool operator!=(const AsyncClient &other) { bool operator!=(const AsyncClient & other) {
return !(*this == other); return !(*this == other);
} }
bool connect(IPAddress ip, uint16_t port); bool connect(IPAddress ip, uint16_t port);
bool connect(const char* host, uint16_t port); bool connect(IPv6Address ip, uint16_t port);
void close(bool now = false); bool connect(const char * host, uint16_t port);
void stop(); void close(bool now = false);
void stop();
int8_t abort(); int8_t abort();
bool free(); bool free();
bool canSend();//ack is not pending bool canSend(); //ack is not pending
size_t space();//space available in the TCP window size_t space(); //space available in the TCP window
size_t add(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY);//add for sending size_t add(const char * data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); //add for sending
bool send();//send all data added with the method above bool send(); //send all data added with the method above
//write equals add()+send() //write equals add()+send()
size_t write(const char* data); size_t write(const char * data);
size_t write(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY); //only when canSend() == true size_t write(const char * data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); //only when canSend() == true
uint8_t state(); uint8_t state();
bool connecting(); bool connecting();
bool connected(); bool connected();
bool disconnecting(); bool disconnecting();
bool disconnected(); bool disconnected();
bool freeable();//disconnected or disconnecting bool freeable(); //disconnected or disconnecting
uint16_t getMss(); uint16_t getMss();
uint32_t getRxTimeout(); uint32_t getRxTimeout();
void setRxTimeout(uint32_t timeout);//no RX data timeout for the connection in seconds void setRxTimeout(uint32_t timeout); //no RX data timeout for the connection in seconds
uint32_t getAckTimeout(); uint32_t getAckTimeout();
void setAckTimeout(uint32_t timeout);//no ACK timeout for the last sent packet in milliseconds void setAckTimeout(uint32_t timeout); //no ACK timeout for the last sent packet in milliseconds
void setNoDelay(bool nodelay); void setNoDelay(bool nodelay);
bool getNoDelay(); bool getNoDelay();
uint32_t getRemoteAddress(); uint32_t getRemoteAddress();
uint16_t getRemotePort(); ip6_addr_t getRemoteAddress6();
uint32_t getLocalAddress(); uint16_t getRemotePort();
uint16_t getLocalPort(); uint32_t getLocalAddress();
ip6_addr_t getLocalAddress6();
uint16_t getLocalPort();
//compatibility //compatibility
IPAddress remoteIP(); IPAddress remoteIP();
uint16_t remotePort(); IPv6Address remoteIP6();
IPAddress localIP(); uint16_t remotePort();
uint16_t localPort(); IPAddress localIP();
IPv6Address localIP6();
uint16_t localPort();
void onConnect(AcConnectHandler cb, void* arg = 0); //on successful connect void onConnect(AcConnectHandler cb, void * arg = 0); //on successful connect
void onDisconnect(AcConnectHandler cb, void* arg = 0); //disconnected void onDisconnect(AcConnectHandler cb, void * arg = 0); //disconnected
void onAck(AcAckHandler cb, void* arg = 0); //ack received void onAck(AcAckHandler cb, void * arg = 0); //ack received
void onError(AcErrorHandler cb, void* arg = 0); //unsuccessful connect or error void onError(AcErrorHandler cb, void * arg = 0); //unsuccessful connect or error
void onData(AcDataHandler cb, void* arg = 0); //data received (called if onPacket is not used) void onData(AcDataHandler cb, void * arg = 0); //data received (called if onPacket is not used)
void onPacket(AcPacketHandler cb, void* arg = 0); //data received void onPacket(AcPacketHandler cb, void * arg = 0); //data received
void onTimeout(AcTimeoutHandler cb, void* arg = 0); //ack timeout void onTimeout(AcTimeoutHandler cb, void * arg = 0); //ack timeout
void onPoll(AcConnectHandler cb, void* arg = 0); //every 125ms when connected void onPoll(AcConnectHandler cb, void * arg = 0); //every 125ms when connected
void ackPacket(struct pbuf * pb);//ack pbuf from onPacket void ackPacket(struct pbuf * pb); //ack pbuf from onPacket
size_t ack(size_t len); //ack data that you have not acked using the method below size_t ack(size_t len); //ack data that you have not acked using the method below
void ackLater(){ _ack_pcb = false; } //will not ack the current packet. Call from onData void ackLater() {
_ack_pcb = false;
} //will not ack the current packet. Call from onData
const char * errorToString(int8_t error); const char * errorToString(int8_t error);
const char * stateToString(); const char * stateToString();
//Do not use any of the functions below! //Do not use any of the functions below!
static int8_t _s_poll(void *arg, struct tcp_pcb *tpcb); static int8_t _s_poll(void * arg, struct tcp_pcb * tpcb);
static int8_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, int8_t err); static int8_t _s_recv(void * arg, struct tcp_pcb * tpcb, struct pbuf * pb, int8_t err);
static int8_t _s_fin(void *arg, struct tcp_pcb *tpcb, int8_t err); static int8_t _s_fin(void * arg, struct tcp_pcb * tpcb, int8_t err);
static int8_t _s_lwip_fin(void *arg, struct tcp_pcb *tpcb, int8_t err); static int8_t _s_lwip_fin(void * arg, struct tcp_pcb * tpcb, int8_t err);
static void _s_error(void *arg, int8_t err); static void _s_error(void * arg, int8_t err);
static int8_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len); static int8_t _s_sent(void * arg, struct tcp_pcb * tpcb, uint16_t len);
static int8_t _s_connected(void* arg, void* tpcb, int8_t err); static int8_t _s_connected(void * arg, void * tpcb, int8_t err);
static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg); static void _s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg);
int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err); int8_t _recv(tcp_pcb * pcb, pbuf * pb, int8_t err);
tcp_pcb * pcb(){ return _pcb; } tcp_pcb * pcb() {
return _pcb;
}
protected: protected:
tcp_pcb* _pcb; bool _connect(ip_addr_t addr, uint16_t port);
int8_t _closed_slot;
tcp_pcb * _pcb;
int8_t _closed_slot;
AcConnectHandler _connect_cb; AcConnectHandler _connect_cb;
void* _connect_cb_arg; void * _connect_cb_arg;
AcConnectHandler _discard_cb; AcConnectHandler _discard_cb;
void* _discard_cb_arg; void * _discard_cb_arg;
AcAckHandler _sent_cb; AcAckHandler _sent_cb;
void* _sent_cb_arg; void * _sent_cb_arg;
AcErrorHandler _error_cb; AcErrorHandler _error_cb;
void* _error_cb_arg; void * _error_cb_arg;
AcDataHandler _recv_cb; AcDataHandler _recv_cb;
void* _recv_cb_arg; void * _recv_cb_arg;
AcPacketHandler _pb_cb; AcPacketHandler _pb_cb;
void* _pb_cb_arg; void * _pb_cb_arg;
AcTimeoutHandler _timeout_cb; AcTimeoutHandler _timeout_cb;
void* _timeout_cb_arg; void * _timeout_cb_arg;
AcConnectHandler _poll_cb; AcConnectHandler _poll_cb;
void* _poll_cb_arg; void * _poll_cb_arg;
bool _pcb_busy; bool _pcb_busy;
uint32_t _pcb_sent_at; uint32_t _pcb_sent_at;
bool _ack_pcb; bool _ack_pcb;
uint32_t _rx_ack_len; uint32_t _rx_ack_len;
uint32_t _rx_last_packet; uint32_t _rx_last_packet;
uint32_t _rx_since_timeout; uint32_t _rx_since_timeout;
@@ -170,47 +184,51 @@ class AsyncClient {
uint16_t _connect_port; uint16_t _connect_port;
int8_t _close(); int8_t _close();
void _free_closed_slot(); void _free_closed_slot();
void _allocate_closed_slot(); void _allocate_closed_slot();
int8_t _connected(void* pcb, int8_t err); int8_t _connected(void * pcb, int8_t err);
void _error(int8_t err); void _error(int8_t err);
int8_t _poll(tcp_pcb* pcb); int8_t _poll(tcp_pcb * pcb);
int8_t _sent(tcp_pcb* pcb, uint16_t len); int8_t _sent(tcp_pcb * pcb, uint16_t len);
int8_t _fin(tcp_pcb* pcb, int8_t err); int8_t _fin(tcp_pcb * pcb, int8_t err);
int8_t _lwip_fin(tcp_pcb* pcb, int8_t err); int8_t _lwip_fin(tcp_pcb * pcb, int8_t err);
void _dns_found(struct ip_addr *ipaddr); void _dns_found(struct ip_addr * ipaddr);
public: public:
AsyncClient* prev; AsyncClient * prev;
AsyncClient* next; AsyncClient * next;
}; };
class AsyncServer { class AsyncServer {
public: public:
AsyncServer(IPAddress addr, uint16_t port); AsyncServer(IPAddress addr, uint16_t port);
AsyncServer(IPv6Address addr, uint16_t port);
AsyncServer(uint16_t port); AsyncServer(uint16_t port);
~AsyncServer(); ~AsyncServer();
void onClient(AcConnectHandler cb, void* arg); void onClient(AcConnectHandler cb, void * arg);
void begin(); void begin();
void end(); void end();
void setNoDelay(bool nodelay); void setNoDelay(bool nodelay);
bool getNoDelay(); bool getNoDelay();
uint8_t status(); uint8_t status();
//Do not use any of the functions below! //Do not use any of the functions below!
static int8_t _s_accept(void *arg, tcp_pcb* newpcb, int8_t err); static int8_t _s_accept(void * arg, tcp_pcb * newpcb, int8_t err);
static int8_t _s_accepted(void *arg, AsyncClient* client); static int8_t _s_accepted(void * arg, AsyncClient * client);
protected: protected:
uint16_t _port; uint16_t _port;
IPAddress _addr; bool _bind4 = false;
bool _noDelay; bool _bind6 = false;
tcp_pcb* _pcb; IPAddress _addr;
IPv6Address _addr6;
bool _noDelay;
tcp_pcb * _pcb;
AcConnectHandler _connect_cb; AcConnectHandler _connect_cb;
void* _connect_cb_arg; void * _connect_cb_arg;
int8_t _accept(tcp_pcb* newpcb, int8_t err); int8_t _accept(tcp_pcb * newpcb, int8_t err);
int8_t _accepted(AsyncClient* client); int8_t _accepted(AsyncClient * client);
}; };

View File

@@ -321,7 +321,7 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u
free(buf); free(buf);
return 0; return 0;
} }
outLen = sprintf_P((char*)buf+headLen, PSTR("%x"), readLen) + headLen; outLen = snprintf_P((char*)buf+headLen, sizeof(buf)-headLen-2, PSTR("%x"), readLen) + headLen;
while(outLen < headLen + 4) buf[outLen++] = ' '; while(outLen < headLen + 4) buf[outLen++] = ' ';
buf[outLen++] = '\r'; buf[outLen++] = '\r';
buf[outLen++] = '\n'; buf[outLen++] = '\n';

View File

@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2015 Marvin Roger Copyright (c) 2015-2021 Marvin Roger
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -6,14 +6,16 @@ AsyncMqttClient::AsyncMqttClient()
, _tail(nullptr) , _tail(nullptr)
, _sent(0) , _sent(0)
, _state(DISCONNECTED) , _state(DISCONNECTED)
, _tlsBadFingerprint(false) , _disconnectReason(AsyncMqttClientDisconnectReason::TCP_DISCONNECTED)
, _lastClientActivity(0) , _lastClientActivity(0)
, _lastServerActivity(0) , _lastServerActivity(0)
, _lastPingRequestTime(0) , _lastPingRequestTime(0)
, _generatedClientId{0} , _generatedClientId{0}
, _ip() , _ip()
, _ipv6()
, _host(nullptr) , _host(nullptr)
, _useIp(false) , _useIp(false)
, _useIpv6(false)
#if ASYNC_TCP_SSL_ENABLED #if ASYNC_TCP_SSL_ENABLED
, _secure(false) , _secure(false)
#endif #endif
@@ -111,16 +113,33 @@ AsyncMqttClient& AsyncMqttClient::setWill(const char* topic, uint8_t qos, bool r
} }
AsyncMqttClient& AsyncMqttClient::setServer(IPAddress ip, uint16_t port) { AsyncMqttClient& AsyncMqttClient::setServer(IPAddress ip, uint16_t port) {
_useIp = true; _useIp = true;
_ip = ip; _useIpv6 = false;
_port = port; _ip = ip;
_port = port;
return *this;
}
AsyncMqttClient& AsyncMqttClient::setServer(IPv6Address ipv6, uint16_t port) {
_useIpv6 = true;
_useIp = false;
_ipv6 = ipv6;
_port = port;
return *this; return *this;
} }
AsyncMqttClient& AsyncMqttClient::setServer(const char* host, uint16_t port) { AsyncMqttClient& AsyncMqttClient::setServer(const char* host, uint16_t port) {
_useIp = false; _port = port;
_host = host; _useIp = false;
_port = port; _useIpv6 = false;
_host = host;
if (_ipv6.fromString(host)) {
_useIpv6 = true;
_useIp = false;
} else if (_ip.fromString(host)) {
_useIpv6 = false;
_useIp = true;
}
return *this; return *this;
} }
@@ -175,11 +194,12 @@ void AsyncMqttClient::_freeCurrentParsedPacket() {
void AsyncMqttClient::_clear() { void AsyncMqttClient::_clear() {
_lastPingRequestTime = 0; _lastPingRequestTime = 0;
_tlsBadFingerprint = false;
_freeCurrentParsedPacket(); _freeCurrentParsedPacket();
_clearQueue(true); // keep session data for now _clearQueue(true); // keep session data for now
_parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::NONE; _parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::NONE;
_client.setRxTimeout(0);
} }
/* TCP */ /* TCP */
@@ -198,7 +218,7 @@ void AsyncMqttClient::_onConnect() {
} }
if (!sslFoundFingerprint) { if (!sslFoundFingerprint) {
_tlsBadFingerprint = true; _disconnectReason = AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT;
_client.close(true); _client.close(true);
return; return;
} }
@@ -222,17 +242,10 @@ void AsyncMqttClient::_onConnect() {
void AsyncMqttClient::_onDisconnect() { void AsyncMqttClient::_onDisconnect() {
log_i("TCP disconn"); log_i("TCP disconn");
_state = DISCONNECTED; _state = DISCONNECTED;
AsyncMqttClientDisconnectReason reason;
if (_tlsBadFingerprint) {
reason = AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT;
} else {
reason = AsyncMqttClientDisconnectReason::TCP_DISCONNECTED;
}
_clear(); _clear();
for (auto callback : _onDisconnectUserCallbacks) callback(reason); for (auto callback : _onDisconnectUserCallbacks) callback(_disconnectReason);
} }
/* /*
@@ -267,6 +280,7 @@ void AsyncMqttClient::_onData(char* data, size_t len) {
case AsyncMqttClientInternals::PacketType.CONNACK: case AsyncMqttClientInternals::PacketType.CONNACK:
log_i("rcv CONNACK"); log_i("rcv CONNACK");
_currentParsedPacket = new AsyncMqttClientInternals::ConnAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onConnAck, this, std::placeholders::_1, std::placeholders::_2)); _currentParsedPacket = new AsyncMqttClientInternals::ConnAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onConnAck, this, std::placeholders::_1, std::placeholders::_2));
_client.setRxTimeout(0);
break; break;
case AsyncMqttClientInternals::PacketType.PINGRESP: case AsyncMqttClientInternals::PacketType.PINGRESP:
log_i("rcv PINGRESP"); log_i("rcv PINGRESP");
@@ -519,6 +533,8 @@ void AsyncMqttClient::_onConnAck(bool sessionPresent, uint8_t connectReturnCode)
for (auto callback : _onConnectUserCallbacks) callback(sessionPresent); for (auto callback : _onConnectUserCallbacks) callback(sessionPresent);
} else { } else {
// Callbacks are handled by the onDisconnect function which is called from the AsyncTcp lib // Callbacks are handled by the onDisconnect function which is called from the AsyncTcp lib
_disconnectReason = static_cast<AsyncMqttClientDisconnectReason>(connectReturnCode);
return;
} }
_handleQueue(); // send any remaining data from continued session _handleQueue(); // send any remaining data from continued session
} }
@@ -688,6 +704,9 @@ void AsyncMqttClient::connect() {
if (_state != DISCONNECTED) return; if (_state != DISCONNECTED) return;
log_i("CONNECTING"); log_i("CONNECTING");
_state = CONNECTING; _state = CONNECTING;
_disconnectReason = AsyncMqttClientDisconnectReason::TCP_DISCONNECTED; // reset any previous
_client.setRxTimeout(_keepAlive);
#if ASYNC_TCP_SSL_ENABLED #if ASYNC_TCP_SSL_ENABLED
if (_useIp) { if (_useIp) {
@@ -698,6 +717,8 @@ void AsyncMqttClient::connect() {
#else #else
if (_useIp) { if (_useIp) {
_client.connect(_ip, _port); _client.connect(_ip, _port);
} else if (_useIpv6) {
_client.connect(_ipv6, _port);
} else { } else {
_client.connect(_host, _port); _client.connect(_host, _port);
} }
@@ -744,6 +765,12 @@ uint16_t AsyncMqttClient::publish(const char* topic, uint8_t qos, bool retain, c
return msg->packetId(); return msg->packetId();
} }
bool AsyncMqttClient::clearQueue() {
if (_state != DISCONNECTED) return false;
_clearQueue(false);
return true;
}
const char* AsyncMqttClient::getClientId() const { const char* AsyncMqttClient::getClientId() const {
return _clientId; return _clientId;
} }

View File

@@ -62,6 +62,7 @@ class AsyncMqttClient {
AsyncMqttClient& setCredentials(const char* username, const char* password = nullptr); AsyncMqttClient& setCredentials(const char* username, const char* password = nullptr);
AsyncMqttClient& setWill(const char* topic, uint8_t qos, bool retain, const char* payload = nullptr, size_t length = 0); AsyncMqttClient& setWill(const char* topic, uint8_t qos, bool retain, const char* payload = nullptr, size_t length = 0);
AsyncMqttClient& setServer(IPAddress ip, uint16_t port); AsyncMqttClient& setServer(IPAddress ip, uint16_t port);
AsyncMqttClient& setServer(IPv6Address ipv6, uint16_t port);
AsyncMqttClient& setServer(const char* host, uint16_t port); AsyncMqttClient& setServer(const char* host, uint16_t port);
#if ASYNC_TCP_SSL_ENABLED #if ASYNC_TCP_SSL_ENABLED
AsyncMqttClient& setSecure(bool secure); AsyncMqttClient& setSecure(bool secure);
@@ -81,6 +82,7 @@ class AsyncMqttClient {
uint16_t subscribe(const char* topic, uint8_t qos); uint16_t subscribe(const char* topic, uint8_t qos);
uint16_t unsubscribe(const char* topic); uint16_t unsubscribe(const char* topic);
uint16_t publish(const char* topic, uint8_t qos, bool retain, const char* payload = nullptr, size_t length = 0, bool dup = false, uint16_t message_id = 0); uint16_t publish(const char* topic, uint8_t qos, bool retain, const char* payload = nullptr, size_t length = 0, bool dup = false, uint16_t message_id = 0);
bool clearQueue(); // Not MQTT compliant!
const char* getClientId() const; const char* getClientId() const;
@@ -95,15 +97,17 @@ class AsyncMqttClient {
DISCONNECTING, DISCONNECTING,
DISCONNECTED DISCONNECTED
} _state; } _state;
bool _tlsBadFingerprint; AsyncMqttClientDisconnectReason _disconnectReason;
uint32_t _lastClientActivity; uint32_t _lastClientActivity;
uint32_t _lastServerActivity; uint32_t _lastServerActivity;
uint32_t _lastPingRequestTime; uint32_t _lastPingRequestTime;
char _generatedClientId[18 + 1]; // esp8266-abc123 and esp32-abcdef123456 char _generatedClientId[18 + 1]; // esp8266-abc123 and esp32-abcdef123456
IPAddress _ip; IPAddress _ip;
IPv6Address _ipv6;
const char* _host; const char* _host;
bool _useIp; bool _useIp;
bool _useIpv6;
#if ASYNC_TCP_SSL_ENABLED #if ASYNC_TCP_SSL_ENABLED
bool _secure; bool _secure;
#endif #endif

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
enum class AsyncMqttClientDisconnectReason : int8_t { enum class AsyncMqttClientDisconnectReason : uint8_t {
TCP_DISCONNECTED = 0, TCP_DISCONNECTED = 0,
MQTT_UNACCEPTABLE_PROTOCOL_VERSION = 1, MQTT_UNACCEPTABLE_PROTOCOL_VERSION = 1,

View File

@@ -10,7 +10,6 @@ PubAckOutPacket::PubAckOutPacket(PendingAck pendingAck) {
_packetId = pendingAck.packetId; _packetId = pendingAck.packetId;
_data[2] = pendingAck.packetId >> 8; _data[2] = pendingAck.packetId >> 8;
_data[3] = pendingAck.packetId & 0xFF; _data[3] = pendingAck.packetId & 0xFF;
// _released = false;
if (packetType() == AsyncMqttClientInternals::PacketType.PUBREL || if (packetType() == AsyncMqttClientInternals::PacketType.PUBREL ||
packetType() == AsyncMqttClientInternals::PacketType.PUBREC) { packetType() == AsyncMqttClientInternals::PacketType.PUBREC) {
_released = false; _released = false;

View File

@@ -47,6 +47,7 @@ void APSettingsService::manageAP() {
void APSettingsService::startAP() { void APSettingsService::startAP() {
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask); WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
esp_wifi_set_bandwidth(ESP_IF_WIFI_AP, WIFI_BW_HT20);
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str()); WiFi.softAP(_state.ssid.c_str(), _state.password.c_str());
if (!_dnsServer) { if (!_dnsServer) {
IPAddress apIp = WiFi.softAPIP(); IPAddress apIp = WiFi.softAPIP();

View File

@@ -84,7 +84,7 @@ void MqttSettingsService::onMqttConnect(bool sessionPresent) {
} }
void MqttSettingsService::onMqttDisconnect(AsyncMqttClientDisconnectReason reason) { void MqttSettingsService::onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
// emsesp::EMSESP::logger().info(F("Disconnected from MQTT reason: %s"), (uint8_t)reason); // emsesp::EMSESP::logger().info(F("Disconnected from MQTT reason: %d"), (uint8_t)reason);
_disconnectReason = reason; _disconnectReason = reason;
_disconnectedAt = uuid::get_uptime(); _disconnectedAt = uuid::get_uptime();
} }
@@ -101,6 +101,7 @@ void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
switch (event) { switch (event) {
case SYSTEM_EVENT_STA_GOT_IP: case SYSTEM_EVENT_STA_GOT_IP:
case SYSTEM_EVENT_ETH_GOT_IP: case SYSTEM_EVENT_ETH_GOT_IP:
case SYSTEM_EVENT_GOT_IP6:
if (_state.enabled) { if (_state.enabled) {
// emsesp::EMSESP::logger().info(F("Network connection found, starting MQTT client")); // emsesp::EMSESP::logger().info(F("Network connection found, starting MQTT client"));
onConfigUpdated(); onConfigUpdated();
@@ -121,14 +122,13 @@ void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
} }
void MqttSettingsService::configureMqtt() { void MqttSettingsService::configureMqtt() {
// disconnect if currently connected
_mqttClient.disconnect();
// only connect if WiFi is connected and MQTT is enabled // only connect if WiFi is connected and MQTT is enabled
if (_state.enabled && emsesp::EMSESP::system_.network_connected()) { if (_state.enabled && emsesp::EMSESP::system_.network_connected()) {
_mqttClient.disconnect();
_mqttClient.setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port); _mqttClient.setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port);
if (_state.username.length() > 0) { if (_state.username.length() > 0) {
_mqttClient.setCredentials(retainCstr(_state.username.c_str(), &_retainedUsername), retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword)); _mqttClient.setCredentials(retainCstr(_state.username.c_str(), &_retainedUsername),
retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword));
} else { } else {
_mqttClient.setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword)); _mqttClient.setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword));
} }
@@ -138,8 +138,6 @@ void MqttSettingsService::configureMqtt() {
_mqttClient.setMaxTopicLength(_state.maxTopicLength); _mqttClient.setMaxTopicLength(_state.maxTopicLength);
_mqttClient.connect(); _mqttClient.connect();
} }
emsesp::EMSESP::dallassensor_.reload(); // added by Proddy for EMS-ESP
} }
void MqttSettings::read(MqttSettings & settings, JsonObject & root) { void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
@@ -163,8 +161,6 @@ void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
root["publish_time_sensor"] = settings.publish_time_sensor; root["publish_time_sensor"] = settings.publish_time_sensor;
root["mqtt_qos"] = settings.mqtt_qos; root["mqtt_qos"] = settings.mqtt_qos;
root["mqtt_retain"] = settings.mqtt_retain; root["mqtt_retain"] = settings.mqtt_retain;
root["dallas_format"] = settings.dallas_format;
root["bool_format"] = settings.bool_format;
root["ha_climate_format"] = settings.ha_climate_format; root["ha_climate_format"] = settings.ha_climate_format;
root["ha_enabled"] = settings.ha_enabled; root["ha_enabled"] = settings.ha_enabled;
root["nested_format"] = settings.nested_format; root["nested_format"] = settings.nested_format;
@@ -195,20 +191,17 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
newSettings.publish_time_other = root["publish_time_other"] | EMSESP_DEFAULT_PUBLISH_TIME; newSettings.publish_time_other = root["publish_time_other"] | EMSESP_DEFAULT_PUBLISH_TIME;
newSettings.publish_time_sensor = root["publish_time_sensor"] | EMSESP_DEFAULT_PUBLISH_TIME; newSettings.publish_time_sensor = root["publish_time_sensor"] | EMSESP_DEFAULT_PUBLISH_TIME;
newSettings.dallas_format = root["dallas_format"] | EMSESP_DEFAULT_DALLAS_FORMAT;
newSettings.bool_format = root["bool_format"] | EMSESP_DEFAULT_BOOL_FORMAT;
newSettings.ha_climate_format = root["ha_climate_format"] | EMSESP_DEFAULT_HA_CLIMATE_FORMAT; newSettings.ha_climate_format = root["ha_climate_format"] | EMSESP_DEFAULT_HA_CLIMATE_FORMAT;
newSettings.ha_enabled = root["ha_enabled"] | EMSESP_DEFAULT_HA_ENABLED; newSettings.ha_enabled = root["ha_enabled"] | EMSESP_DEFAULT_HA_ENABLED;
newSettings.nested_format = root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT; newSettings.nested_format = root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT;
newSettings.subscribe_format = root["subscribe_format"] | EMSESP_DEFAULT_SUBSCRIBE_FORMAT; newSettings.subscribe_format = root["subscribe_format"] | EMSESP_DEFAULT_SUBSCRIBE_FORMAT;
if (newSettings.mqtt_qos != settings.mqtt_qos) { if (newSettings.enabled != settings.enabled) {
emsesp::EMSESP::mqtt_.set_qos(newSettings.mqtt_qos);
changed = true; changed = true;
} }
if (newSettings.dallas_format != settings.dallas_format) { if (newSettings.mqtt_qos != settings.mqtt_qos) {
emsesp::EMSESP::mqtt_.dallas_format(newSettings.dallas_format); emsesp::EMSESP::mqtt_.set_qos(newSettings.mqtt_qos);
changed = true; changed = true;
} }

Some files were not shown because too many files have changed in this diff Show More