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
node_modules
/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/),
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
## Changed

View File

@@ -5,5 +5,3 @@
## Fixed
## 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
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.
3. Issues that are accepted should be marked with appropriate labels.
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.
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.
8. Feature requests that are not accompanied by a PR:
* could be closed immediately (denied).
* 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.
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.
3. Issues that are accepted should be marked with appropriate labels.
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.
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.
8. Feature requests that are not accompanied by a PR:
- could be closed immediately (denied).
- 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.
## 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.
- 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).
- Write/Change the code in your Fork for a new feature, bug fix, new sensor, optimization, etc.
- Ensure tests work.
- Create a Pull Request against the [**dev**](https://github.com/emsesp/EMS-ESP32/tree/dev) branch of EMS-ESP.
- 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).
- Write/Change the code in your Fork for a new feature, bug fix, new sensor, optimization, etc.
- Ensure tests work.
- 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.
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).
4. Only one feature/fix should be added per PR.
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.
6. All pull requests should undergo peer review by at least one contributor other than the creator, excepts for the owner.
7. All pull requests should consider updates to the documentation.
8. Pull requests that address an outstanding issue, particularly an issue deemed to be severe, should be given priority.
9. If a PR is accepted, then it should undergo review and updated based on the feedback provided, then merged.
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.
11. Pull requests that don't meet the above will be denied and closed.
2. Make sure code is formatting per the `.clang-format`.
3. Make sure any new code is clearly commented explaining what the function/logic does.
4. Only relevant files should be touched (Also beware if your editor has auto-formatting feature enabled).
5. Only one feature/fix should be added per PR.
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 undergo peer review by at least one contributor other than the creator, excepts for the owner.
8. All pull requests should consider updates to the documentation.
9. Pull requests that address an outstanding issue, particularly an issue deemed to be severe, should be given priority.
10. If a PR is accepted, then it should undergo review and updated based on the feedback provided, then merged.
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
@@ -92,7 +92,7 @@ More Examples:
References:
- https://www.conventionalcommits.org/
- <https://www.conventionalcommits.org/>
--------------------------------------
@@ -139,4 +139,4 @@ A __CLA__ enables a contributor to grant "inbound" rights to a project.
<Other>
<A table should be maintained for relating maintainers and components. When triaging, this is essential to figure out if someone in particular should be consulted about specific changes.>
<A stable release cadence should be established, e.g.: every month.>
<A stable release cadence should be established, e.g.: every month.>

View File

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

View File

@@ -1,6 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x1F0000,
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xE000, 0x2000,
app0, app, ota_0, 0x10000, 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 WEB_SOCKET_ROOT = calculateWebSocketRoot('/ws/');
export const EVENT_SOURCE_ROOT = calculateEndpointRoot('/es/');
export const API_ENDPOINT_ROOT = calculateEndpointRoot('/api/');
function calculateEndpointRoot(endpointPath: string) {
const httpRoot = process.env.REACT_APP_HTTP_ROOT;

View File

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

View File

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

View File

@@ -51,7 +51,11 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
ssid: selectedNetwork.ssid,
password: '',
hostname: props.data.hostname,
static_ip_config: false
static_ip_config: false,
enableIPv6: false,
bandwidth20: false,
tx_power: 20,
nosleep: false
};
props.setData(networkSettings);
}
@@ -145,6 +149,53 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
onChange={handleValueChange('hostname')}
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
control={
<Checkbox
@@ -153,7 +204,7 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
onChange={handleValueChange('static_ip_config')}
/>
}
label="Static IP Config"
label="Use Static IPs"
/>
{data.static_ip_config && (
<Fragment>

View File

@@ -40,7 +40,22 @@ class NetworkStatusForm extends Component<NetworkStatusFormProps> {
if (!status.dns_ip_1) {
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() {
@@ -77,7 +92,7 @@ class NetworkStatusForm extends Component<NetworkStatusFormProps> {
<ListItemAvatar>
<Avatar>IP</Avatar>
</ListItemAvatar>
<ListItemText primary="IP Address" secondary={data.local_ip} />
<ListItemText primary="IP Address" secondary={this.IPs(data)} />
</ListItem>
<Divider variant="inset" component="li" />
<ListItem>

View File

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

View File

@@ -8,7 +8,7 @@ import { MenuAppBar } from '../components';
import { AuthenticatedRoute } from '../authentication';
import EMSESPStatusController from './EMSESPStatusController';
import EMSESPDevicesController from './EMSESPDevicesController';
import EMSESPDataController from './EMSESPDataController';
import EMSESPHelp from './EMSESPHelp';
class EMSESP extends Component<RouteComponentProps> {
@@ -24,18 +24,15 @@ class EMSESP extends Component<RouteComponentProps> {
onChange={(e, path) => this.handleTabChange(path)}
variant="fullWidth"
>
<Tab
value={`/${PROJECT_PATH}/devices`}
label="Devices &amp; Sensors"
/>
<Tab value={`/${PROJECT_PATH}/data`} label="Devices &amp; Sensors" />
<Tab value={`/${PROJECT_PATH}/status`} label="EMS Status" />
<Tab value={`/${PROJECT_PATH}/help`} label="EMS-ESP Help" />
</Tabs>
<Switch>
<AuthenticatedRoute
exact
path={`/${PROJECT_PATH}/devices`}
component={EMSESPDevicesController}
path={`/${PROJECT_PATH}/data`}
component={EMSESPDataController}
/>
<AuthenticatedRoute
exact
@@ -47,7 +44,7 @@ class EMSESP extends Component<RouteComponentProps> {
path={`/${PROJECT_PATH}/help`}
component={EMSESPHelp}
/>
<Redirect to={`/${PROJECT_PATH}/devices`} />
<Redirect to={`/${PROJECT_PATH}/data`} />
</Switch>
</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 {
EMSESPDevices,
EMSESPData,
EMSESPDeviceData,
Device,
DeviceValue,
DeviceValueUOM,
DeviceValueUOM_s
DeviceValueUOM_s,
Sensor
} from './EMSESPtypes';
import ValueForm from './ValueForm';
import SensorForm from './SensorForm';
import { ENDPOINT_ROOT } from '../api';
export const SCANDEVICES_ENDPOINT = ENDPOINT_ROOT + 'scanDevices';
export const DEVICE_DATA_ENDPOINT = ENDPOINT_ROOT + 'deviceData';
export const WRITE_VALUE_ENDPOINT = ENDPOINT_ROOT + 'writeValue';
export const WRITE_SENSOR_ENDPOINT = ENDPOINT_ROOT + 'writeSensor';
const StyledTableCell = withStyles((theme: Theme) =>
createStyles({
@@ -88,15 +91,16 @@ function compareDevices(a: Device, b: Device) {
return 0;
}
interface EMSESPDevicesFormState {
interface EMSESPDataFormState {
confirmScanDevices: boolean;
processing: boolean;
deviceData?: EMSESPDeviceData;
selectedDevice?: number;
edit_devicevalue?: DeviceValue;
edit_Sensor?: Sensor;
}
type EMSESPDevicesFormProps = RestFormProps<EMSESPDevices> &
type EMSESPDataFormProps = RestFormProps<EMSESPData> &
AuthenticatedContextProps &
WithWidthProps;
@@ -118,18 +122,27 @@ export const formatDuration = (duration_min: number) => {
const pluralize = (count: number, noun: string, suffix = 's') =>
` ${count} ${noun}${count !== 1 ? suffix : ''} `;
function formatValue(value: any, uom: number) {
function formatValue(value: any, uom: number, digit: number) {
switch (uom) {
case DeviceValueUOM.HOURS:
return value ? formatDuration(value * 60) : '0 hours';
case DeviceValueUOM.MINUTES:
return value ? formatDuration(value) : '0 minutes';
case DeviceValueUOM.NONE:
case DeviceValueUOM.LIST:
return value;
case DeviceValueUOM.NUM:
return new Intl.NumberFormat().format(value);
case DeviceValueUOM.BOOLEAN:
return value ? 'on' : 'off';
case DeviceValueUOM.DEGREES:
return (
new Intl.NumberFormat(undefined, {
minimumFractionDigits: digit
}).format(value) +
' ' +
DeviceValueUOM_s[uom]
);
default:
return (
new Intl.NumberFormat().format(value) + ' ' + DeviceValueUOM_s[uom]
@@ -137,16 +150,16 @@ function formatValue(value: any, uom: number) {
}
}
class EMSESPDevicesForm extends Component<
EMSESPDevicesFormProps,
EMSESPDevicesFormState
class EMSESPDataForm extends Component<
EMSESPDataFormProps,
EMSESPDataFormState
> {
state: EMSESPDevicesFormState = {
state: EMSESPDataFormState = {
confirmScanDevices: false,
processing: false
};
handleValueChange = (name: keyof DeviceValue) => (
handleDeviceValueChange = (name: keyof DeviceValue) => (
event: React.ChangeEvent<HTMLInputElement>
) => {
this.setState({
@@ -157,11 +170,11 @@ class EMSESPDevicesForm extends Component<
});
};
cancelEditingValue = () => {
cancelEditingDeviceValue = () => {
this.setState({ edit_devicevalue: undefined });
};
doneEditingValue = () => {
doneEditingDeviceValue = () => {
const { edit_devicevalue, selectedDevice } = this.state;
redirectingAuthorizedFetch(WRITE_VALUE_ENDPOINT, {
@@ -179,6 +192,7 @@ class EMSESPDevicesForm extends Component<
this.props.enqueueSnackbar('Write command sent to device', {
variant: 'success'
});
this.handleRowClick(selectedDevice);
} else if (response.status === 204) {
this.props.enqueueSnackbar('Write command failed', {
variant: 'error'
@@ -206,6 +220,72 @@ class EMSESPDevicesForm extends Component<
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 = () => {
return this.props.data.devices.length === 0;
};
@@ -236,7 +316,7 @@ class EMSESPDevicesForm extends Component<
<TableRow
hover
key={device.id}
onClick={() => this.handleRowClick(device)}
onClick={() => this.handleRowClick(device.id)}
>
<TableCell>
<CustomTooltip
@@ -289,30 +369,49 @@ class EMSESPDevicesForm extends Component<
renderSensorItems() {
const { data } = this.props;
const me = this.props.authenticatedContext.me;
return (
<TableContainer>
<p></p>
<Typography variant="h6" color="primary" paragraph>
Dallas Sensors
Sensors
</Typography>
{!this.noSensors() && (
<Table size="small" padding="default">
<TableHead>
<TableRow>
<StyledTableCell
padding="checkbox"
style={{ width: 18 }}
></StyledTableCell>
<StyledTableCell>Sensor #</StyledTableCell>
<StyledTableCell align="center">ID</StyledTableCell>
<StyledTableCell align="left">ID / Name</StyledTableCell>
<StyledTableCell align="right">Temperature</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{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">
{sensorData.no}
</TableCell>
<TableCell align="center">{sensorData.id}</TableCell>
<TableCell align="left">{sensorData.id}</TableCell>
<TableCell align="right">
{formatValue(sensorData.temp, DeviceValueUOM.DEGREES)}
{formatValue(sensorData.temp, DeviceValueUOM.DEGREES, 1)}
</TableCell>
</TableRow>
))}
@@ -322,7 +421,7 @@ class EMSESPDevicesForm extends Component<
{this.noSensors() && (
<Box color="warning.main" p={0} mt={0} mb={0}>
<Typography variant="body1">
<i>no external temperature sensors were detected</i>
<i>no connected Dallas temperature sensors were detected</i>
</Typography>
</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() {
return (
<Dialog
@@ -396,10 +523,10 @@ class EMSESPDevicesForm extends Component<
};
handleRowClick = (device: any) => {
this.setState({ selectedDevice: device.id, deviceData: undefined });
this.setState({ selectedDevice: device, deviceData: undefined });
redirectingAuthorizedFetch(DEVICE_DATA_ENDPOINT, {
method: 'POST',
body: JSON.stringify({ id: device.id }),
body: JSON.stringify({ id: device }),
headers: {
'Content-Type': 'application/json'
}
@@ -475,7 +602,7 @@ class EMSESPDevicesForm extends Component<
{item.n}
</TableCell>
<TableCell padding="none" align="right">
{formatValue(item.v, item.u)}
{formatValue(item.v, item.u, 0)}
</TableCell>
</TableRow>
))}
@@ -495,13 +622,14 @@ class EMSESPDevicesForm extends Component<
}
render() {
const { edit_devicevalue } = this.state;
const { edit_devicevalue, edit_Sensor } = this.state;
return (
<Fragment>
<br></br>
{this.renderDeviceItems()}
{this.renderDeviceData()}
{this.renderSensorItems()}
{this.renderAnalog()}
<br></br>
<Box display="flex" flexWrap="wrap">
<Box flexGrow={1} padding={1}>
@@ -528,9 +656,17 @@ class EMSESPDevicesForm extends Component<
{edit_devicevalue && (
<ValueForm
devicevalue={edit_devicevalue}
onDoneEditing={this.doneEditingValue}
onCancelEditing={this.cancelEditingValue}
handleValueChange={this.handleValueChange}
onDoneEditing={this.doneEditingDeviceValue}
onCancelEditing={this.cancelEditingDeviceValue}
handleValueChange={this.handleDeviceValueChange}
/>
)}
{edit_Sensor && (
<SensorForm
sensor={edit_Sensor}
onDoneEditing={this.doneEditingSensor}
onCancelEditing={this.cancelEditingSensor}
handleSensorChange={this.handleSensorChange}
/>
)}
</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 {
Typography,
Box,
@@ -14,14 +14,40 @@ import CommentIcon from '@material-ui/icons/CommentTwoTone';
import MenuBookIcon from '@material-ui/icons/MenuBookTwoTone';
import GitHubIcon from '@material-ui/icons/GitHub';
import StarIcon from '@material-ui/icons/Star';
import ImportExportIcon from '@material-ui/icons/ImportExport';
import BugReportIcon from '@material-ui/icons/BugReportTwoTone';
import DownloadIcon from '@material-ui/icons/GetApp';
export const WebAPISystemSettings =
window.location.origin + '/api/system/settings';
export const WebAPISystemInfo = window.location.origin + '/api/system/info';
import { FormButton } from '../components';
import { API_ENDPOINT_ROOT } from '../api';
import { redirectingAuthorizedFetch } from '../authentication';
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() {
return (
<SectionContent title="EMS-ESP Help" titleGutter>
@@ -31,9 +57,9 @@ class EMSESPHelp extends Component {
<MenuBookIcon />
</ListItemAvatar>
<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">
{'official documentation'}&nbsp;website
{'online documentation'}
</Link>
</ListItemText>
</ListItem>
@@ -55,41 +81,36 @@ class EMSESPHelp extends Component {
<GitHubIcon />
</ListItemAvatar>
<ListItemText>
To report an issue or feature request go to{' '}
To report an issue or request a feature go to{' '}
<Link
href="https://github.com/emsesp/EMS-ESP32/issues/new/choose"
color="primary"
>
{'click here'}
</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'}
{'GitHub'}
</Link>
</ListItemText>
</ListItem>
</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}>
<Typography variant="h6">
EMS-ESP is free and open-source.

View File

@@ -32,7 +32,7 @@ import {
BlockFormControlLabel
} from '../components';
import { isIP, optional } from '../validators';
import { isIPv4, optional, isHostname, or } from '../validators';
import { EMSESPSettings } from './EMSESPtypes';
@@ -55,7 +55,10 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
};
componentDidMount() {
ValidatorForm.addValidationRule('isOptionalIP', optional(isIP));
ValidatorForm.addValidationRule(
'isOptionalIPorHost',
optional(or(isIPv4, isHostname))
);
}
changeBoardProfile = (event: React.ChangeEvent<HTMLSelectElement>) => {
@@ -109,15 +112,17 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
<ValidatorForm onSubmit={saveData}>
<Box bgcolor="info.main" p={2} mt={2} mb={2}>
<Typography variant="body1">
Adjust any of the EMS-ESP settings here. For help refer to the{' '}
<Link
target="_blank"
href="https://emsesp.github.io/docs/#/Configure-firmware32?id=ems-esp-settings"
color="primary"
>
{'online documentation'}
</Link>
.
<i>
Refer to the
<Link
target="_blank"
href="https://emsesp.github.io/docs/#/Configure-firmware32?id=ems-esp-settings"
color="primary"
>
{' documentation'}
</Link>
&nbsp;for information on each setting
</i>
</Typography>
</Box>
@@ -202,7 +207,7 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
<Typography variant="body2">
<i>
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>
</Typography>
</Box>
@@ -365,7 +370,7 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
<br></br>
<Typography variant="h6" color="primary">
Options
General Options
</Typography>
{data.led_gpio !== 0 && (
@@ -390,20 +395,10 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
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
control={
<Checkbox
@@ -414,6 +409,26 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
}
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
container
spacing={0}
@@ -443,6 +458,65 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
/>
</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>
<Typography variant="h6" color="primary">
Syslog
@@ -469,10 +543,10 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
>
<Grid item xs={5}>
<TextValidator
validators={['isOptionalIP']}
errorMessages={['Not a valid IP address']}
validators={['isOptionalIPorHost']}
errorMessages={['Not a valid IPv4 address or hostname']}
name="syslog_host"
label="IP"
label="Host"
fullWidth
variant="outlined"
value={data.syslog_host}
@@ -537,7 +611,7 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
'Max value is 10'
]}
name="syslog_mark_interval"
label="Mark Interval seconds (0=off)"
label="Mark Interval (seconds, 0=off)"
fullWidth
variant="outlined"
value={data.syslog_mark_interval}
@@ -554,7 +628,7 @@ class EMSESPSettingsForm extends Component<EMSESPSettingsFormProps> {
value="trace_raw"
/>
}
label="Output EMS telegrams in raw format"
label="Output EMS telegrams as hexadecimal bytes"
/>
</Grid>
)}

View File

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

View File

@@ -23,7 +23,7 @@ class ProjectMenu extends Component<ProjectProps> {
to="/ems-esp/"
selected={
path.startsWith('/ems-esp/status') ||
path.startsWith('/ems-esp/devices') ||
path.startsWith('/ems-esp/data') ||
path.startsWith('/ems-esp/help')
}
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>
<DialogContent dividers>
{devicevalue.u !== DeviceValueUOM.BOOLEAN && (
<OutlinedInput
id="outlined-adornment-value"
{devicevalue.u === DeviceValueUOM.LIST && (
<TextField
id="outlined-select-value"
select
value={devicevalue.v}
autoFocus
fullWidth
onChange={handleValueChange('v')}
endAdornment={
<InputAdornment position="end">
{DeviceValueUOM_s[devicevalue.u]}
</InputAdornment>
}
aria-describedby="outlined-value-helper-text"
inputProps={{
'aria-label': 'value'
}}
/>
variant="outlined"
>
{devicevalue.l.map((val) => (
<MenuItem value={val}>{val}</MenuItem>
))}
</TextField>
)}
{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 && (
<TextField
id="outlined-select-value"
id="selected-value"
select
value={devicevalue.v}
autoFocus
@@ -83,9 +95,7 @@ class ValueForm extends React.Component<ValueFormProps> {
<MenuItem value="false">off</MenuItem>
</TextField>
)}
<FormHelperText id="outlined-value-helper-text">
{devicevalue.n}
</FormHelperText>
<FormHelperText>{devicevalue.n}</FormHelperText>
<Box color="warning.main" p={0} pl={0} pr={0} mt={4} mb={0}>
<Typography variant="body2">
<i>

View File

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

View File

@@ -6,6 +6,8 @@ import { useWindowSize } from '../components';
interface LogEventConsoleProps {
events: LogEvent[];
compact: boolean;
level: number;
}
interface Offsets {
@@ -63,7 +65,9 @@ const useStyles = makeStyles((theme: Theme) => ({
const LogEventConsole: FC<LogEventConsoleProps> = (props) => {
useWindowSize();
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) => {
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);
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 + ']';
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 (
<Box id="log-window" className={classes.console}>
{events.map((e) => (
<div className={classes.entry}>
{filter_events.map((e) => (
<div className={classes.entry} key={e.i}>
<span>{e.t}</span>
<span className={styleLevel(e.l)}>{paddedLevelLabel(e.l)} </span>
<span>{paddedNameLabel(e.n)} </span>
{compact && <span>{paddedLevelLabel(e.l, compact)} </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>
</div>
))}

View File

@@ -3,22 +3,38 @@ import { Component } from 'react';
import {
restController,
RestControllerProps,
RestFormLoader,
SectionContent
SectionContent,
BlockFormControlLabel
} 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';
export const FETCH_LOG_ENDPOINT = ENDPOINT_ROOT + 'fetchLog';
export const LOG_SETTINGS_ENDPOINT = ENDPOINT_ROOT + 'logSettings';
export const LOG_EVENT_EVENT_SOURCE_URL = EVENT_SOURCE_ROOT + 'log';
import LogEventForm from './LogEventForm';
import LogEventConsole from './LogEventConsole';
import { LogEvent, LogSettings } from './types';
import { LogEvent, LogSettings, LogLevel } from './types';
import { Decoder } from '@msgpack/msgpack';
const decoder = new Decoder();
@@ -26,6 +42,9 @@ const decoder = new Decoder();
interface LogEventControllerState {
eventSource?: EventSource;
events: LogEvent[];
compact: boolean;
level: number;
max_messages: number;
}
type LogEventControllerProps = RestControllerProps<LogSettings>;
@@ -40,12 +59,15 @@ class LogEventController extends Component<
constructor(props: LogEventControllerProps) {
super(props);
this.state = {
events: []
events: [],
compact: false,
level: 6,
max_messages: 25
};
}
componentDidMount() {
this.props.loadData();
this.fetchValues();
this.fetchLog();
this.configureEventSource();
}
@@ -59,6 +81,15 @@ class LogEventController extends Component<
}
}
changeCompact = (
event: React.ChangeEvent<HTMLInputElement>,
checked: boolean
) => {
this.setState({
compact: checked
});
};
fetchLog = () => {
fetch(FETCH_LOG_ENDPOINT)
.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 = () => {
this.eventSource = new EventSource(
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() {
const { saveData } = this.props;
return (
<SectionContent title="System Log" id="log-window">
<RestFormLoader
{...this.props}
render={(formProps) => <LogEventForm {...formProps} />}
<ValidatorForm onSubmit={saveData}>
<Grid
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>
);
}

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 {
t: string;
l: LogLevel;
i: number;
n: string;
m: string;
}

View File

@@ -3,3 +3,4 @@ export { default as isIP } from './isIP';
export { default as optional } from './optional';
export { default as or } from './or';
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) {
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
=======================
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)
-------

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://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)
@@ -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)
* Deduplicates strings
* 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 [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 [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 Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/?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 [`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 [`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 [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
* 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`
* [Header-only library](https://en.wikipedia.org/wiki/Header-only)
* 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)
* [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)
* Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/)
* Well documented
* [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)
* [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)
* [Troubleshooter](https://arduinojson.org/v6/troubleshooter/?utm_source=github&utm_medium=readme)
* [Book](https://arduinojson.org/book/?utm_source=github&utm_medium=readme)
* [Changelog](CHANGELOG.md)
* 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)
* [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)
## 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?
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"
#if !ARDUINOJSON_DEBUG
#ifdef __clang__
#pragma clang system_header
#elif defined __GNUC__
#pragma GCC system_header
#endif
# ifdef __clang__
# pragma clang system_header
# elif defined __GNUC__
# pragma GCC system_header
# endif
#endif
#include "ArduinoJson/Array/ArrayRef.hpp"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -155,7 +155,6 @@ class TextFormatter {
protected:
CountingDecorator<TWriter> _writer;
size_t _length;
private:
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
// Garbage in => Garbage out
#if defined(__GNUC__)
#if __GNUC__ >= 7
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
# if __GNUC__ >= 7
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
# endif
#endif
namespace ARDUINOJSON_NAMESPACE {
@@ -31,7 +31,7 @@ inline bool isLowSurrogate(uint16_t codeunit) {
class Codepoint {
public:
Codepoint() : _highSurrogate(0) {}
Codepoint() : _highSurrogate(0), _codepoint(0) {}
bool append(uint16_t codeunit) {
if (isHighSurrogate(codeunit)) {
@@ -61,7 +61,7 @@ class Codepoint {
} // namespace ARDUINOJSON_NAMESPACE
#if defined(__GNUC__)
#if __GNUC__ >= 8
#pragma GCC diagnostic pop
#endif
# if __GNUC__ >= 8
# pragma GCC diagnostic pop
# endif
#endif

View File

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

View File

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

View File

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

View File

@@ -5,13 +5,13 @@
#pragma once
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wconversion"
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic push
#endif
#pragma GCC diagnostic ignored "-Wconversion"
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
# pragma GCC diagnostic push
# endif
# pragma GCC diagnostic ignored "-Wconversion"
#endif
#include <ArduinoJson/Numbers/Float.hpp>
@@ -71,9 +71,23 @@ canConvertNumber(TIn) {
}
// int32 -> uint32
// int32 -> uint64
template <typename TOut, typename TIn>
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
canConvertNumber(TIn value) {
if (value < 0)
@@ -99,9 +113,9 @@ TOut convertNumber(TIn value) {
} // namespace ARDUINOJSON_NAMESPACE
#if defined(__clang__)
#pragma clang diagnostic pop
# pragma clang diagnostic pop
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic pop
#endif
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
# pragma GCC diagnostic pop
# endif
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,15 +5,16 @@
#pragma once
#include "integral_constant.hpp"
#include "is_same.hpp"
#include "remove_cv.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename>
struct is_floating_point : false_type {};
template <class T>
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

View File

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

View File

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

View File

@@ -5,33 +5,24 @@
#pragma once
#include "integral_constant.hpp"
#include "is_same.hpp"
#include "remove_cv.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename>
struct is_unsigned : false_type {};
template <>
struct is_unsigned<bool> : true_type {};
template <>
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 {};
// clang-format off
template <typename T>
struct is_unsigned : integral_constant<bool,
is_same<typename remove_cv<T>::type, unsigned char>::value ||
is_same<typename remove_cv<T>::type, unsigned short>::value ||
is_same<typename remove_cv<T>::type, unsigned int>::value ||
is_same<typename remove_cv<T>::type, unsigned long>::value ||
#if ARDUINOJSON_HAS_INT64
template <>
struct is_unsigned<unsigned __int64> : true_type {};
is_same<typename remove_cv<T>::type, unsigned __int64>::value ||
#endif
#if ARDUINOJSON_HAS_LONG_LONG
template <>
struct is_unsigned<unsigned long long> : true_type {};
is_same<typename remove_cv<T>::type, unsigned long long>::value ||
#endif
is_same<typename remove_cv<T>::type, bool>::value> {};
// clang-format on
} // 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>
#if ARDUINOJSON_ENABLE_STD_STRING
#include <ArduinoJson/Serialization/Writers/StdStringWriter.hpp>
# include <ArduinoJson/Serialization/Writers/StdStringWriter.hpp>
#endif
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp>
# include <ArduinoJson/Serialization/Writers/ArduinoStringWriter.hpp>
#endif
#if ARDUINOJSON_ENABLE_STD_STREAM
#include <ArduinoJson/Serialization/Writers/StdStreamWriter.hpp>
# include <ArduinoJson/Serialization/Writers/StdStreamWriter.hpp>
#endif
#if ARDUINOJSON_ENABLE_ARDUINO_PRINT
#include <ArduinoJson/Serialization/Writers/PrintWriter.hpp>
# include <ArduinoJson/Serialization/Writers/PrintWriter.hpp>
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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>
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <Arduino.h>
# include <Arduino.h>
#endif
#if ARDUINOJSON_ENABLE_STD_STRING
#include <string>
# include <string>
#endif
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
#include <ArduinoJson/Strings/ConstRamStringAdapter.hpp>
#include <ArduinoJson/Strings/IsString.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
namespace ARDUINOJSON_NAMESPACE {
class String {
@@ -53,25 +49,4 @@ class String {
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

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
#include <ArduinoJson/Strings/ConstRamStringAdapter.hpp>
#include <ArduinoJson/Strings/RamStringAdapter.hpp>
#include <ArduinoJson/Strings/SizedRamStringAdapter.hpp>
#include <ArduinoJson/Strings/Adapters/ConstRamStringAdapter.hpp>
#include <ArduinoJson/Strings/Adapters/JsonStringAdapter.hpp>
#include <ArduinoJson/Strings/Adapters/RamStringAdapter.hpp>
#include <ArduinoJson/Strings/Adapters/SizedRamStringAdapter.hpp>
#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
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
#include <ArduinoJson/Strings/ArduinoStringAdapter.hpp>
# include <ArduinoJson/Strings/Adapters/ArduinoStringAdapter.hpp>
#endif
#if ARDUINOJSON_ENABLE_PROGMEM
#include <ArduinoJson/Strings/FlashStringAdapter.hpp>
#include <ArduinoJson/Strings/SizedFlashStringAdapter.hpp>
# include <ArduinoJson/Strings/Adapters/FlashStringAdapter.hpp>
# include <ArduinoJson/Strings/Adapters/SizedFlashStringAdapter.hpp>
#endif

View File

@@ -9,4 +9,9 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename T, typename Enable = void>
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

View File

@@ -12,9 +12,9 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename T, typename Enable>
struct Converter {
static bool toJson(const T& src, VariantRef dst) {
static void toJson(const T& src, VariantRef dst) {
// 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
}
@@ -38,13 +38,11 @@ template <typename T>
struct Converter<
T, typename enable_if<is_integral<T>::value && !is_same<bool, T>::value &&
!is_same<char, T>::value>::type> {
static bool toJson(T src, VariantRef dst) {
static void toJson(T src, VariantRef dst) {
VariantData* data = getData(dst);
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
if (!data)
return false;
data->setInteger(src);
return true;
if (data)
data->setInteger(src);
}
static T fromJson(VariantConstRef src) {
@@ -61,8 +59,8 @@ struct Converter<
template <typename T>
struct Converter<T, typename enable_if<is_enum<T>::value>::type> {
static bool toJson(T src, VariantRef dst) {
return dst.set(static_cast<Integer>(src));
static void toJson(T src, VariantRef dst) {
dst.set(static_cast<Integer>(src));
}
static T fromJson(VariantConstRef src) {
@@ -78,12 +76,10 @@ struct Converter<T, typename enable_if<is_enum<T>::value>::type> {
template <>
struct Converter<bool> {
static bool toJson(bool src, VariantRef dst) {
static void toJson(bool src, VariantRef dst) {
VariantData* data = getData(dst);
if (!data)
return false;
data->setBoolean(src);
return true;
if (data)
data->setBoolean(src);
}
static bool fromJson(VariantConstRef src) {
@@ -99,12 +95,10 @@ struct Converter<bool> {
template <typename T>
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);
if (!data)
return false;
data->setFloat(static_cast<Float>(src));
return true;
if (data)
data->setFloat(static_cast<Float>(src));
}
static T fromJson(VariantConstRef src) {
@@ -120,8 +114,8 @@ struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> {
template <>
struct Converter<const char*> {
static bool toJson(const char* src, VariantRef dst) {
return variantSetString(getData(dst), adaptString(src), getPool(dst));
static void toJson(const char* src, VariantRef dst) {
variantSetString(getData(dst), adaptString(src), getPool(dst));
}
static const char* fromJson(VariantConstRef src) {
@@ -163,12 +157,10 @@ canConvertFromJson(VariantConstRef src, const T&) {
template <>
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);
if (!data)
return false;
data->setLinkedRaw(src);
return true;
if (data)
data->setLinkedRaw(src);
}
};
@@ -178,10 +170,11 @@ struct Converter<SerializedValue<const char*> > {
template <typename T>
struct Converter<SerializedValue<T>,
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);
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 <>
struct Converter<decltype(nullptr)> {
static bool toJson(decltype(nullptr), VariantRef dst) {
static void toJson(decltype(nullptr), VariantRef dst) {
variantSetNull(getData(dst));
return true;
}
static decltype(nullptr) fromJson(VariantConstRef) {
return nullptr;
@@ -247,20 +239,33 @@ class MemoryPoolPrint : public Print {
size_t _capacity;
};
inline bool convertToJson(const ::Printable& src, VariantRef dst) {
inline void convertToJson(const ::Printable& src, VariantRef dst) {
MemoryPool* pool = getPool(dst);
VariantData* data = getData(dst);
if (!pool || !data)
return false;
return;
MemoryPoolPrint print(pool);
src.printTo(print);
if (print.overflowed()) {
pool->markAsOverflowed();
data->setNull();
return false;
return;
}
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

View File

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

View File

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

View File

@@ -140,4 +140,9 @@ inline VariantConstRef operator|(VariantConstRef preferedValue,
VariantConstRef 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

View File

@@ -85,18 +85,18 @@ class VariantRef : public VariantRefBase<VariantData>,
template <typename T>
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")
set(char value) const {
return set<signed char>(value);
}
set(char value) const;
template <typename T>
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>
@@ -341,16 +341,22 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
template <>
struct Converter<VariantRef> {
static bool toJson(VariantRef src, VariantRef dst) {
return variantCopyFrom(getData(dst), getData(src), getPool(dst));
static void toJson(VariantRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static VariantRef fromJson(VariantRef src) {
return src;
}
static InvalidConversion<VariantConstRef, VariantRef> fromJson(
VariantConstRef);
static bool checkJson(VariantRef src) {
VariantData *data = getData(src);
return !!data;
}
static bool checkJson(VariantConstRef) {
return false;
}
@@ -358,8 +364,8 @@ struct Converter<VariantRef> {
template <>
struct Converter<VariantConstRef> {
static bool toJson(VariantConstRef src, VariantRef dst) {
return variantCopyFrom(getData(dst), getData(src), getPool(dst));
static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static VariantConstRef fromJson(VariantConstRef src) {

View File

@@ -4,7 +4,7 @@
#pragma once
#define ARDUINOJSON_VERSION "6.18.0"
#define ARDUINOJSON_VERSION "6.18.3"
#define ARDUINOJSON_VERSION_MAJOR 6
#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_
#include "IPAddress.h"
#include "IPv6Address.h"
#include "sdkconfig.h"
#include <functional>
extern "C" {
#include "freertos/semphr.h"
#include "lwip/pbuf.h"
#include "freertos/semphr.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
#ifndef CONFIG_ASYNC_TCP_RUNNING_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
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_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*, size_t len, uint32_t time)> AcAckHandler;
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*, struct pbuf *pb)> AcPacketHandler;
typedef std::function<void(void*, AsyncClient*, uint32_t time)> AcTimeoutHandler;
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 *, int8_t error)> AcErrorHandler;
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 *, uint32_t time)> AcTimeoutHandler;
struct tcp_pcb;
struct ip_addr;
class AsyncClient {
public:
AsyncClient(tcp_pcb* pcb = 0);
AsyncClient(tcp_pcb * pcb = 0);
~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) {
return !(*this == other);
bool operator!=(const AsyncClient & other) {
return !(*this == other);
}
bool connect(IPAddress ip, uint16_t port);
bool connect(const char* host, uint16_t port);
void close(bool now = false);
void stop();
bool connect(IPAddress ip, uint16_t port);
bool connect(IPv6Address ip, uint16_t port);
bool connect(const char * host, uint16_t port);
void close(bool now = false);
void stop();
int8_t abort();
bool free();
bool free();
bool canSend();//ack is not pending
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
bool send();//send all data added with the method above
bool canSend(); //ack is not pending
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
bool send(); //send all data added with the method above
//write equals add()+send()
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 write(const char * data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); //only when canSend() == true
uint8_t state();
bool connecting();
bool connected();
bool disconnecting();
bool disconnected();
bool freeable();//disconnected or disconnecting
bool connecting();
bool connected();
bool disconnecting();
bool disconnected();
bool freeable(); //disconnected or disconnecting
uint16_t getMss();
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();
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);
bool getNoDelay();
uint32_t getRemoteAddress();
uint16_t getRemotePort();
uint32_t getLocalAddress();
uint16_t getLocalPort();
uint32_t getRemoteAddress();
ip6_addr_t getRemoteAddress6();
uint16_t getRemotePort();
uint32_t getLocalAddress();
ip6_addr_t getLocalAddress6();
uint16_t getLocalPort();
//compatibility
IPAddress remoteIP();
uint16_t remotePort();
IPAddress localIP();
uint16_t localPort();
IPAddress remoteIP();
IPv6Address remoteIP6();
uint16_t remotePort();
IPAddress localIP();
IPv6Address localIP6();
uint16_t localPort();
void onConnect(AcConnectHandler cb, void* arg = 0); //on successful connect
void onDisconnect(AcConnectHandler cb, void* arg = 0); //disconnected
void onAck(AcAckHandler cb, void* arg = 0); //ack received
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 onPacket(AcPacketHandler cb, void* arg = 0); //data received
void onTimeout(AcTimeoutHandler cb, void* arg = 0); //ack timeout
void onPoll(AcConnectHandler cb, void* arg = 0); //every 125ms when connected
void onConnect(AcConnectHandler cb, void * arg = 0); //on successful connect
void onDisconnect(AcConnectHandler cb, void * arg = 0); //disconnected
void onAck(AcAckHandler cb, void * arg = 0); //ack received
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 onPacket(AcPacketHandler cb, void * arg = 0); //data received
void onTimeout(AcTimeoutHandler cb, void * arg = 0); //ack timeout
void onPoll(AcConnectHandler cb, void * arg = 0); //every 125ms when connected
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
void ackLater(){ _ack_pcb = false; } //will not ack the current packet. Call from onData
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
void ackLater() {
_ack_pcb = false;
} //will not ack the current packet. Call from onData
const char * errorToString(int8_t error);
const char * stateToString();
//Do not use any of the functions below!
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_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 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 void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg);
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_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 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 void _s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg);
int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err);
tcp_pcb * pcb(){ return _pcb; }
int8_t _recv(tcp_pcb * pcb, pbuf * pb, int8_t err);
tcp_pcb * pcb() {
return _pcb;
}
protected:
tcp_pcb* _pcb;
int8_t _closed_slot;
bool _connect(ip_addr_t addr, uint16_t port);
tcp_pcb * _pcb;
int8_t _closed_slot;
AcConnectHandler _connect_cb;
void* _connect_cb_arg;
void * _connect_cb_arg;
AcConnectHandler _discard_cb;
void* _discard_cb_arg;
AcAckHandler _sent_cb;
void* _sent_cb_arg;
AcErrorHandler _error_cb;
void* _error_cb_arg;
AcDataHandler _recv_cb;
void* _recv_cb_arg;
AcPacketHandler _pb_cb;
void* _pb_cb_arg;
void * _discard_cb_arg;
AcAckHandler _sent_cb;
void * _sent_cb_arg;
AcErrorHandler _error_cb;
void * _error_cb_arg;
AcDataHandler _recv_cb;
void * _recv_cb_arg;
AcPacketHandler _pb_cb;
void * _pb_cb_arg;
AcTimeoutHandler _timeout_cb;
void* _timeout_cb_arg;
void * _timeout_cb_arg;
AcConnectHandler _poll_cb;
void* _poll_cb_arg;
void * _poll_cb_arg;
bool _pcb_busy;
bool _pcb_busy;
uint32_t _pcb_sent_at;
bool _ack_pcb;
bool _ack_pcb;
uint32_t _rx_ack_len;
uint32_t _rx_last_packet;
uint32_t _rx_since_timeout;
@@ -170,48 +184,52 @@ class AsyncClient {
uint16_t _connect_port;
int8_t _close();
void _free_closed_slot();
void _allocate_closed_slot();
int8_t _connected(void* pcb, int8_t err);
void _error(int8_t err);
int8_t _poll(tcp_pcb* pcb);
int8_t _sent(tcp_pcb* pcb, uint16_t len);
int8_t _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 _free_closed_slot();
void _allocate_closed_slot();
int8_t _connected(void * pcb, int8_t err);
void _error(int8_t err);
int8_t _poll(tcp_pcb * pcb);
int8_t _sent(tcp_pcb * pcb, uint16_t len);
int8_t _fin(tcp_pcb * pcb, int8_t err);
int8_t _lwip_fin(tcp_pcb * pcb, int8_t err);
void _dns_found(struct ip_addr * ipaddr);
public:
AsyncClient* prev;
AsyncClient* next;
AsyncClient * prev;
AsyncClient * next;
};
class AsyncServer {
public:
AsyncServer(IPAddress addr, uint16_t port);
AsyncServer(IPv6Address addr, uint16_t port);
AsyncServer(uint16_t port);
~AsyncServer();
void onClient(AcConnectHandler cb, void* arg);
void begin();
void end();
void setNoDelay(bool nodelay);
bool getNoDelay();
void onClient(AcConnectHandler cb, void * arg);
void begin();
void end();
void setNoDelay(bool nodelay);
bool getNoDelay();
uint8_t status();
//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_accepted(void *arg, AsyncClient* client);
static int8_t _s_accept(void * arg, tcp_pcb * newpcb, int8_t err);
static int8_t _s_accepted(void * arg, AsyncClient * client);
protected:
uint16_t _port;
IPAddress _addr;
bool _noDelay;
tcp_pcb* _pcb;
uint16_t _port;
bool _bind4 = false;
bool _bind6 = false;
IPAddress _addr;
IPv6Address _addr6;
bool _noDelay;
tcp_pcb * _pcb;
AcConnectHandler _connect_cb;
void* _connect_cb_arg;
void * _connect_cb_arg;
int8_t _accept(tcp_pcb* newpcb, int8_t err);
int8_t _accepted(AsyncClient* client);
int8_t _accept(tcp_pcb * newpcb, int8_t err);
int8_t _accepted(AsyncClient * client);
};
#endif /* ASYNCTCP_H_ */
#endif /* ASYNCTCP_H_ */

View File

@@ -321,7 +321,7 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u
free(buf);
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++] = ' ';
buf[outLen++] = '\r';
buf[outLen++] = '\n';

View File

@@ -1,6 +1,6 @@
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
of this software and associated documentation files (the "Software"), to deal

View File

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

View File

@@ -62,6 +62,7 @@ class AsyncMqttClient {
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& setServer(IPAddress ip, uint16_t port);
AsyncMqttClient& setServer(IPv6Address ipv6, uint16_t port);
AsyncMqttClient& setServer(const char* host, uint16_t port);
#if ASYNC_TCP_SSL_ENABLED
AsyncMqttClient& setSecure(bool secure);
@@ -81,6 +82,7 @@ class AsyncMqttClient {
uint16_t subscribe(const char* topic, uint8_t qos);
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);
bool clearQueue(); // Not MQTT compliant!
const char* getClientId() const;
@@ -95,15 +97,17 @@ class AsyncMqttClient {
DISCONNECTING,
DISCONNECTED
} _state;
bool _tlsBadFingerprint;
AsyncMqttClientDisconnectReason _disconnectReason;
uint32_t _lastClientActivity;
uint32_t _lastServerActivity;
uint32_t _lastPingRequestTime;
char _generatedClientId[18 + 1]; // esp8266-abc123 and esp32-abcdef123456
IPAddress _ip;
IPv6Address _ipv6;
const char* _host;
bool _useIp;
bool _useIpv6;
#if ASYNC_TCP_SSL_ENABLED
bool _secure;
#endif

View File

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

View File

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

View File

@@ -47,6 +47,7 @@ void APSettingsService::manageAP() {
void APSettingsService::startAP() {
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());
if (!_dnsServer) {
IPAddress apIp = WiFi.softAPIP();

View File

@@ -84,7 +84,7 @@ void MqttSettingsService::onMqttConnect(bool sessionPresent) {
}
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;
_disconnectedAt = uuid::get_uptime();
}
@@ -101,6 +101,7 @@ void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
switch (event) {
case SYSTEM_EVENT_STA_GOT_IP:
case SYSTEM_EVENT_ETH_GOT_IP:
case SYSTEM_EVENT_GOT_IP6:
if (_state.enabled) {
// emsesp::EMSESP::logger().info(F("Network connection found, starting MQTT client"));
onConfigUpdated();
@@ -121,14 +122,13 @@ void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
}
void MqttSettingsService::configureMqtt() {
// disconnect if currently connected
_mqttClient.disconnect();
// only connect if WiFi is connected and MQTT is enabled
if (_state.enabled && emsesp::EMSESP::system_.network_connected()) {
_mqttClient.disconnect();
_mqttClient.setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port);
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 {
_mqttClient.setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword));
}
@@ -138,8 +138,6 @@ void MqttSettingsService::configureMqtt() {
_mqttClient.setMaxTopicLength(_state.maxTopicLength);
_mqttClient.connect();
}
emsesp::EMSESP::dallassensor_.reload(); // added by Proddy for EMS-ESP
}
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["mqtt_qos"] = settings.mqtt_qos;
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_enabled"] = settings.ha_enabled;
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_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_enabled = root["ha_enabled"] | EMSESP_DEFAULT_HA_ENABLED;
newSettings.nested_format = root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT;
newSettings.subscribe_format = root["subscribe_format"] | EMSESP_DEFAULT_SUBSCRIBE_FORMAT;
if (newSettings.mqtt_qos != settings.mqtt_qos) {
emsesp::EMSESP::mqtt_.set_qos(newSettings.mqtt_qos);
if (newSettings.enabled != settings.enabled) {
changed = true;
}
if (newSettings.dallas_format != settings.dallas_format) {
emsesp::EMSESP::mqtt_.dallas_format(newSettings.dallas_format);
if (newSettings.mqtt_qos != settings.mqtt_qos) {
emsesp::EMSESP::mqtt_.set_qos(newSettings.mqtt_qos);
changed = true;
}

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