Compare commits

...
Author SHA1 Message Date
ESPEasy release bot fda973bb78 automatically updated release notes for mega-20180802 2018-08-02 04:00:14 +02:00
GrovkillenandGitHub 402de69fd5 Added extra info to self compilers 2018-08-01 14:22:27 +02:00
ESPEasy release bot 41341b46de automatically updated release notes for mega-20180801 2018-08-01 04:00:18 +02:00
Gijs NoorlanderandGitHub 3574517014 Merge pull request #1618 from TD-er/bugfix/storage_task_settings
[#1574] Stability improvements on ExtraTaskSettings
2018-07-31 20:31:21 +02:00
Edwin Eefting cca785e1f0 Power down PN532 after reading. Saves power and reduces interference with Wifi. 2018-07-31 16:53:32 +02:00
TD-er 4215e058d0 [#1306] Added %R% and %N% for literals \r and \n 2018-07-30 22:41:25 +02:00
TD-er 2f91fbe931 [#1379] Check for "forbidden" characters in names. 2018-07-29 21:59:27 +02:00
TD-er 90febfd46f [#882] Add checks on names in task setup
When saving a task, a warning or error is displayed (when appropriate) when the settings are saved.
2018-07-29 21:59:18 +02:00
TD-er ccc5b68111 [Storage] Simplify settings I/O error handling
Remove a lot of code duplication
2018-07-29 21:59:13 +02:00
TD-er 07f6b86138 [Storage] Split storage related functions to new file
Only moved the storage related functions from `Misc.ino` to the new `ESPEasyStorage.ino`
2018-07-29 21:59:08 +02:00
TD-er 7b2667feaa [compiler fix] Forgot to declare String 2018-07-29 21:59:02 +02:00
TD-er 48bd7b334d [FileHandling] Write some log indicating file operation
Add some log line indicating what setting is read of written.
2018-07-29 21:58:57 +02:00
TD-er 9dd4242590 [meminfodetail] Add command meminfodetail
This command `meminfodetail` does output the detailed structure of the settings stored.
See for an example:
https://github.com/letscontrolit/ESPEasy/issues/1574#issuecomment-408641424
2018-07-29 21:58:51 +02:00
TD-er ac8c29e9c5 [ExtraTaskSettings] Keep ExtraTaskSettings actualized for plugin calls 2018-07-29 21:58:45 +02:00
TD-er 387b0f68a8 [ExtraTaskSettings] Added extra clear functions and checks
Mainly reading and writing files / settings now perform a lot more checks.
2018-07-29 21:58:38 +02:00
TD-er fa130bf649 [ExtraTaskSettings] Added some comments & clarifications 2018-07-29 21:58:31 +02:00
ESPEasy release bot e596403c0a automatically updated release notes for mega-20180723 2018-07-23 04:00:09 +02:00
Gijs NoorlanderandGitHub 1030bd0b0f Merge pull request #1603 from TD-er/bugfix/commands_with_space
[parseString] Some fixes and checks added + quotes in parameters possible
2018-07-23 01:09:52 +02:00
TD-er 985e463ddf [GetArgv] Add some C-array size checks
There was no check in size of the given C-array to write into.
2018-07-23 01:08:45 +02:00
TD-er 3787fa637a [Compiler warning] Initialize the matching_parenthesis to something
The variable is not used uninitialised, but still the compiler gives a warning which may trip Travis.
2018-07-22 23:47:18 +02:00
TD-er ac62eb40a0 [WebLogViewer] Removed reRunCount as quick fix for web log viewer 2018-07-22 23:41:32 +02:00
TD-er b9e883beba [GetArgv] Make sure only matching ", ' or [ is allowed
Added `'` as allowed "parenthesis" and make sure only the matching character is allowed as end of the string match.
2018-07-22 23:40:49 +02:00
TD-er 6281c002e0 [Travis CI] Signed/unsigned compare fix 2018-07-22 21:36:26 +02:00
TD-er 4e8a3cab2f [parseString] Add checks when command parameters used as int
Several usages of `parseString` were directly converted to int, without proper checking.
2018-07-22 17:23:29 +02:00
TD-er 423b90a661 [parseString] Use quotes to use special characters in command parameters
A command parameter may now allow for spaces or comma when the String is wrapped with either ' ' or " ".
2018-07-22 16:07:23 +02:00
TD-er 63fc99dd34 [parseString] Fix 1-of error in getParamStartPos
We need to find the xth command, so we need to find the position of the (X-1)th separator.

Too bad the rest of the world (other than programmers) do not start counting at 0 :(
2018-07-22 11:34:11 +02:00
ESPEasy release bot 71caf09c70 automatically updated release notes for mega-20180722 2018-07-22 04:00:08 +02:00
Gijs NoorlanderandGitHub ee3164a8f6 Merge pull request #1602 from TD-er/feature/LogLevelCheck
Feature/log level check
2018-07-22 02:58:21 +02:00
TD-er 3d5f612ac9 [Scheduler] Call yield() when idle
This makes the ESP do a lot more background tasks, which makes each yield() call shorter on average.
This makes the ESP feel more snappy.
2018-07-22 02:53:49 +02:00
TD-er 79f2eaf808 [Scheduler] Keep statistics on timeDiff computations
Apparently it is called 1.4 million times in 30 seconds and takes 8.5 CPU cycles on average (about 50'000 calls per second)
So maybe this function can benefit from some optimisation?
2018-07-22 02:39:02 +02:00
TD-er 1806a1438a [LogLevel] Added extra checks and make sure loglevel cache is up to date 2018-07-22 02:34:36 +02:00
TD-er 5108967c35 [LogLevel] Add checks for LOG_LEVEL_DEBUG_DEV 2018-07-22 01:31:14 +02:00
TD-er d0f1014bef [LogLevel] Add checks for LOG_LEVEL_DEBUG_MORE
Do not create Strings when not needed.
Highest level of checks added: LOG_LEVEL_DEBUG_MORE
2018-07-22 00:52:58 +02:00
TD-er 2afc143051 [LogLevel] Check loglevel before sending to log
Using template to do the check to prevent creation of Strings when required log level is higher than anyone is reading.
2018-07-21 23:54:51 +02:00
TD-er b2bf70e4ce [LogLevel] Use function to set loglevel and keep track of max log level 2018-07-21 23:32:37 +02:00
TD-er 6a5f090198 [LogLevel] LoadFromFile log to LOG_LEVEL_DEBUG_DEV 2018-07-21 22:56:08 +02:00
Gijs NoorlanderandGitHub 92c0543743 Merge pull request #1601 from TD-er/bugfix/logviewer_JavaScript
[Log Viewer] Fix a 1-off error when parsing logs
2018-07-21 21:29:30 +02:00
TD-er 1859aaad7d [Log Viewer] Fix a 1-off error when parsing logs 2018-07-21 21:27:23 +02:00
Gijs NoorlanderandGitHub 7e67ce536d Merge pull request #1594 from TD-er/bugfix/longpulse
[#1591] Move system timers to main scheduler
2018-07-21 21:19:32 +02:00
TD-er 2bd573963a [#1596] Remove timerSensor and make it set its own interval.
All enabled plugins have their own timer added to the scheduler.
The `PLUGIN_INIT` function call is used to reschedule when it was added, or enabled.
The set interval for the plugin will be used to set the new entry in the scheduler.
2018-07-21 01:28:14 +02:00
TD-er 447e958e74 [#1592] Remove systemCMDTimers
These timers were not used.
2018-07-20 21:52:49 +02:00
ESPEasy release bot 43908b37cd automatically updated release notes for mega-20180720 2018-07-20 04:00:16 +02:00
TD-er 04b631e4c9 [#1591] Move system timers to main scheduler
And fix longpulse command

With other plugins active, like the OLED Framed, the set period of `longpulse_ms` may fluctuate and durations below 100 msec are quite useless.

However, when running just a few sensors, the set pulse width is quite accurate.

Must still check a few other plugins.
2018-07-20 02:17:00 +02:00
Gijs NoorlanderandGitHub 2e8fc777d2 Merge pull request #1568 from TD-er/bugfix/1556_change_parse_params
[ParseString] Make ParseString more efficient and check results when used
2018-07-19 18:43:49 +02:00
ESPEasy release bot e060c83cf8 automatically updated release notes for mega-20180719 2018-07-19 04:00:14 +02:00
Gijs NoorlanderandGitHub 5480af2d5d Merge pull request #1587 from TD-er/feature/sunrise_sunset_offset
[sunrise/sunset] Allow offset from sunrise/sunset
2018-07-19 01:07:39 +02:00
TD-er ff28605d39 [sunrise/sunset] Allow offset from sunrise/sunset
`%sunrise%` and `%sunset%` were already available.
Now it is also possible to get some time before or after those times.
For example `%sunrise+10m%` or `%sunset-1h%`
The offset must be an integer (including + or -) and can have a postfix of "m" or "h".
Default is "s", for seconds.
2018-07-19 01:06:06 +02:00
Gijs NoorlanderandGitHub fe0ca9b9a3 Merge pull request #1584 from denisfrench/enable_clientid_is_name_without_unit
When clientid = %sysname%, only add %unit% if non-zero (#1155)
2018-07-18 21:17:06 +02:00
Gijs NoorlanderandGitHub 54ef70aee9 Merge pull request #1586 from beigenmann/mega
lib_archive already exists & Implicit dependency not found
2018-07-18 21:16:03 +02:00
Gijs NoorlanderandGitHub e24d077061 Merge pull request #1583 from clumsy-stefan/P077_fix
Fix for P077 crashes
2018-07-18 21:15:44 +02:00
Benno Eigenmann 7ebf29d857 lib_archive already exists & Implicit dependency not found 2018-07-18 14:02:01 +02:00
denisfrench 33c6925376 When clientid = %sysname%, only add %unit% if non-zero 2018-07-17 19:35:17 +10:00
stefan 0b383a1f3b Fix for P077 crashes
some code rearrangements and improvements:
- fix a rare buffer overflow
- only update variables when new (correct) values are received
- little speed-up
- correct code indentations...
2018-07-16 13:39:51 +02:00
stefan 70d1b0807c Merge remote-tracking branch 'origin/mega' into mega 2018-07-16 07:22:31 +02:00
ESPEasy release bot 8e1f4d628b automatically updated release notes for mega-20180716 2018-07-16 04:00:09 +02:00
Gijs NoorlanderandGitHub ef29603f05 Merge pull request #1581 from TD-er/feature/ESP32_partitiontable
[ESP32] Show partition table on sysinfo page
2018-07-16 00:59:50 +02:00
Gijs NoorlanderandGitHub 71b27d95fa Merge pull request #1562 from TD-er/bugfix/wifi_reset_empty_IP
[WiFi] Reset wifi when IP is set to 0.0.0.0
2018-07-16 00:58:31 +02:00
Gijs NoorlanderandGitHub 787c1c6c39 Merge pull request #1579 from TD-er/bugfix/scheduler_rewrite
[Scheduler] Complete rewrite of time based scheduling
2018-07-16 00:58:02 +02:00
Gijs NoorlanderandGitHub 74e4848edc Merge pull request #1578 from TD-er/bugfix/JSON_device_info
[JSON] Fixed broken JSON output on /json URL
2018-07-16 00:57:41 +02:00
TD-er 9a7690473a [ESP32] Show partition table on sysinfo page
Graphical display of partition table.
2018-07-16 00:49:30 +02:00
TD-er c401edde6b [ParseString] Fix getting the right part of the command line
Fix several 1-off errors.
Should drink more coffee ;)
2018-07-15 21:34:29 +02:00
TD-er 3fc1ba27e5 [JSON] Fixed broken JSON output on /json URL
This bug also broke the auto update of the sensor values on the device tab.
2018-07-15 20:23:11 +02:00
TD-er b2212d2edb [Scheduler] Complete rewrite of time based scheduling
All scheduled operations are now handled by a time scheduler.
Also the CPU load is now based entirely on the idle time found by this scheduler.
2018-07-15 20:21:37 +02:00
stefan 76f7dc82fc Merge branch 'bugfix/wifi_reset_empty_IP' into mega 2018-07-15 11:07:47 +02:00
ESPEasy release bot 86233b65bc automatically updated release notes for mega-20180714 2018-07-14 04:00:13 +02:00
Gijs NoorlanderandGitHub 984cfe23a0 Merge pull request #1569 from letscontrolit/bugfix/1567_uservarcheck
[#1567] Only check values set before sending
2018-07-13 10:35:25 +02:00
Gijs NoorlanderandGitHub 621087d48f [#1567] Only check values set before sending
Fix suggested by @s0170071 [here](https://github.com/letscontrolit/ESPEasy/issues/1567#issuecomment-404746920)
2018-07-13 09:21:42 +02:00
TD-er 00683a38c5 [ParseString] Make ParseString more efficient and check results before use
`ParseString` and `getParamStartPos` made (lots of) copies of the strings.
Also the result of `getParamStartPos` was not checked, which can result in crashes.
2018-07-13 08:09:42 +02:00
ESPEasy release bot 9336697f1a automatically updated release notes for mega-20180712 2018-07-12 04:00:12 +02:00
TD-er ad06cbc835 [WiFi] Reset wifi when IP is set to 0.0.0.0
As being described a few times and a screenshot shown here: https://github.com/letscontrolit/ESPEasy/issues/1302#issuecomment-393631572
It looks like a DHCP request may fail resulting in a cleared IP setup. The web server then still replies to requests, but no new connections can be made then.

This patch should detect such a situation and then reset the wifi and make a new connection.
2018-07-12 00:20:55 +02:00
Gijs NoorlanderandGitHub f5b026e678 Merge pull request #1561 from TD-er/bugfix/1542_domoticz_IDX
[#1542] Fix  Domoticz IDX more than 4 characters
2018-07-11 22:27:05 +02:00
TD-er e29eb2eb3c [#1542] Fix Domoticz IDX more than 4 characters
Looks like Domoticz uses an unsigned int, so it could be up-to 32 bits.
Just to be sure, I limited it now to 1 bln.
2018-07-11 22:26:05 +02:00
Gijs NoorlanderandGitHub 10329f4351 Merge pull request #1560 from TD-er/bugfix/send_to_controller
[#1555] Fix TSL2591 values are not transferred to controller
2018-07-11 22:08:13 +02:00
TD-er ab4750d5fa [#1555] Fix TSL2591 values are not transferred to controller
Also checked other plugins to see if they had the same issue and fixed a few other obvious switch-statement bugs.
2018-07-11 22:04:11 +02:00
55 changed files with 3095 additions and 1923 deletions
+1
View File
@@ -1,3 +1,4 @@
### If you self compile, please state this and PLEASE try to ONLY REPORT ISSUES WITH OFFICIAL BUILDS! ###
<!--- If you self compile, please state this and PLEASE try to ONLY REPORT ISSUES WITH OFFICIAL BUILDS! --->
<!--- NOTE: This is not a support forum! For questions and support go here: --->
<!--- https://www.letscontrolit.com/forum/viewforum.php?f=1 --->
+135
View File
@@ -1,3 +1,138 @@
-------------------------------------------------
Changes in release mega-20180802 (since mega-20180801)
-------------------------------------------------
Release date: Thu Aug 2 04:00:14 CEST 2018
Grovkillen (1):
Added extra info to self compilers
-------------------------------------------------
Changes in release mega-20180801 (since mega-20180723)
-------------------------------------------------
Release date: Wed Aug 1 04:00:18 CEST 2018
Edwin Eefting (1):
Power down PN532 after reading. Saves power and reduces interference with Wifi.
TD-er (11):
[ExtraTaskSettings] Added some comments & clarifications
[ExtraTaskSettings] Added extra clear functions and checks
[ExtraTaskSettings] Keep ExtraTaskSettings actualized for plugin calls
[meminfodetail] Add command `meminfodetail`
[FileHandling] Write some log indicating file operation
[compiler fix] Forgot to declare String
[Storage] Split storage related functions to new file
[Storage] Simplify settings I/O error handling
[#882] Add checks on names in task setup
[#1379] Check for "forbidden" characters in names.
[#1306] Added %R% and %N% for literals \r and \n
-------------------------------------------------
Changes in release mega-20180723 (since mega-20180722)
-------------------------------------------------
Release date: Mon Jul 23 04:00:09 CEST 2018
TD-er (8):
[parseString] Fix 1-of error in getParamStartPos
[parseString] Use quotes to use special characters in command parameters
[parseString] Add checks when command parameters used as int
[Travis CI] Signed/unsigned compare fix
[GetArgv] Make sure only matching ", ' or [ is allowed
[WebLogViewer] Removed reRunCount as quick fix for web log viewer
[Compiler warning] Initialize the matching_parenthesis to something
[GetArgv] Add some C-array size checks
-------------------------------------------------
Changes in release mega-20180722 (since mega-20180720)
-------------------------------------------------
Release date: Sun Jul 22 04:00:08 CEST 2018
TD-er (12):
[#1591] Move system timers to main scheduler
[#1592] Remove systemCMDTimers
[#1596] Remove timerSensor and make it set its own interval.
[Log Viewer] Fix a 1-off error when parsing logs
[LogLevel] LoadFromFile log to LOG_LEVEL_DEBUG_DEV
[LogLevel] Use function to set loglevel and keep track of max log level
[LogLevel] Check loglevel before sending to log
[LogLevel] Add checks for LOG_LEVEL_DEBUG_MORE
[LogLevel] Add checks for LOG_LEVEL_DEBUG_DEV
[LogLevel] Added extra checks and make sure loglevel cache is up to date
[Scheduler] Keep statistics on timeDiff computations
[Scheduler] Call yield() when idle
-------------------------------------------------
Changes in release mega-20180720 (since mega-20180719)
-------------------------------------------------
Release date: Fri Jul 20 04:00:16 CEST 2018
TD-er (2):
[ParseString] Make ParseString more efficient and check results before use
[ParseString] Fix getting the right part of the command line
-------------------------------------------------
Changes in release mega-20180719 (since mega-20180716)
-------------------------------------------------
Release date: Thu Jul 19 04:00:14 CEST 2018
Benno Eigenmann (1):
lib_archive already exists & Implicit dependency not found
TD-er (1):
[sunrise/sunset] Allow offset from sunrise/sunset
denisfrench (1):
When clientid = %sysname%, only add %unit% if non-zero
stefan (1):
Fix for P077 crashes
-------------------------------------------------
Changes in release mega-20180716 (since mega-20180714)
-------------------------------------------------
Release date: Mon Jul 16 04:00:09 CEST 2018
TD-er (4):
[WiFi] Reset wifi when IP is set to 0.0.0.0
[Scheduler] Complete rewrite of time based scheduling
[JSON] Fixed broken JSON output on /json URL
[ESP32] Show partition table on sysinfo page
-------------------------------------------------
Changes in release mega-20180714 (since mega-20180712)
-------------------------------------------------
Release date: Sat Jul 14 04:00:13 CEST 2018
Gijs Noorlander (1):
[#1567] Only check values set before sending
-------------------------------------------------
Changes in release mega-20180712 (since mega-20180710)
-------------------------------------------------
Release date: Thu Jul 12 04:00:12 CEST 2018
TD-er (2):
[#1555] Fix TSL2591 values are not transferred to controller
[#1542] Fix Domoticz IDX more than 4 characters
-------------------------------------------------
Changes in release mega-20180710 (since mega-20180708)
-------------------------------------------------
+17 -18
View File
@@ -70,7 +70,7 @@ platform = espressif32@1.1.1
platform = https://github.com/platformio/platform-espressif32.git#feature/stage
[core_esp32]
platform = ${core_esp32_1_1_1.platform}
platform = ${core_esp32_0_12_0.platform}
build_flags = -D BUILD_GIT='"${sysenv.TRAVIS_TAG}"'
-lstdc++ -lsupc++
lib_ignore = AS_BH1750, ESP8266WiFi, ESP8266Ping, ESP8266WebServer, ESP8266HTTPUpdateServer, ESP8266mDNS, IRremoteESP8266, ESPEasy_ESP8266Ping, SerialSensors
@@ -79,7 +79,7 @@ monitor_speed = 115200
[common]
build_flags = -D BUILD_GIT='"${sysenv.TRAVIS_TAG}"' ; ${compiler_warnings.build_flags}
build_flags = -D BUILD_GIT='"${sysenv.TRAVIS_TAG}"'
-D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
-D NDEBUG
-D VTABLES_IN_FLASH
@@ -183,7 +183,6 @@ lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
lib_archive = ${common.lib_archive}
framework = ${common.framework}
upload_speed = ${common.upload_speed}
monitor_speed = ${common.monitor_speed}
@@ -416,7 +415,7 @@ build_flags = ${esp8266_1M.build_flags} -D PLUGIN_BUILD_DEV -D FLA
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_build.flash_mode = ${Sonoff.board_build.flash_mode}
;board = ${Sonoff.board}
;build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_BASIC
@@ -430,7 +429,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_build.flash_mode = ${Sonoff.board_build.flash_mode}
;board = ${Sonoff.board}
;build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_TH10
@@ -444,7 +443,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_build.flash_mode = ${Sonoff.board_build.flash_mode}
;board = ${Sonoff.board}
;build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_TH16
@@ -498,7 +497,7 @@ build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_POW_R2
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_build.flash_mode = ${Sonoff.board_build.flash_mode}
;board = ${Sonoff.board}
;build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_S20
@@ -512,7 +511,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_build.flash_mode = ${Sonoff.board_build.flash_mode}
;board = ${Sonoff.board}
;build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_4CH
@@ -526,7 +525,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_build.flash_mode = ${Sonoff.board_build.flash_mode}
;board = ${Sonoff.board}
;build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_TOUCH
@@ -544,7 +543,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_upload.maximum_size = ${esp8266_1M.board_upload.maximum_size}
;board_build.flash_mode = ${esp8266_1M.board_build.flash_mode}
;board = esp01_1m
@@ -559,7 +558,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_upload.maximum_size = ${esp8266_1M.board_upload.maximum_size}
;board_build.flash_mode = ${esp8266_1M.board_build.flash_mode}
;board = esp01_1m
@@ -574,7 +573,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_upload.maximum_size = ${esp8266_1M.board_upload.maximum_size}
;board_build.flash_mode = ${esp8266_1M.board_build.flash_mode}
;board = esp01_1m
@@ -596,7 +595,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_upload.maximum_size = ${esp8266_1M.board_upload.maximum_size}
;board_build.flash_mode = ${esp8266_1M.board_build.flash_mode}
;board = esp01_1m
@@ -612,7 +611,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_upload.maximum_size = ${esp8266_1M.board_upload.maximum_size}
;board_build.flash_mode = ${esp8266_1M.board_build.flash_mode}
;board = esp01_1m
@@ -630,7 +629,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_upload.maximum_size = ${esp8266_1M.board_upload.maximum_size}
;board_build.flash_mode = ${esp8266_1M.board_build.flash_mode}
;board = esp01_1m
@@ -645,7 +644,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_upload.maximum_size = ${esp8266_1M.board_upload.maximum_size}
;board_build.flash_mode = ${esp8266_1M.board_build.flash_mode}
;board = esp01_1m
@@ -660,7 +659,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_upload.maximum_size = ${esp8266_1M.board_upload.maximum_size}
;board_build.flash_mode = ${esp8266_1M.board_build.flash_mode}
;board = esp01_1m
@@ -675,7 +674,7 @@ lib_archive = ${common.lib_archive}
;lib_deps = ${common.lib_deps}
;lib_ignore = ${common.lib_ignore}
;lib_ldf_mode = ${common.lib_ldf_mode}
lib_archive = ${common.lib_archive}
;lib_archive = ${common.lib_archive}
;board_upload.maximum_size = ${esp8266_1M.board_upload.maximum_size}
;board_build.flash_mode = ${esp8266_1M.board_build.flash_mode}
;board = esp01_1m
+70 -66
View File
@@ -25,96 +25,97 @@
\*********************************************************************************************/
bool doExecuteCommand(const char * cmd, struct EventStruct *event, const char* line) {
// Simple macro to match command to function call.
#define COMMAND_CASE(S,C) if (strcmp_P(cmd_lc, PSTR(S)) == 0) return (C(event,line));
String tmpcmd;
tmpcmd = cmd;
tmpcmd.toLowerCase();
String log = F("Command: ");
log += tmpcmd;
addLog(LOG_LEVEL_INFO, log);
char cmd_lc[INPUT_COMMAND_SIZE];
tmpcmd.toCharArray(cmd_lc, tmpcmd.length() + 1);
#define COMMAND_CASE(S,C) if (strcmp_P(cmd_lc, PSTR(S)) == 0) return (C(event,line));
String tmpcmd;
tmpcmd = cmd;
tmpcmd.toLowerCase();
String log = F("Command: ");
log += tmpcmd;
addLog(LOG_LEVEL_INFO, log);
char cmd_lc[INPUT_COMMAND_SIZE];
tmpcmd.toCharArray(cmd_lc, tmpcmd.length() + 1);
switch (cmd_lc[0]) {
case 'a': {
case 'a': {
COMMAND_CASE("accessinfo" , Command_AccessInfo_Ls); // Network Command
break;
}
case 'b': {
break;
}
case 'b': {
COMMAND_CASE("background" , Command_Background); // Diagnostic.h
#ifdef CPLUGIN_012
COMMAND_CASE("blynkget" , Command_Blynk_Get);
#endif
COMMAND_CASE("build" , Command_Settings_Build); // Settings.h
break;
}
case 'c': {
break;
}
case 'c': {
COMMAND_CASE("clearaccessblock" , Command_AccessInfo_Clear); // Network Command
COMMAND_CASE("clearrtcram" , Command_RTC_Clear); // RTC.h
COMMAND_CASE("config" , Command_Task_RemoteConfig); // Tasks.h
break;
}
case 'd': {
break;
}
case 'd': {
COMMAND_CASE("debug" , Command_Debug); // Diagnostic.h
COMMAND_CASE("deepsleep" , Command_System_deepSleep); // System.h
COMMAND_CASE("delay" , Command_Delay); // Timers.h
COMMAND_CASE("dns" , Command_DNS); // Network Command
COMMAND_CASE("dst" , Command_DST); // Time.h
break;
}
case 'e': {
break;
}
case 'e': {
COMMAND_CASE("erase" , Command_WiFi_Erase); // WiFi.h
COMMAND_CASE("event" , Command_Rules_Events); // Rule.h
COMMAND_CASE("executerules" , Command_Rules_Execute); // Rule.h
break;
}
case 'g': {
break;
}
case 'g': {
COMMAND_CASE("gateway" , Command_Gateway); // Network Command
break;
}
case 'i': {
break;
}
case 'i': {
COMMAND_CASE("i2cscanner" , Command_i2c_Scanner); // i2c.h
COMMAND_CASE("ip" , Command_IP); // Network Command
break;
}
case 'l': {
break;
}
case 'l': {
COMMAND_CASE("load" , Command_Settings_Load); // Settings.h
COMMAND_CASE("logentry" , Command_logentry); // Diagnostic.h
COMMAND_CASE("lowmem" , Command_Lowmem); // Diagnostic.h
break;
}
case 'm': {
break;
}
case 'm': {
COMMAND_CASE("malloc" , Command_Malloc); // Diagnostic.h
COMMAND_CASE("meminfo" , Command_MenInfo); // Diagnostic.h
COMMAND_CASE("meminfo" , Command_MemInfo); // Diagnostic.h
COMMAND_CASE("meminfodetail" , Command_MemInfo_detail); // Diagnostic.h
COMMAND_CASE("messagedelay" , Command_MQTT_messageDelay); // MQTT.h
COMMAND_CASE("mqttretainflag" , Command_MQTT_Retain); // MQTT.h
break;
}
case 'n': {
break;
}
case 'n': {
COMMAND_CASE("name" , Command_Settings_Name); // Settings.h
COMMAND_CASE("nosleep" , Command_System_NoSleep); // System.h
COMMAND_CASE("notify" , Command_Notifications_Notify); // Notifications.h
COMMAND_CASE("ntphost" , Command_NTPHost); // Time.h
break;
}
case 'p': {
break;
}
case 'p': {
COMMAND_CASE("password" , Command_Settings_Password); // Settings.h
COMMAND_CASE("publish" , Command_MQTT_Publish); // MQTT.h
break;
}
case 'r': {
break;
}
case 'r': {
COMMAND_CASE("reboot" , Command_System_Reboot); // System.h
COMMAND_CASE("reset" , Command_Settings_Reset); // Settings.h
COMMAND_CASE("resetflashwritecounter" , Command_RTC_resetFlashWriteCounter); // RTC.h
COMMAND_CASE("restart" , Command_System_Restart); // System.h
COMMAND_CASE("rules" , Command_Rules_UseRules); // Rule.h
break;
}
case 's': {
break;
}
case 's': {
COMMAND_CASE("save" , Command_Settings_Save); // Settings.h
#if FEATURE_SD
COMMAND_CASE("sdcard" , Command_SD_LS); // SDCARDS.h
COMMAND_CASE("sdremove" , Command_SD_Remove); // SDCARDS.h
COMMAND_CASE("sdremove" , Command_SD_Remove); // SDCARDS.h
#endif
COMMAND_CASE("sendto" , Command_UPD_SendTo); // UDP.h
COMMAND_CASE("sendtohttp" , Command_HTTP_SendToHTTP); // HTTP.h
@@ -123,9 +124,9 @@ bool doExecuteCommand(const char * cmd, struct EventStruct *event, const char* l
COMMAND_CASE("settings" , Command_Settings_Print); // Settings.h
COMMAND_CASE("subnet" , Command_Subnet); // Network Command
COMMAND_CASE("sysload" , Command_SysLoad); // Diagnostic.h
break;
}
case 't': {
break;
}
case 't': {
COMMAND_CASE("taskclear" , Command_Task_Clear); // Tasks.h
COMMAND_CASE("taskclearall" , Command_Task_ClearAll); // Tasks.h
COMMAND_CASE("taskrun" , Command_Task_Run); // Tasks.h
@@ -135,16 +136,16 @@ bool doExecuteCommand(const char * cmd, struct EventStruct *event, const char* l
COMMAND_CASE("timerresume" , Command_Timer_Resume); // Timers.h
COMMAND_CASE("timerset" , Command_Timer_Set); // Timers.h
COMMAND_CASE("timezone" , Command_TimeZone); // Time.h
break;
}
case 'u': {
break;
}
case 'u': {
COMMAND_CASE("udpport" , Command_UDP_Port); // UDP.h
COMMAND_CASE("udptest" , Command_UDP_Test); // UDP.h
COMMAND_CASE("unit" , Command_Settings_Unit); // Settings.h
COMMAND_CASE("usentp" , Command_useNTP); // Time.h
break;
}
case 'w': {
break;
}
case 'w': {
COMMAND_CASE("wdconfig" , Command_WD_Config); // WD.h
COMMAND_CASE("wdread" , Command_WD_Read); // WD.h
COMMAND_CASE("wifiapmode" , Command_Wifi_APMode); // WiFi.h
@@ -157,12 +158,15 @@ bool doExecuteCommand(const char * cmd, struct EventStruct *event, const char* l
COMMAND_CASE("wifissid" , Command_Wifi_SSID); // WiFi.h
COMMAND_CASE("wifissid2" , Command_Wifi_SSID2); // WiFi.h
COMMAND_CASE("wifistamode" , Command_Wifi_STAMode); // WiFi.h
break;
}
default:
break;
}
addLog(LOG_LEVEL_INFO, F("Command unknown"));
}
default:
break;
}
String errorUnknown = F("Command unknown: \"");
errorUnknown += cmd_lc;
errorUnknown += '\"';
addLog(LOG_LEVEL_INFO, errorUnknown);
return false;
#undef COMMAND_CASE
@@ -175,17 +179,17 @@ void ExecuteCommand(byte source, const char *Line)
boolean success = false;
char TmpStr1[INPUT_COMMAND_SIZE];
TmpStr1[0] = 0;
char cmd[INPUT_COMMAND_SIZE];
char cmd[INPUT_COMMAND_SIZE];
cmd[0] = 0;
struct EventStruct TempEvent;
TempEvent.Source = source;
TempEvent.Source = source;
GetArgv(Line, cmd, 1);
if (GetArgv(Line, TmpStr1, 2)) TempEvent.Par1 = str2int(TmpStr1);
if (GetArgv(Line, TmpStr1, 3)) TempEvent.Par2 = str2int(TmpStr1);
if (GetArgv(Line, TmpStr1, 4)) TempEvent.Par3 = str2int(TmpStr1);
if (GetArgv(Line, TmpStr1, 5)) TempEvent.Par4 = str2int(TmpStr1);
if (GetArgv(Line, TmpStr1, 6)) TempEvent.Par5 = str2int(TmpStr1);
success = doExecuteCommand((char*)&cmd[0], &TempEvent, Line);
yield();
+40 -10
View File
@@ -35,21 +35,51 @@ bool Command_SerialFloat(struct EventStruct *event, const char* Line)
pinMode(1, INPUT);
pinMode(3, INPUT);
delay(60000);
return success;
return success;
}
bool Command_MenInfo(struct EventStruct *event, const char* Line)
bool Command_MemInfo(struct EventStruct *event, const char* Line)
{
bool success = true;
Serial.print(F("SecurityStruct : "));
Serial.print(F("SecurityStruct | "));
Serial.println(sizeof(SecuritySettings));
Serial.print(F("SettingsStruct : "));
Serial.print(F("SettingsStruct | "));
Serial.println(sizeof(Settings));
Serial.print(F("ExtraTaskSettingsStruct: "));
Serial.print(F("ExtraTaskSettingsStruct| "));
Serial.println(sizeof(ExtraTaskSettings));
Serial.print(F("DeviceStruct: "));
Serial.print(F("DeviceStruct | "));
Serial.println(sizeof(Device));
return success;
return success;
}
bool Command_MemInfo_detail(struct EventStruct *event, const char* Line)
{
bool success = true;
Command_MemInfo(event, Line);
for (int st = 0; st < SettingsType_MAX; ++st) {
SettingsType settingsType = static_cast<SettingsType>(st);
int max_index, offset, max_size;
int struct_size = 0;
Serial.println();
Serial.print(getSettingsTypeString(settingsType));
Serial.println(F(" | start | end | max_size | struct_size"));
Serial.println(F("--- | --- | --- | --- | ---"));
getSettingsParameters(settingsType, 0, max_index, offset, max_size, struct_size);
for (int i = 0; i < max_index; ++i) {
getSettingsParameters(settingsType, i, offset, max_size);
Serial.print(i);
Serial.print('|');
Serial.print(offset);
Serial.print('|');
Serial.print(offset + max_size);
Serial.print('|');
Serial.print(max_size);
Serial.print('|');
Serial.println(struct_size);
}
}
return success;
}
bool Command_Background(struct EventStruct *event, const char* Line)
@@ -60,7 +90,7 @@ bool Command_Background(struct EventStruct *event, const char* Line)
while (!timeOutReached(timer))
backgroundtasks();
Serial.println(F("end"));
return success;
return success;
}
@@ -68,7 +98,7 @@ bool Command_Debug(struct EventStruct *event, const char* Line)
{
char TmpStr1[INPUT_COMMAND_SIZE];
if (GetArgv(Line, TmpStr1, 2)) {
Settings.SerialLogLevel = event->Par1;
setLogLevelFor(LOG_TO_SERIAL, event->Par1);
}
else{
Serial.println();
@@ -83,4 +113,4 @@ bool Command_logentry(struct EventStruct *event, const char* Line)
return true;
}
#endif // COMMAND_DIAGNOSTIC_H
#endif // COMMAND_DIAGNOSTIC_H
+16 -3
View File
@@ -8,8 +8,20 @@ bool Command_HTTP_SendToHTTP(struct EventStruct *event, const char* Line)
String strLine = Line;
String host = parseString(strLine, 2);
String port = parseString(strLine, 3);
int pathpos = getParamStartPos(strLine, 4);
String path = strLine.substring(pathpos);
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = F("SendToHTTP: Host: ");
log += host;
log += F(" port: ");
log += port;
addLog(LOG_LEVEL_DEBUG, log);
}
if (!isInt(port)) return false;
String path = parseStringToEndKeepCase(strLine, 4);
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = F("SendToHTTP: Path: ");
log += path;
addLog(LOG_LEVEL_DEBUG, log);
}
WiFiClient client;
if (client.connect(host.c_str(), port.toInt()))
{
@@ -20,6 +32,7 @@ bool Command_HTTP_SendToHTTP(struct EventStruct *event, const char* Line)
reply += host;
reply += F("\r\n");
reply += F("Connection: close\r\n\r\n");
addLog(LOG_LEVEL_DEBUG, reply);
client.print(reply);
unsigned long timer = millis() + 200;
@@ -43,4 +56,4 @@ bool Command_HTTP_SendToHTTP(struct EventStruct *event, const char* Line)
return true;
}
#endif // COMMAND_HTTP_H
#endif // COMMAND_HTTP_H
+7 -6
View File
@@ -5,6 +5,7 @@
bool Command_Task_Clear(struct EventStruct *event, const char* Line)
{
bool success = true;
// Par1 is here for 1 ... TASKS_MAX
taskClear(event->Par1 - 1, true);
return success;
}
@@ -12,13 +13,13 @@ bool Command_Task_Clear(struct EventStruct *event, const char* Line)
bool Command_Task_ClearAll(struct EventStruct *event, const char* Line)
{
bool success = true;
for (byte t=0; t<TASKS_MAX; t++)
for (byte t = 0; t < TASKS_MAX; t++)
taskClear(t, false);
return success;
}
bool Command_Task_ValueSet(struct EventStruct *event, const char* Line)
{
{
bool success = true;
char TmpStr1[INPUT_COMMAND_SIZE];
if (GetArgv(Line, TmpStr1, 4))
@@ -29,14 +30,14 @@ bool Command_Task_ValueSet(struct EventStruct *event, const char* Line)
}
else
{
//TODO: Get Task description and var name
//TODO: Get Task description and var name
Serial.println(UserVar[(VARS_PER_TASK * (event->Par1 - 1)) + event->Par2 - 1]);
}
return success;
}
bool Command_Task_ValueSetAndRun(struct EventStruct *event, const char* Line)
{
{
bool success = true;
char TmpStr1[INPUT_COMMAND_SIZE];
if (GetArgv(Line, TmpStr1, 4))
@@ -50,7 +51,7 @@ bool Command_Task_ValueSetAndRun(struct EventStruct *event, const char* Line)
}
bool Command_Task_Run(struct EventStruct *event, const char* Line)
{
{
bool success = true;
SensorSendTask(event->Par1 - 1);
return success;
@@ -64,4 +65,4 @@ bool Command_Task_RemoteConfig(struct EventStruct *event, const char* Line)
return true;
}
#endif // COMMAND_TASKS_H
#endif // COMMAND_TASKS_H
+5 -5
View File
@@ -39,12 +39,11 @@ bool Command_UDP_SendToUPD(struct EventStruct *event, const char* Line)
{
bool success = false;
if (wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED) {
success = true;
String strLine = Line;
String ip = parseString(strLine, 2);
String port = parseString(strLine, 3);
int msgpos = getParamStartPos(strLine, 4);
String message = strLine.substring(msgpos);
if (!isInt(port)) return success;
String message = parseStringToEndKeepCase(strLine, 4);
IPAddress UDP_IP;
if(UDP_IP.fromString(ip)) {
portUDP.beginPacket(UDP_IP, port.toInt());
@@ -56,8 +55,9 @@ bool Command_UDP_SendToUPD(struct EventStruct *event, const char* Line)
#endif
portUDP.endPacket();
}
success = true;
}
return success;
return success;
}
#endif // COMMAND_UDP_H
#endif // COMMAND_UDP_H
+16 -11
View File
@@ -60,7 +60,8 @@ void sendData(struct EventStruct *event)
}
boolean validUserVar(struct EventStruct *event) {
for (int i = 0; i < VARS_PER_TASK; ++i) {
byte valueCount = getValueCountFromSensorType(event->sensorType);
for (int i = 0; i < valueCount; ++i) {
const float f(UserVar[event->BaseVarIndex + i]);
if (!isValidFloat(f)) return false;
}
@@ -92,14 +93,16 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
c_payload[length] = 0;
/*
String log;
log=F("MQTT : Topic: ");
log+=c_topic;
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
String log;
log=F("MQTT : Topic: ");
log+=c_topic;
addLog(LOG_LEVEL_DEBUG_MORE, log);
log=F("MQTT : Payload: ");
log+=c_payload;
addLog(LOG_LEVEL_DEBUG_MORE, log);
log=F("MQTT : Payload: ");
log+=c_payload;
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
*/
// sprintf_P(log, PSTR("%s%s"), "MQTT : Topic: ", c_topic);
@@ -141,8 +144,10 @@ bool MQTTConnect(int controller_idx)
String clientid;
if(Settings.MQTTUseUnitNameAsClientId){
clientid = Settings.Name;
clientid += F("_");
clientid += Settings.Unit;
if (Settings.Unit != 0) { // only append non-zero unit number
clientid += F("_");
clientid += Settings.Unit;
}
}
else{
clientid = F("ESPClient_");
@@ -259,7 +264,7 @@ void SendStatus(byte source, String status)
boolean MQTTpublish(int controller_idx, const char* topic, const char* payload, boolean retained)
{
if (MQTTclient.publish(topic, payload, retained)) {
timermqtt = millis() + 10; // Make sure the MQTT is being processed as soon as possible.
setIntervalTimerOverride(TIMER_MQTT, 10); // Make sure the MQTT is being processed as soon as possible.
return true;
}
addLog(LOG_LEVEL_DEBUG, F("MQTT : publish failed"));
+235 -107
View File
@@ -196,6 +196,13 @@
#define NODE_TYPE_ID_ARDUINO_EASY_STD 65
#define NODE_TYPE_ID_NANO_EASY_STD 81
#define TIMER_20MSEC 1
#define TIMER_100MSEC 2
#define TIMER_1SEC 3
#define TIMER_30SEC 4
#define TIMER_MQTT 5
#define TIMER_STATISTICS 6
#define PLUGIN_INIT_ALL 1
#define PLUGIN_INIT 2
#define PLUGIN_READ 3
@@ -290,13 +297,12 @@
#define NPLUGIN_MAX 4
#define UNIT_MAX 32 // Only relevant for UDP unicast message 'sweeps' and the nodelist.
#define RULES_TIMER_MAX 8
#define SYSTEM_TIMER_MAX 8
#define SYSTEM_CMD_TIMER_MAX 2
#define PINSTATE_TABLE_MAX 32
#define RULES_MAX_SIZE 2048
#define RULES_MAX_NESTING_LEVEL 3
#define RULESETS_MAX 4
#define RULES_BUFFER_SIZE 64
#define NAME_FORMULA_LENGTH_MAX 40
#define PIN_MODE_UNDEFINED 0
#define PIN_MODE_INPUT 1
@@ -339,8 +345,9 @@
#define BOOT_CAUSE_DEEP_SLEEP 2
#define BOOT_CAUSE_EXT_WD 10
#define DAT_TASKS_SIZE 2048
#define DAT_TASKS_CUSTOM_OFFSET 1024
#define DAT_TASKS_DISTANCE 2048 // DAT_TASKS_SIZE + DAT_TASKS_CUSTOM_SIZE
#define DAT_TASKS_SIZE 1024
#define DAT_TASKS_CUSTOM_OFFSET 1024 // Equal to DAT_TASKS_SIZE
#define DAT_TASKS_CUSTOM_SIZE 1024
#define DAT_CUSTOM_CONTROLLER_SIZE 1024
#define DAT_CONTROLLER_SIZE 1024
@@ -359,6 +366,30 @@
#define CONFIG_FILE_SIZE 131072
#endif
enum SettingsType {
TaskSettings_Type = 0,
CustomTaskSettings_Type,
ControllerSettings_Type,
CustomControllerSettings_Type,
NotificationSettings_Type,
SettingsType_MAX
};
bool getSettingsParameters(SettingsType settingsType, int index, int& offset, int& max_size);
String getSettingsTypeString(SettingsType settingsType) {
switch (settingsType) {
case TaskSettings_Type: return F("TaskSettings");
case CustomTaskSettings_Type: return F("CustomTaskSettings");
case ControllerSettings_Type: return F("ControllerSettings");
case CustomControllerSettings_Type: return F("CustomControllerSettings");
case NotificationSettings_Type: return F("NotificationSettings");
default:
break;
}
return String();
}
/*
To modify the stock configuration without changing this repo file :
- define USE_CUSTOM_H as a build flags. ie : export PLATFORMIO_BUILD_FLAGS="'-DUSE_CUSTOM_H'"
@@ -373,6 +404,7 @@
#include "ESPEasyTimeTypes.h"
#include "I2CTypes.h"
#include <I2Cdev.h>
#include <map>
#define FS_NO_GLOBALS
#if defined(ESP8266)
@@ -575,48 +607,94 @@ struct SecurityStruct
struct SettingsStruct
{
SettingsStruct() :
PID(0), Version(0), Build(0), IP_Octet(0), Unit(0), Delay(0),
Pin_i2c_sda(-1), Pin_i2c_scl(-1), Pin_status_led(-1), Pin_sd_cs(-1),
UDPPort(0), SyslogLevel(0), SerialLogLevel(0), WebLogLevel(0), SDLogLevel(0),
BaudRate(0), MessageDelay(0), deepSleep(0),
CustomCSS(false), DST(false), WDI2CAddress(0),
UseRules(false), UseSerial(false), UseSSDP(false), UseNTP(false),
WireClockStretchLimit(0), GlobalSync(false), ConnectionFailuresThreshold(0),
TimeZone(0), MQTTRetainFlag(false), InitSPI(false),
Pin_status_led_Inversed(false), deepSleepOnFail(false), UseValueLogger(false),
DST_Start(0), DST_End(0), UseRTOSMultitasking(false), Pin_Reset(-1),
SyslogFacility(DEFAULT_SYSLOG_FACILITY), StructSize(0), MQTTUseUnitNameAsClientId(0)
{
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
Protocol[i] = 0;
ControllerEnabled[i] = false;
for (byte task = 0; task < TASKS_MAX; ++task) {
TaskDeviceID[i][task] = 0;
TaskDeviceSendData[i][task] = false;
}
}
for (byte task = 0; task < TASKS_MAX; ++task) {
TaskDeviceNumber[task] = 0;
OLD_TaskDeviceID[task] = 0;
TaskDevicePin1PullUp[task] = false;
for (byte cv = 0; cv < PLUGIN_CONFIGVAR_MAX; ++cv) {
TaskDevicePluginConfig[task][cv] = 0;
}
TaskDevicePin1Inversed[task] = false;
for (byte cv = 0; cv < PLUGIN_CONFIGFLOATVAR_MAX; ++cv) {
TaskDevicePluginConfigFloat[task][cv] = 0.0;
}
for (byte cv = 0; cv < PLUGIN_CONFIGLONGVAR_MAX; ++cv) {
TaskDevicePluginConfigLong[task][cv] = 0;
}
OLD_TaskDeviceSendData[task] = false;
TaskDeviceGlobalSync[task] = false;
TaskDeviceDataFeed[task] = 0;
TaskDeviceTimer[task] = 0;
TaskDeviceEnabled[task] = false;
}
SettingsStruct() {
clearAll();
}
void clearAll() {
PID = 0;
Version = 0;
Build = 0;
IP_Octet = 0;
Unit = 0;
Delay = 0;
Pin_i2c_sda = -1;
Pin_i2c_scl = -1;
Pin_status_led = -1;
Pin_sd_cs = -1;
UDPPort = 0;
SyslogLevel = 0;
SerialLogLevel = 0;
WebLogLevel = 0;
SDLogLevel = 0;
BaudRate = 0;
MessageDelay = 0;
deepSleep = 0;
CustomCSS = false;
DST = false;
WDI2CAddress = 0;
UseRules = false;
UseSerial = false;
UseSSDP = false;
UseNTP = false;
WireClockStretchLimit = 0;
GlobalSync = false;
ConnectionFailuresThreshold = 0;
TimeZone = 0;
MQTTRetainFlag = false;
InitSPI = false;
Pin_status_led_Inversed = false;
deepSleepOnFail = false;
UseValueLogger = false;
DST_Start = 0;
DST_End = 0;
UseRTOSMultitasking = false;
Pin_Reset = -1;
SyslogFacility = DEFAULT_SYSLOG_FACILITY;
StructSize = 0;
MQTTUseUnitNameAsClientId = 0;
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
Protocol[i] = 0;
ControllerEnabled[i] = false;
}
for (byte i = 0; i < NOTIFICATION_MAX; ++i) {
Notification[i] = 0;
NotificationEnabled[i] = false;
}
for (byte task = 0; task < TASKS_MAX; ++task) {
clearTask(task);
}
}
void clearTask(byte task) {
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
TaskDeviceID[i][task] = 0;
TaskDeviceSendData[i][task] = false;
}
TaskDeviceNumber[task] = 0;
OLD_TaskDeviceID[task] = 0;
TaskDevicePin1[task] = -1;
TaskDevicePin2[task] = -1;
TaskDevicePin3[task] = -1;
TaskDevicePort[task] = 0;
TaskDevicePin1PullUp[task] = false;
for (byte cv = 0; cv < PLUGIN_CONFIGVAR_MAX; ++cv) {
TaskDevicePluginConfig[task][cv] = 0;
}
TaskDevicePin1Inversed[task] = false;
for (byte cv = 0; cv < PLUGIN_CONFIGFLOATVAR_MAX; ++cv) {
TaskDevicePluginConfigFloat[task][cv] = 0.0;
}
for (byte cv = 0; cv < PLUGIN_CONFIGLONGVAR_MAX; ++cv) {
TaskDevicePluginConfigLong[task][cv] = 0;
}
OLD_TaskDeviceSendData[task] = false;
TaskDeviceGlobalSync[task] = false;
TaskDeviceDataFeed[task] = 0;
TaskDeviceTimer[task] = 0;
TaskDeviceEnabled[task] = false;
}
unsigned long PID;
int Version;
@@ -677,12 +755,12 @@ struct SettingsStruct
long TaskDevicePluginConfigLong[TASKS_MAX][PLUGIN_CONFIGLONGVAR_MAX];
boolean OLD_TaskDeviceSendData[TASKS_MAX];
boolean TaskDeviceGlobalSync[TASKS_MAX];
byte TaskDeviceDataFeed[TASKS_MAX];
byte TaskDeviceDataFeed[TASKS_MAX]; // When set to 0, only read local connected sensorsfeeds
unsigned long TaskDeviceTimer[TASKS_MAX];
boolean TaskDeviceEnabled[TASKS_MAX];
boolean ControllerEnabled[CONTROLLER_MAX];
boolean NotificationEnabled[NOTIFICATION_MAX];
unsigned int TaskDeviceID[CONTROLLER_MAX][TASKS_MAX];
unsigned int TaskDeviceID[CONTROLLER_MAX][TASKS_MAX]; // IDX number (mainly used by Domoticz)
boolean TaskDeviceSendData[CONTROLLER_MAX][TASKS_MAX];
boolean Pin_status_led_Inversed;
boolean deepSleepOnFail;
@@ -854,15 +932,26 @@ struct NotificationSettingsStruct
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
};
// This is only used by some plugins to store extra settings like formula descriptions.
// These settings can only be active for one plugin, meaning they have to be loaded
// over and over again from flash when another active plugin uses these values.
//FIXME @TD-er: Should think of another mechanism to make this more efficient.
struct ExtraTaskSettingsStruct
{
ExtraTaskSettingsStruct() : TaskIndex(0) {
TaskDeviceName[0] = 0;
ExtraTaskSettingsStruct() : TaskIndex(TASKS_MAX) {
clear();
}
void clear() {
TaskIndex = TASKS_MAX;
for (byte j = 0; j < (NAME_FORMULA_LENGTH_MAX + 1); ++j) {
TaskDeviceName[j] = 0;
}
for (byte i = 0; i < VARS_PER_TASK; ++i) {
for (byte j = 0; j < 41; ++j) {
for (byte j = 0; j < (NAME_FORMULA_LENGTH_MAX + 1); ++j) {
TaskDeviceFormula[i][j] = 0;
TaskDeviceValueNames[i][j] = 0;
TaskDeviceValueDecimals[i] = 0;
TaskDeviceValueDecimals[i] = 2;
}
}
for (byte i = 0; i < PLUGIN_EXTRACONFIGVAR_MAX; ++i) {
@@ -871,10 +960,46 @@ struct ExtraTaskSettingsStruct
}
}
byte TaskIndex;
char TaskDeviceName[41];
char TaskDeviceFormula[VARS_PER_TASK][41];
char TaskDeviceValueNames[VARS_PER_TASK][41];
bool checkUniqueValueNames() {
for (int i = 0; i < (VARS_PER_TASK - 1); ++i) {
for (int j = i; j < VARS_PER_TASK; ++j) {
if (i != j && TaskDeviceValueNames[i][0] != 0) {
if (strcasecmp(TaskDeviceValueNames[i], TaskDeviceValueNames[j]) == 0)
return false;
}
}
}
return true;
}
bool checkInvalidCharInNames(const char* name) {
int pos = 0;
while (*(name+pos) != 0) {
switch (*(name+pos)) {
case ',':
case ' ':
case '#':
case '[':
case ']':
return false;
}
++pos;
}
return true;
}
bool checkInvalidCharInNames() {
if (!checkInvalidCharInNames(&TaskDeviceName[0])) return false;
for (int i = 0; i < (VARS_PER_TASK - 1); ++i) {
if (!checkInvalidCharInNames(&TaskDeviceValueNames[i][0])) return false;
}
return true;
}
byte TaskIndex; // Always < TASKS_MAX
char TaskDeviceName[NAME_FORMULA_LENGTH_MAX + 1];
char TaskDeviceFormula[VARS_PER_TASK][NAME_FORMULA_LENGTH_MAX + 1];
char TaskDeviceValueNames[VARS_PER_TASK][NAME_FORMULA_LENGTH_MAX + 1];
long TaskDevicePluginConfigLong[PLUGIN_EXTRACONFIGVAR_MAX];
byte TaskDeviceValueDecimals[VARS_PER_TASK];
int16_t TaskDevicePluginConfig[PLUGIN_EXTRACONFIGVAR_MAX];
@@ -1035,6 +1160,11 @@ struct LogStruct {
} Logging;
byte highest_active_log_level = 0;
bool log_to_serial_disabled = false;
// Do this in a template to prevent casting to String when not needed.
#define addLog(L,S) if (loglevelActiveFor(L)) { addToLog(L,S); }
struct DeviceStruct
{
DeviceStruct() :
@@ -1042,20 +1172,26 @@ struct DeviceStruct
PullUpOption(false), InverseLogicOption(false), FormulaOption(false),
ValueCount(0), Custom(false), SendDataOption(false), GlobalSyncOption(false),
TimerOption(false), TimerOptional(false), DecimalsOnly(false) {}
byte Number;
byte Type;
byte VType;
byte Ports;
boolean PullUpOption;
boolean InverseLogicOption;
boolean FormulaOption;
byte ValueCount;
bool connectedToGPIOpins() {
return (Type >= DEVICE_TYPE_SINGLE && Type <= DEVICE_TYPE_TRIPLE);
}
byte Number; // Plugin ID number. (PLUGIN_ID_xxx)
byte Type; // How the device is connected. e.g. DEVICE_TYPE_SINGLE => connected through 1 datapin
byte VType; // Type of value the plugin will return, used only for Domoticz
byte Ports; // Port to use when device has multiple I/O pins (N.B. not used much)
boolean PullUpOption; // Allow to set internal pull-up resistors.
boolean InverseLogicOption; // Allow to invert the boolean state (e.g. a switch)
boolean FormulaOption; // Allow to enter a formula to convert values during read. (not possible with Custom enabled)
byte ValueCount; // The number of output values of a plugin. The value should match the number of keys PLUGIN_VALUENAME1_xxx
boolean Custom;
boolean SendDataOption;
boolean GlobalSyncOption;
boolean TimerOption;
boolean TimerOptional;
boolean DecimalsOnly;
boolean SendDataOption; // Allow to send data to a controller.
boolean GlobalSyncOption; // No longer used. Was used for ESPeasy values sync between nodes
boolean TimerOption; // Allow to set the "Interval" timer for the plugin.
boolean TimerOptional; // When taskdevice timer is not set and not optional, use default "Interval" delay (Settings.Delay)
boolean DecimalsOnly; // Allow to set the number of decimals (otherwise treated a 0 decimals)
} Device[DEVICES_MAX + 1]; // 1 more because first device is empty device
struct ProtocolStruct
@@ -1109,16 +1245,8 @@ struct systemTimerStruct
int Par3;
int Par4;
int Par5;
} systemTimers[SYSTEM_TIMER_MAX];
#define NOTAVAILABLE_SYSTEM_TIMER_ERROR "There are no system timer available, max parallel timers are " STR(SYSTEM_TIMER_MAX)
struct systemCMDTimerStruct
{
systemCMDTimerStruct() : timer(0) {}
unsigned long timer;
String action;
} systemCMDTimers[SYSTEM_CMD_TIMER_MAX];
};
std::map<unsigned long, systemTimerStruct> systemTimers;
struct pinStatesStruct
{
@@ -1157,19 +1285,15 @@ String printWebString = "";
boolean printToWebJSON = false;
float UserVar[VARS_PER_TASK * TASKS_MAX];
struct rulesTiemerStatus
struct rulesTimerStatus
{
unsigned long timestamp;
unsigned int interval; //interval in millisencond
unsigned int interval; //interval in milliseconds
boolean paused;
} RulesTimer[RULES_TIMER_MAX];
unsigned long timerSensor[TASKS_MAX];
unsigned long timer100ms;
unsigned long timer20ms;
unsigned long timer1s;
unsigned long timerwd;
unsigned long timermqtt;
msecTimerHandlerStruct msecTimerHandler;
unsigned long timermqtt_interval;
unsigned long lastSend;
unsigned long lastWeb;
@@ -1293,6 +1417,7 @@ bool processedScanDone = true;
bool webserver_state = false;
bool webserver_init = false;
unsigned long idle_msec_per_sec = 0;
unsigned long elapsed10ps = 0;
unsigned long elapsed10psU = 0;
unsigned long elapsed50ps = 0;
@@ -1306,9 +1431,6 @@ unsigned long loopCounter_full = 1;
float loop_usec_duration_total = 0.0;
unsigned long countFindPluginId = 0;
unsigned long systemTimerCalls = 1;
float systemTimerDurationTotal = 0.0;
unsigned long dailyResetCounter = 0;
String eventBuffer = "";
@@ -1325,8 +1447,6 @@ boolean UseRTOSMultitasking;
void (*MainLoopCall_ptr)(void);
#include <map>
class TimingStats {
public:
TimingStats() : _timeTotal(0.0), _count(0), _maxVal(0), _minVal(4294967295) {}
@@ -1443,7 +1563,7 @@ bool mustLogFunction(int function) {
case PLUGIN_SERIAL_IN: return true;
case PLUGIN_UDP_IN: return true;
case PLUGIN_CLOCK_IN: return false;
case PLUGIN_TIMER_IN: return false;
case PLUGIN_TIMER_IN: return true;
case PLUGIN_FIFTY_PER_SECOND: return true;
case PLUGIN_SET_CONFIG: return false;
case PLUGIN_GET_DEVICEGPIONAMES: return false;
@@ -1457,16 +1577,21 @@ bool mustLogFunction(int function) {
std::map<int,TimingStats> pluginStats;
std::map<int,TimingStats> miscStats;
unsigned long timediff_calls = 0;
unsigned long timediff_cpu_cycles_total = 0;
#define LOADFILE_STATS 0
#define LOOP_STATS 1
#define PLUGIN_CALL_50PS 2
#define PLUGIN_CALL_10PS 3
#define PLUGIN_CALL_10PSU 4
#define PLUGIN_CALL_1PS 5
#define CHECK_SENSORS 6
#define SEND_DATA_STATS 7
#define LOADFILE_STATS 0
#define LOOP_STATS 1
#define PLUGIN_CALL_50PS 2
#define PLUGIN_CALL_10PS 3
#define PLUGIN_CALL_10PSU 4
#define PLUGIN_CALL_1PS 5
#define SENSOR_SEND_TASK 6
#define SEND_DATA_STATS 7
#define COMPUTE_FORMULA_STATS 8
#define PROC_SYS_TIMER 9
#define SET_NEW_TIMER 10
#define TIME_DIFF_COMPUTE 11
@@ -1482,13 +1607,16 @@ String getMiscStatsName(int stat) {
switch (stat) {
case LOADFILE_STATS: return F("Load File");
case LOOP_STATS: return F("Loop");
case PLUGIN_CALL_50PS : return F("Plugin call 50 p/s ");
case PLUGIN_CALL_10PS : return F("Plugin call 10 p/s ");
case PLUGIN_CALL_10PSU : return F("Plugin call 10 p/s U");
case PLUGIN_CALL_1PS : return F("Plugin call 1 p/s ");
case CHECK_SENSORS: return F("checkSensors() ");
case SEND_DATA_STATS: return F("sendData() ");
case COMPUTE_FORMULA_STATS: return F("Compute formula ");
case PLUGIN_CALL_50PS: return F("Plugin call 50 p/s ");
case PLUGIN_CALL_10PS: return F("Plugin call 10 p/s ");
case PLUGIN_CALL_10PSU: return F("Plugin call 10 p/s U");
case PLUGIN_CALL_1PS: return F("Plugin call 1 p/s ");
case SENSOR_SEND_TASK: return F("SensorSendTask() ");
case SEND_DATA_STATS: return F("sendData() ");
case COMPUTE_FORMULA_STATS: return F("Compute formula ");
case PROC_SYS_TIMER: return F("proc_system_timer() ");
case SET_NEW_TIMER: return F("setNewTimerAt() ");
case TIME_DIFF_COMPUTE: return F("timeDiff() ");
}
return F("Unknown");
}
+58 -224
View File
@@ -195,8 +195,6 @@ void setup()
// setWifiMode(WIFI_STA);
checkRuleSets();
ExtraTaskSettings.TaskIndex = 255; // make sure this is an unused nr to prevent cache load on boot
// if different version, eeprom settings structure has changed. Full Reset needed
// on a fresh ESP module eeprom values are set to 255. Version results into -1 (signed int)
if (Settings.Version != VERSION || Settings.PID != ESP_PROJECT_PID)
@@ -233,17 +231,6 @@ void setup()
checkRAM(F("hardwareInit"));
hardwareInit();
//After booting, we want all the tasks to run without delaying more than neccesary.
//Plugins that need an initial startup delay need to overwrite their initial timerSensor value in PLUGIN_INIT
//They should also check if we returned from deep sleep so that they can skip the delay in that case.
for (byte x = 0; x < TASKS_MAX; x++)
if (Settings.TaskDeviceTimer[x] !=0)
timerSensor[x] = millis() + (x * Settings.MessageDelay);
timer100ms = 0; // timer for periodic actions 10 x per/sec
timer1s = 0; // timer for periodic actions once per/sec
timerwd = 0; // timer for watchdog once per 30 sec
timermqtt = 10000; // Timer for the MQTT keep alive loop, initial value can be high, since it will be set as soon as IP is set.
timermqtt_interval = 250; // Interval for checking MQTT
timerAwakeFromDeepSleep = millis();
@@ -324,9 +311,16 @@ void setup()
// #ifndef ESP32
// connectionCheck.attach(30, connectionCheckHandler);
// #endif
timer20ms = millis();
timer100ms = millis();
timer1s = millis();
// Start the interval timers at N msec from now.
// Make sure to start them at some time after eachother,
// since they will keep running at the same interval.
setIntervalTimerOverride(TIMER_20MSEC, 5); // timer for periodic actions 50 x per/sec
setIntervalTimerOverride(TIMER_100MSEC, 66); // timer for periodic actions 10 x per/sec
setIntervalTimerOverride(TIMER_1SEC, 777); // timer for periodic actions once per/sec
setIntervalTimerOverride(TIMER_30SEC, 1333); // timer for watchdog once per 30 sec
setIntervalTimerOverride(TIMER_MQTT, 88); // timer for interaction with MQTT
setIntervalTimerOverride(TIMER_STATISTICS, 2222);
}
#ifdef USE_RTOS_MULTITASKING
@@ -395,38 +389,36 @@ void updateLoopStats() {
longestLoop = usecSince;
}
void updateLoopStats_30sec() {
void updateLoopStats_30sec(byte loglevel) {
loopCounterLast = loopCounter;
loopCounter = 0;
if (loopCounterLast > loopCounterMax)
loopCounterMax = loopCounterLast;
String log = F("LoopStats: shortestLoop: ");
log += shortestLoop;
log += F(" longestLoop: ");
log += longestLoop;
log += F(" avgLoopDuration: ");
log += loop_usec_duration_total / loopCounter_full;
log += F(" systemTimerDuration: ");
log += systemTimerDurationTotal / systemTimerCalls;
log += F(" systemTimerCalls: ");
log += systemTimerCalls;
log += F(" loopCounterMax: ");
log += loopCounterMax;
log += F(" loopCounterLast: ");
log += loopCounterLast;
log += F(" countFindPluginId: ");
log += countFindPluginId;
addLog(LOG_LEVEL_INFO, log);
msecTimerHandler.updateIdleTimeStats();
if (loglevelActiveFor(loglevel)) {
String log = F("LoopStats: shortestLoop: ");
log += shortestLoop;
log += F(" longestLoop: ");
log += longestLoop;
log += F(" avgLoopDuration: ");
log += loop_usec_duration_total / loopCounter_full;
log += F(" loopCounterMax: ");
log += loopCounterMax;
log += F(" loopCounterLast: ");
log += loopCounterLast;
log += F(" countFindPluginId: ");
log += countFindPluginId;
addLog(loglevel, log);
}
countFindPluginId = 0;
loop_usec_duration_total = 0;
loopCounter_full = 1;
systemTimerDurationTotal = 0;
systemTimerCalls = 1;
}
int getCPUload() {
return 100 - (100 * loopCounterLast / loopCounterMax);
float getCPUload() {
return 100.0 - msecTimerHandler.getIdleTimePct();
}
int getLoopCountPerSec() {
@@ -435,6 +427,7 @@ int getLoopCountPerSec() {
/*********************************************************************************************\
* MAIN LOOP
\*********************************************************************************************/
@@ -484,23 +477,7 @@ void loop()
//normal mode, run each task when its time
else
{
if (timeOutReached(timer20ms))
run50TimesPerSecond();
if (timeOutReached(timer100ms))
if(!UseRTOSMultitasking)
run10TimesPerSecond();
if (timeOutReached(timerwd))
runEach30Seconds();
if (timeOutReached(timer1s))
runOncePerSecond();
if (timeOutReached(timermqtt)) {
runPeriodicalMQTT();
}
handle_schedule();
}
backgroundtasks();
@@ -561,16 +538,14 @@ void updateMQTTclient_connected() {
} else {
timermqtt_interval = 250;
}
timermqtt = millis() + timermqtt_interval;
setIntervalTimer(TIMER_MQTT);
}
/*********************************************************************************************\
* Tasks that run 50 times per second
\*********************************************************************************************/
void run50TimesPerSecond()
{
setNextTimeInterval(timer20ms, 20);
void run50TimesPerSecond() {
START_TIMER;
PluginCall(PLUGIN_FIFTY_PER_SECOND, 0, dummyString);
STOP_TIMER(PLUGIN_CALL_50PS);
@@ -579,9 +554,7 @@ void run50TimesPerSecond()
/*********************************************************************************************\
* Tasks that run 10 times per second
\*********************************************************************************************/
void run10TimesPerSecond()
{
setNextTimeInterval(timer100ms, 100);
void run10TimesPerSecond() {
{
START_TIMER;
PluginCall(PLUGIN_TEN_PER_SECOND, 0, dummyString);
@@ -609,7 +582,7 @@ void run10TimesPerSecond()
void runOncePerSecond()
{
START_TIMER;
setNextTimeInterval(timer1s, 1000);
updateLogLevelCache();
dailyResetCounter++;
if (dailyResetCounter > 86400) // 1 day elapsed... //86400
{
@@ -620,8 +593,6 @@ void runOncePerSecond()
addLog(LOG_LEVEL_INFO, log);
}
checkSensors();
if (Settings.ConnectionFailuresThreshold)
if (connectionFailures > Settings.ConnectionFailuresThreshold)
delayedReboot(60);
@@ -658,8 +629,6 @@ void runOncePerSecond()
PluginCall(PLUGIN_ONCE_A_SECOND, 0, dummyString);
// unsigned long elapsed = micros() - start;
checkSystemTimers();
if (Settings.UseRules)
rulesTimers();
@@ -701,6 +670,17 @@ void runOncePerSecond()
STOP_TIMER(PLUGIN_CALL_1PS);
}
void logTimerStatistics() {
byte loglevel = LOG_LEVEL_DEBUG;
updateLoopStats_30sec(loglevel);
logStatistics(loglevel, true);
if (loglevelActiveFor(loglevel)) {
String queueLog = F("Scheduler stats: (called/tasks/max_length/idle%) ");
queueLog += msecTimerHandler.getQueueStats();
addLog(loglevel, queueLog);
}
}
/*********************************************************************************************\
* Tasks each 30 seconds
\*********************************************************************************************/
@@ -708,19 +688,18 @@ void runEach30Seconds()
{
extern void checkRAMtoLog();
checkRAMtoLog();
updateLoopStats_30sec();
logStatistics(true);
wdcounter++;
timerwd = millis() + 30000;
String log;
log.reserve(60);
log = F("WD : Uptime ");
log += wdcounter / 2;
log += F(" ConnectFailures ");
log += connectionFailures;
log += F(" FreeMem ");
log += FreeMem();
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log;
log.reserve(60);
log = F("WD : Uptime ");
log += wdcounter / 2;
log += F(" ConnectFailures ");
log += connectionFailures;
log += F(" FreeMem ");
log += FreeMem();
addLog(LOG_LEVEL_INFO, log);
}
sendSysInfoUDP(1);
refreshNodeList();
@@ -739,33 +718,6 @@ void runEach30Seconds()
}
/*********************************************************************************************\
* Check sensor timers
\*********************************************************************************************/
void checkSensors()
{
START_TIMER;
checkRAM(F("checkSensors"));
bool isDeepSleep = isDeepSleepEnabled();
//check all the devices and only run the sendtask if its time, or we if we used deep sleep mode
for (byte x = 0; x < TASKS_MAX; x++)
{
if (
(Settings.TaskDeviceTimer[x] != 0) &&
(isDeepSleep || timeOutReached(timerSensor[x]))
)
{
setNextTimeInterval(timerSensor[x], Settings.TaskDeviceTimer[x] * 1000);
if (timerSensor[x] == 0) // small fix if result is 0, else timer will be stopped...
timerSensor[x] = 1;
SensorSendTask(x);
}
}
saveUserVarToRTC();
STOP_TIMER(CHECK_SENSORS);
}
/*********************************************************************************************\
* send all sensordata
\*********************************************************************************************/
@@ -833,124 +785,6 @@ void SensorSendTask(byte TaskIndex)
}
/*********************************************************************************************\
* set global system timer
\*********************************************************************************************/
void setSystemTimer(unsigned long timer, byte plugin, int Par1, int Par2, int Par3)
{
setSystemTimer(timer, plugin, -1, Par1, Par2, Par3, 0, 0);
}
void setSystemTimer(unsigned long timer, byte plugin, short taskIndex, int Par1, int Par2, int Par3)
{
setSystemTimer(timer, plugin, taskIndex , Par1, Par2, Par3, 0, 0);
}
void setSystemTimer(unsigned long timer, byte plugin, short taskIndex, int Par1, int Par2, int Par3, int Par4)
{
setSystemTimer(timer, plugin, taskIndex , Par1, Par2, Par3, Par4, 0);
}
void setSystemTimer(unsigned long timer, byte plugin, short taskIndex, int Par1, int Par2, int Par3, int Par4, int Par5)
{
// plugin number and par1 form a unique key that can be used to restart a timer
// first check if a timer is not already running for this request
byte firstAvailable = SYSTEM_TIMER_MAX;
for (byte x = 0; x < SYSTEM_TIMER_MAX; x++)
{
if (systemTimers[x].timer != 0)
{
if ((systemTimers[x].plugin == plugin) && systemTimers[x].TaskIndex == taskIndex && (systemTimers[x].Par1 == Par1))
{
firstAvailable = x;
break;
}
}
else if(firstAvailable == SYSTEM_TIMER_MAX)
{
firstAvailable = x;
}
}
if (firstAvailable == SYSTEM_TIMER_MAX )
{
addLog(LOG_LEVEL_ERROR, F(NOTAVAILABLE_SYSTEM_TIMER_ERROR));
}
else
{
systemTimers[firstAvailable].plugin = plugin;
systemTimers[firstAvailable].TaskIndex = taskIndex;
systemTimers[firstAvailable].Par1 = Par1;
systemTimers[firstAvailable].Par2 = Par2;
systemTimers[firstAvailable].Par3 = Par3;
systemTimers[firstAvailable].Par4 = Par4;
systemTimers[firstAvailable].Par5 = Par5;
systemTimers[firstAvailable].timer = timer > 0
? millis() + timer
: 0;
}
}
//EDWIN: this function seems to be unused?
/*********************************************************************************************\
* set global system command timer
\*********************************************************************************************/
void setSystemCMDTimer(unsigned long timer, String& action)
{
for (byte x = 0; x < SYSTEM_CMD_TIMER_MAX; x++)
if (systemCMDTimers[x].timer == 0)
{
systemCMDTimers[x].timer = millis() + timer;
systemCMDTimers[x].action = action;
break;
}
}
/*********************************************************************************************\
* check global system timers
\*********************************************************************************************/
void checkSystemTimers()
{
unsigned long start = micros();
for (byte x = 0; x < SYSTEM_TIMER_MAX; x++)
if (systemTimers[x].timer != 0)
{
if (timeOutReached(systemTimers[x].timer))
{
struct EventStruct TempEvent;
TempEvent.TaskIndex = systemTimers[x].TaskIndex;
TempEvent.Par1 = systemTimers[x].Par1;
TempEvent.Par2 = systemTimers[x].Par2;
TempEvent.Par3 = systemTimers[x].Par3;
TempEvent.Par4 = systemTimers[x].Par4;
TempEvent.Par5 = systemTimers[x].Par5;
systemTimers[x].timer = 0;
const int y = getPluginId(systemTimers[x].TaskIndex);
if (y >= 0) {
Plugin_ptr[y](PLUGIN_TIMER_IN, &TempEvent, dummyString);
}
}
}
for (byte x = 0; x < SYSTEM_CMD_TIMER_MAX; x++)
if (systemCMDTimers[x].timer != 0)
if (timeOutReached(systemCMDTimers[x].timer))
{
struct EventStruct TempEvent;
parseCommandString(&TempEvent, systemCMDTimers[x].action);
if (!PluginCall(PLUGIN_WRITE, &TempEvent, systemCMDTimers[x].action))
ExecuteCommand(VALUE_SOURCE_SYSTEM, systemCMDTimers[x].action.c_str());
systemCMDTimers[x].timer = 0;
systemCMDTimers[x].action = "";
}
++systemTimerCalls;
systemTimerDurationTotal += usecPassedSince(start);;
}
/*********************************************************************************************\
* run background tasks
\*********************************************************************************************/
+16 -4
View File
@@ -1,10 +1,11 @@
void logStatistics(bool clearLog) {
void logStatistics(byte loglevel, bool clearLog) {
if (loglevelActiveFor(loglevel)) {
String log;
log.reserve(80);
for (auto& x: pluginStats) {
if (!x.second.isEmpty()) {
const int pluginId = x.first/32;
String P_name = "";
String P_name = "";
Plugin_ptr[pluginId](PLUGIN_GET_DEVICENAME, NULL, P_name);
log = F("PluginStats P_");
log += pluginId + 1;
@@ -14,7 +15,7 @@ void logStatistics(bool clearLog) {
log += getPluginFunctionName(x.first%32);
log += ' ';
log += getLogLine(x.second);
addLog(LOG_LEVEL_DEBUG, log);
addLog(loglevel, log);
if (clearLog) x.second.reset();
}
}
@@ -23,8 +24,19 @@ void logStatistics(bool clearLog) {
log = getMiscStatsName(x.first);
log += F(" stats: ");
log += getLogLine(x.second);
addLog(LOG_LEVEL_DEBUG, log);
addLog(loglevel, log);
if (clearLog) x.second.reset();
}
}
log = getMiscStatsName(TIME_DIFF_COMPUTE);
log += F(" stats: Count: ");
log += timediff_calls;
log += F(" - CPU cycles per call: ");
log += static_cast<float>(timediff_cpu_cycles_total) / static_cast<float>(timediff_calls);
addLog(loglevel, log);
if (clearLog) {
timediff_calls = 0;
timediff_cpu_cycles_total = 0;
}
}
}
+697
View File
@@ -0,0 +1,697 @@
/********************************************************************************************\
SPIFFS error handling
Look here for error # reference: https://github.com/pellepl/spiffs/blob/master/src/spiffs.h
\*********************************************************************************************/
#define SPIFFS_CHECK(result, fname) if (!(result)) { return(FileError(__LINE__, fname)); }
String FileError(int line, const char * fname)
{
String err = F("FS : Error while reading/writing ");
err += fname;
err += F(" in ");
err += line;
addLog(LOG_LEVEL_ERROR, err);
return(err);
}
/********************************************************************************************\
Keep track of number of flash writes.
\*********************************************************************************************/
void flashCount()
{
if (RTC.flashDayCounter <= MAX_FLASHWRITES_PER_DAY)
RTC.flashDayCounter++;
RTC.flashCounter++;
saveToRTC();
}
String flashGuard()
{
checkRAM(F("flashGuard"));
if (RTC.flashDayCounter > MAX_FLASHWRITES_PER_DAY)
{
String log = F("FS : Daily flash write rate exceeded! (powercycle to reset this)");
addLog(LOG_LEVEL_ERROR, log);
return log;
}
flashCount();
return(String());
}
//use this in function that can return an error string. it automaticly returns with an error string if there where too many flash writes.
#define FLASH_GUARD() { String flashErr=flashGuard(); if (flashErr.length()) return(flashErr); }
/********************************************************************************************\
Fix stuff to clear out differences between releases
\*********************************************************************************************/
String BuildFixes()
{
checkRAM(F("BuildFixes"));
Serial.println(F("\nBuild changed!"));
if (Settings.Build < 145)
{
String fname=F(FILE_NOTIFICATION);
fs::File f = SPIFFS.open(fname, "w");
SPIFFS_CHECK(f, fname.c_str());
if (f)
{
for (int x = 0; x < 4096; x++)
{
SPIFFS_CHECK(f.write(0), fname.c_str());
}
f.close();
}
}
if (Settings.Build < 20101)
{
Serial.println(F("Fix reset Pin"));
Settings.Pin_Reset = -1;
}
if (Settings.Build < 20102) {
// Settings were 'mangled' by using older version
// Have to patch settings to make sure no bogus data is being used.
Serial.println(F("Fix settings with uninitalized data or corrupted by switching between versions"));
Settings.UseRTOSMultitasking = false;
Settings.Pin_Reset = -1;
Settings.SyslogFacility = DEFAULT_SYSLOG_FACILITY;
Settings.MQTTUseUnitNameAsClientId = DEFAULT_MQTT_USE_UNITNANE_AS_CLIENTID;
Settings.StructSize = sizeof(Settings);
}
Settings.Build = BUILD;
return(SaveSettings());
}
/********************************************************************************************\
Mount FS and check config.dat
\*********************************************************************************************/
void fileSystemCheck()
{
checkRAM(F("fileSystemCheck"));
addLog(LOG_LEVEL_INFO, F("FS : Mounting..."));
if (SPIFFS.begin())
{
#if defined(ESP8266)
fs::FSInfo fs_info;
SPIFFS.info(fs_info);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("FS : Mount successful, used ");
log=log+fs_info.usedBytes;
log=log+F(" bytes of ");
log=log+fs_info.totalBytes;
addLog(LOG_LEVEL_INFO, log);
}
#endif
fs::File f = SPIFFS.open(FILE_CONFIG, "r");
if (!f)
{
ResetFactory();
}
f.close();
}
else
{
String log = F("FS : Mount failed");
Serial.println(log);
addLog(LOG_LEVEL_ERROR, log);
ResetFactory();
}
}
/********************************************************************************************\
Save settings to SPIFFS
\*********************************************************************************************/
String SaveSettings(void)
{
checkRAM(F("SaveSettings"));
MD5Builder md5;
uint8_t tmp_md5[16] = {0};
String err;
Settings.StructSize = sizeof(struct SettingsStruct);
// FIXME @TD-er: As discussed in #1292, the CRC for the settings is now disabled.
/*
memcpy( Settings.ProgmemMd5, CRCValues.runTimeMD5, 16);
md5.begin();
md5.add((uint8_t *)&Settings, sizeof(Settings)-16);
md5.calculate();
md5.getBytes(tmp_md5);
if (memcmp(tmp_md5, Settings.md5, 16) != 0) {
// Settings have changed, save to file.
memcpy(Settings.md5, tmp_md5, 16);
*/
err=SaveToFile((char*)FILE_CONFIG, 0, (byte*)&Settings, sizeof(Settings));
if (err.length())
return(err);
// }
memcpy( SecuritySettings.ProgmemMd5, CRCValues.runTimeMD5, 16);
md5.begin();
md5.add((uint8_t *)&SecuritySettings, sizeof(SecuritySettings)-16);
md5.calculate();
md5.getBytes(tmp_md5);
if (memcmp(tmp_md5, SecuritySettings.md5, 16) != 0) {
// Settings have changed, save to file.
memcpy(SecuritySettings.md5, tmp_md5, 16);
err=SaveToFile((char*)FILE_SECURITY, 0, (byte*)&SecuritySettings, sizeof(SecuritySettings));
if (WifiIsAP(WiFi.getMode())) {
// Security settings are saved, may be update of WiFi settings or hostname.
wifiSetupConnect = true;
}
}
return (err);
}
/********************************************************************************************\
Load settings from SPIFFS
\*********************************************************************************************/
String LoadSettings()
{
checkRAM(F("LoadSettings"));
String err;
uint8_t calculatedMd5[16];
MD5Builder md5;
err=LoadFromFile((char*)FILE_CONFIG, 0, (byte*)&Settings, sizeof( SettingsStruct));
if (err.length())
return(err);
// FIXME @TD-er: As discussed in #1292, the CRC for the settings is now disabled.
/*
if (Settings.StructSize > 16) {
md5.begin();
md5.add((uint8_t *)&Settings, Settings.StructSize -16);
md5.calculate();
md5.getBytes(calculatedMd5);
}
if (memcmp (calculatedMd5, Settings.md5,16)==0){
addLog(LOG_LEVEL_INFO, F("CRC : Settings CRC ...OK"));
if (memcmp(Settings.ProgmemMd5, CRCValues.runTimeMD5, 16)!=0)
addLog(LOG_LEVEL_INFO, F("CRC : binary has changed since last save of Settings"));
}
else{
addLog(LOG_LEVEL_ERROR, F("CRC : Settings CRC ...FAIL"));
}
*/
err=LoadFromFile((char*)FILE_SECURITY, 0, (byte*)&SecuritySettings, sizeof( SecurityStruct));
md5.begin();
md5.add((uint8_t *)&SecuritySettings, sizeof(SecuritySettings)-16);
md5.calculate();
md5.getBytes(calculatedMd5);
if (memcmp (calculatedMd5, SecuritySettings.md5, 16)==0){
addLog(LOG_LEVEL_INFO, F("CRC : SecuritySettings CRC ...OK "));
if (memcmp(SecuritySettings.ProgmemMd5,CRCValues.runTimeMD5, 16)!=0)
addLog(LOG_LEVEL_INFO, F("CRC : binary has changed since last save of Settings"));
}
else{
addLog(LOG_LEVEL_ERROR, F("CRC : SecuritySettings CRC ...FAIL"));
}
setUseStaticIP(useStaticIP());
ExtraTaskSettings.clear(); // make sure these will not contain old settings.
return(err);
}
/********************************************************************************************\
Offsets in settings files
\*********************************************************************************************/
bool getSettingsParameters(SettingsType settingsType, int index, int& max_index, int& offset, int& max_size, int& struct_size) {
struct_size = 0;
switch (settingsType) {
case TaskSettings_Type:
max_index = TASKS_MAX;
offset = DAT_OFFSET_TASKS + (index * DAT_TASKS_DISTANCE);
max_size = DAT_TASKS_SIZE;
struct_size = sizeof(ExtraTaskSettingsStruct);
break;
case CustomTaskSettings_Type:
max_index = TASKS_MAX;
offset = DAT_OFFSET_TASKS + (index * DAT_TASKS_DISTANCE) + DAT_TASKS_CUSTOM_OFFSET;
max_size = DAT_TASKS_CUSTOM_SIZE;
// struct_size may differ.
break;
case ControllerSettings_Type:
max_index = CONTROLLER_MAX;
offset = DAT_OFFSET_CONTROLLER + (index * DAT_CONTROLLER_SIZE);
max_size = DAT_CONTROLLER_SIZE;
struct_size = sizeof(ControllerSettingsStruct);
break;
case CustomControllerSettings_Type:
max_index = CONTROLLER_MAX;
offset = DAT_OFFSET_CUSTOM_CONTROLLER + (index * DAT_CUSTOM_CONTROLLER_SIZE);
max_size = DAT_CUSTOM_CONTROLLER_SIZE;
// struct_size may differ.
break;
case NotificationSettings_Type:
max_index = NOTIFICATION_MAX;
offset = index * DAT_NOTIFICATION_SIZE;
max_size = DAT_NOTIFICATION_SIZE;
struct_size = sizeof(NotificationSettingsStruct);
break;
default:
max_index = -1;
offset = -1;
return false;
}
return true;
}
bool getAndLogSettingsParameters(bool read, SettingsType settingsType, int index, int& offset, int& max_size) {
if (loglevelActiveFor(LOG_LEVEL_DEBUG_DEV)) {
String log = read ? F("Read") : F("Write");
log += F(" settings: ");
log += getSettingsTypeString(settingsType);
log += F(" index: ");
log += index;
addLog(LOG_LEVEL_DEBUG_DEV, log);
}
return getSettingsParameters(settingsType, index, offset, max_size);
}
bool getSettingsParameters(SettingsType settingsType, int index, int& offset, int& max_size) {
int max_index = -1;
int struct_size;
if (!getSettingsParameters(settingsType, index, max_index, offset, max_size, struct_size))
return false;
if (index >= 0 && index < max_index) return true;
offset = -1;
return false;
}
/********************************************************************************************\
Save Task settings to SPIFFS
\*********************************************************************************************/
String SaveTaskSettings(byte TaskIndex)
{
checkRAM(F("SaveTaskSettings"));
if (ExtraTaskSettings.TaskIndex != TaskIndex)
return F("SaveTaskSettings taskIndex does not match");
String err = SaveToFile(TaskSettings_Type, TaskIndex, (char*)FILE_CONFIG, (byte*)&ExtraTaskSettings, sizeof(struct ExtraTaskSettingsStruct));
if (err.length() == 0)
err = checkTaskSettings(TaskIndex);
return err;
}
/********************************************************************************************\
Load Task settings from SPIFFS
\*********************************************************************************************/
String LoadTaskSettings(byte TaskIndex)
{
checkRAM(F("LoadTaskSettings"));
if (ExtraTaskSettings.TaskIndex == TaskIndex)
return(String()); //already loaded
ExtraTaskSettings.clear();
String result = "";
result = LoadFromFile(TaskSettings_Type, TaskIndex, (char*)FILE_CONFIG, (byte*)&ExtraTaskSettings, sizeof(struct ExtraTaskSettingsStruct));
// After loading, some settings may need patching.
ExtraTaskSettings.TaskIndex = TaskIndex; // Needed when an empty task was requested
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) {
// if field set empty, reload defaults
struct EventStruct TempEvent;
TempEvent.TaskIndex = TaskIndex;
String dummyString;
//the plugin call should populate ExtraTaskSettings with its default values.
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, &TempEvent, dummyString);
}
return result;
}
/********************************************************************************************\
Save Custom Task settings to SPIFFS
\*********************************************************************************************/
String SaveCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
{
checkRAM(F("SaveCustomTaskSettings"));
return(SaveToFile(CustomTaskSettings_Type, TaskIndex, (char*)FILE_CONFIG, memAddress, datasize));
}
/********************************************************************************************\
Clear custom task settings
\*********************************************************************************************/
String ClearCustomTaskSettings(int TaskIndex)
{
// addLog(LOG_LEVEL_DEBUG, F("Clearing custom task settings"));
return(ClearInFile(CustomTaskSettings_Type, TaskIndex, (char*)FILE_CONFIG));
}
/********************************************************************************************\
Load Custom Task settings to SPIFFS
\*********************************************************************************************/
String LoadCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
{
checkRAM(F("LoadCustomTaskSettings"));
return(LoadFromFile(CustomTaskSettings_Type, TaskIndex, (char*)FILE_CONFIG, memAddress, datasize));
}
/********************************************************************************************\
Save Controller settings to SPIFFS
\*********************************************************************************************/
String SaveControllerSettings(int ControllerIndex, byte* memAddress, int datasize)
{
checkRAM(F("SaveControllerSettings"));
return SaveToFile(ControllerSettings_Type, ControllerIndex, (char*)FILE_CONFIG, memAddress, datasize);
}
/********************************************************************************************\
Load Controller settings to SPIFFS
\*********************************************************************************************/
String LoadControllerSettings(int ControllerIndex, byte* memAddress, int datasize)
{
checkRAM(F("LoadControllerSettings"));
return(LoadFromFile(ControllerSettings_Type, ControllerIndex, (char*)FILE_CONFIG, memAddress, datasize));
}
/********************************************************************************************\
Clear Custom Controller settings
\*********************************************************************************************/
String ClearCustomControllerSettings(int ControllerIndex)
{
checkRAM(F("ClearCustomControllerSettings"));
// addLog(LOG_LEVEL_DEBUG, F("Clearing custom controller settings"));
return(ClearInFile(CustomControllerSettings_Type, ControllerIndex, (char*)FILE_CONFIG));
}
/********************************************************************************************\
Save Custom Controller settings to SPIFFS
\*********************************************************************************************/
String SaveCustomControllerSettings(int ControllerIndex,byte* memAddress, int datasize)
{
checkRAM(F("SaveCustomControllerSettings"));
return SaveToFile(CustomControllerSettings_Type, ControllerIndex, (char*)FILE_CONFIG, memAddress, datasize);
}
/********************************************************************************************\
Load Custom Controller settings to SPIFFS
\*********************************************************************************************/
String LoadCustomControllerSettings(int ControllerIndex,byte* memAddress, int datasize)
{
checkRAM(F("LoadCustomControllerSettings"));
return(LoadFromFile(CustomControllerSettings_Type, ControllerIndex, (char*)FILE_CONFIG, memAddress, datasize));
}
/********************************************************************************************\
Save Controller settings to SPIFFS
\*********************************************************************************************/
String SaveNotificationSettings(int NotificationIndex, byte* memAddress, int datasize)
{
checkRAM(F("SaveNotificationSettings"));
return SaveToFile(NotificationSettings_Type, NotificationIndex, (char*)FILE_NOTIFICATION, memAddress, datasize);
}
/********************************************************************************************\
Load Controller settings to SPIFFS
\*********************************************************************************************/
String LoadNotificationSettings(int NotificationIndex, byte* memAddress, int datasize)
{
checkRAM(F("LoadNotificationSettings"));
return(LoadFromFile(NotificationSettings_Type, NotificationIndex, (char*)FILE_NOTIFICATION, memAddress, datasize));
}
/********************************************************************************************\
Init a file with zeros on SPIFFS
\*********************************************************************************************/
String InitFile(const char* fname, int datasize)
{
checkRAM(F("InitFile"));
FLASH_GUARD();
fs::File f = SPIFFS.open(fname, "w");
SPIFFS_CHECK(f, fname);
for (int x = 0; x < datasize ; x++)
{
SPIFFS_CHECK(f.write(0), fname);
}
f.close();
//OK
return String();
}
/********************************************************************************************\
Save data into config file on SPIFFS
\*********************************************************************************************/
String SaveToFile(char* fname, int index, byte* memAddress, int datasize)
{
if (index < 0) {
String log = F("SaveToFile: ");
log += fname;
log += F(" ERROR, invalid position in file");
addLog(LOG_LEVEL_ERROR, log);
return log;
}
checkRAM(F("SaveToFile"));
FLASH_GUARD();
fs::File f = SPIFFS.open(fname, "r+");
SPIFFS_CHECK(f, fname);
SPIFFS_CHECK(f.seek(index, fs::SeekSet), fname);
byte *pointerToByteToSave = memAddress;
for (int x = 0; x < datasize ; x++)
{
SPIFFS_CHECK(f.write(*pointerToByteToSave), fname);
pointerToByteToSave++;
}
f.close();
String log = F("FILE : Saved ");
log=log+fname;
addLog(LOG_LEVEL_INFO, log);
//OK
return String();
}
/********************************************************************************************\
Clear a certain area in a file (set to 0)
\*********************************************************************************************/
String ClearInFile(char* fname, int index, int datasize)
{
if (index < 0) {
String log = F("ClearInFile: ");
log += fname;
log += F(" ERROR, invalid position in file");
addLog(LOG_LEVEL_ERROR, log);
return log;
}
checkRAM(F("ClearInFile"));
FLASH_GUARD();
fs::File f = SPIFFS.open(fname, "r+");
SPIFFS_CHECK(f, fname);
SPIFFS_CHECK(f.seek(index, fs::SeekSet), fname);
for (int x = 0; x < datasize ; x++)
{
SPIFFS_CHECK(f.write(0), fname);
}
f.close();
//OK
return String();
}
/********************************************************************************************\
Load data from config file on SPIFFS
\*********************************************************************************************/
String LoadFromFile(char* fname, int offset, byte* memAddress, int datasize)
{
if (offset < 0) {
String log = F("LoadFromFile: ");
log += fname;
log += F(" ERROR, invalid position in file");
addLog(LOG_LEVEL_ERROR, log);
return log;
}
START_TIMER;
checkRAM(F("LoadFromFile"));
fs::File f = SPIFFS.open(fname, "r+");
SPIFFS_CHECK(f, fname);
SPIFFS_CHECK(f.seek(offset, fs::SeekSet), fname);
SPIFFS_CHECK(f.read(memAddress,datasize), fname);
f.close();
STOP_TIMER(LOADFILE_STATS);
return(String());
}
/********************************************************************************************\
Wrapper functions to handle errors in accessing settings
\*********************************************************************************************/
String getSettingsFileIndexRangeError(bool read, SettingsType settingsType, int index) {
if (settingsType >= SettingsType_MAX) {
String error = F("Unknown settingsType: ");
error += static_cast<int>(settingsType);
return error;
}
String error = read ? F("Load") : F("Save");
error += getSettingsTypeString(settingsType);
error += F(" index out of range: ");
error += index;
return error;
}
String getSettingsFileDatasizeError(bool read, SettingsType settingsType, int index, int datasize, int max_size) {
String error = read ? F("Load") : F("Save");
error += getSettingsTypeString(settingsType);
error += '(';
error += index;
error += F(") datasize(");
error += datasize;
error += F(") > max_size(");
error += max_size;
error += ')';
return error;
}
String LoadFromFile(SettingsType settingsType, int index, char* fname, byte* memAddress, int datasize) {
bool read = true;
int offset, max_size;
if (!getAndLogSettingsParameters(read, settingsType, index, offset, max_size)) {
return getSettingsFileIndexRangeError(read, settingsType, index);
}
if (datasize > max_size)
return getSettingsFileDatasizeError(read, settingsType, index, datasize, max_size);
return(LoadFromFile(fname, offset, memAddress, datasize));
}
String SaveToFile(SettingsType settingsType, int index, char* fname, byte* memAddress, int datasize) {
bool read = false;
int offset, max_size;
if (!getAndLogSettingsParameters(read, settingsType, index, offset, max_size)) {
return getSettingsFileIndexRangeError(read, settingsType, index);
}
if (datasize > max_size)
return getSettingsFileDatasizeError(read, settingsType, index, datasize, max_size);
return(SaveToFile(fname, offset, memAddress, datasize));
}
String ClearInFile(SettingsType settingsType, int index, char* fname) {
bool read = false;
int offset, max_size;
if (!getAndLogSettingsParameters(read, settingsType, index, offset, max_size)) {
return getSettingsFileIndexRangeError(read, settingsType, index);
}
return(ClearInFile(fname, offset, max_size));
}
/********************************************************************************************\
Check SPIFFS area settings
\*********************************************************************************************/
int SpiffsSectors()
{
checkRAM(F("SpiffsSectors"));
#if defined(ESP8266)
uint32_t _sectorStart = ((uint32_t)&_SPIFFS_start - 0x40200000) / SPI_FLASH_SEC_SIZE;
uint32_t _sectorEnd = ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE;
return _sectorEnd - _sectorStart;
#endif
#if defined(ESP32)
return 32;
#endif
}
/********************************************************************************************\
Get partition table information
\*********************************************************************************************/
#ifdef ESP32
String getPartitionType(byte pType, byte pSubType) {
esp_partition_type_t partitionType = static_cast<esp_partition_type_t>(pType);
esp_partition_subtype_t partitionSubType = static_cast<esp_partition_subtype_t>(pSubType);
if (partitionType == ESP_PARTITION_TYPE_APP) {
if (partitionSubType >= ESP_PARTITION_SUBTYPE_APP_OTA_MIN &&
partitionSubType < ESP_PARTITION_SUBTYPE_APP_OTA_MAX) {
String result = F("OTA partition ");
result += (partitionSubType - ESP_PARTITION_SUBTYPE_APP_OTA_MIN);
return result;
}
switch (partitionSubType) {
case ESP_PARTITION_SUBTYPE_APP_FACTORY: return F("Factory app");
case ESP_PARTITION_SUBTYPE_APP_TEST: return F("Test app");
default: break;
}
}
if (partitionType == ESP_PARTITION_TYPE_DATA) {
switch (partitionSubType) {
case ESP_PARTITION_SUBTYPE_DATA_OTA: return F("OTA selection");
case ESP_PARTITION_SUBTYPE_DATA_PHY: return F("PHY init data");
case ESP_PARTITION_SUBTYPE_DATA_NVS: return F("NVS");
case ESP_PARTITION_SUBTYPE_DATA_COREDUMP: return F("COREDUMP");
case ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD: return F("ESPHTTPD");
case ESP_PARTITION_SUBTYPE_DATA_FAT: return F("FAT");
case ESP_PARTITION_SUBTYPE_DATA_SPIFFS: return F("SPIFFS");
default: break;
}
}
String result = F("Unknown(");
result += partitionSubType;
result += ')';
return result;
}
String getPartitionTableHeader(const String& itemSep, const String& lineEnd) {
String result;
result += F("Address");
result += itemSep;
result += F("Size");
result += itemSep;
result += F("Label");
result += itemSep;
result += F("Partition Type");
result += itemSep;
result += F("Encrypted");
result += lineEnd;
return result;
}
String getPartitionTable(byte pType, const String& itemSep, const String& lineEnd) {
esp_partition_type_t partitionType = static_cast<esp_partition_type_t>(pType);
String result;
const esp_partition_t * _mypart;
esp_partition_iterator_t _mypartiterator = esp_partition_find(partitionType, ESP_PARTITION_SUBTYPE_ANY, NULL);
if (_mypartiterator) {
do {
_mypart = esp_partition_get(_mypartiterator);
result += formatToHex(_mypart->address);
result += itemSep;
result += formatToHex_decimal(_mypart->size, 1024);
result += itemSep;
result += _mypart->label;
result += itemSep;
result += getPartitionType(_mypart->type, _mypart->subtype);
result += itemSep;
result += (_mypart->encrypted ? F("Yes") : F("-"));
result += lineEnd;
} while ((_mypartiterator = esp_partition_next(_mypartiterator)) != NULL);
}
esp_partition_iterator_release(_mypartiterator);
return result;
}
#endif
+144
View File
@@ -2,6 +2,7 @@
#define ESPEASY_TIMETYPES_H_
#include <stdint.h>
#include <list>
struct timeStruct {
timeStruct() : Second(0), Minute(0), Hour(0), Wday(0), Day(0), Month(0), Year(0) {}
@@ -65,6 +66,149 @@ uint32_t calcTimeChangeForRule(const TimeChangeRule& r, int yr);
String getTimeString(char delimiter, bool show_seconds=true);
String getTimeString_ampm(char delimiter, bool show_seconds=true);
long timeDiff(unsigned long prev, unsigned long next);
long timePassedSince(unsigned long timestamp);
boolean timeOutReached(unsigned long timer);
long usecPassedSince(unsigned long timestamp);
boolean usecTimeOutReached(unsigned long timer);
void setSystemTimer(unsigned long timer, byte plugin, short taskIndex, int Par1,
int Par2 = 0, int Par3 = 0, int Par4 = 0, int Par5 = 0);
/*********************************************************************************************\
* TimerHandler Used by the Scheduler
\*********************************************************************************************/
struct timer_id_couple {
timer_id_couple(unsigned long id, unsigned long newtimer) : _id(id), _timer(newtimer) {}
timer_id_couple(unsigned long id) : _id(id) {
_timer = millis();
}
bool operator<(const timer_id_couple& other) {
const unsigned long now(millis());
// timediff > 0, means timer has already passed
return (timeDiff(_timer, now) > timeDiff(other._timer, now));
}
unsigned long _id;
unsigned long _timer;
};
struct msecTimerHandlerStruct {
msecTimerHandlerStruct() : get_called(0), get_called_ret_id(0), max_queue_length(0),
last_exec_time_usec(0), total_idle_time_usec(0), is_idle(false), idle_time_pct(0.0)
{
last_log_start_time = millis();
}
void registerAt(unsigned long id, unsigned long timer) {
timer_id_couple item(id, timer);
insert(item);
}
// Check if timeout has been reached and also return its set timer.
// Return 0 if no item has reached timeout moment.
unsigned long getNextId(unsigned long& timer) {
++get_called;
if (_timer_ids.empty()) {
recordIdle();
return 0;
}
timer_id_couple item = _timer_ids.front();
if (!timeOutReached(item._timer)) {
recordIdle();
return 0;
}
recordRunning();
unsigned long size = _timer_ids.size();
if (size > max_queue_length) max_queue_length = size;
_timer_ids.pop_front();
timer = item._timer;
++get_called_ret_id;
return item._id;
}
String getQueueStats() {
String result;
result += get_called;
result += '/';
result += get_called_ret_id;
result += '/';
result += max_queue_length;
result += '/';
result += idle_time_pct;
get_called = 0;
get_called_ret_id = 0;
//max_queue_length = 0;
return result;
}
void updateIdleTimeStats() {
const long duration = timePassedSince(last_log_start_time);
last_log_start_time = millis();
idle_time_pct = total_idle_time_usec / duration / 10.0;
total_idle_time_usec = 0;
}
float getIdleTimePct() {
return idle_time_pct;
}
private:
struct match_id {
match_id(unsigned long id) : _id(id) {}
bool operator() (const timer_id_couple& item) { return _id == item._id; }
unsigned long _id;
};
void insert(const timer_id_couple& item) {
if (item._id == 0) return;
// Make sure only one is present with the same id.
_timer_ids.remove_if(match_id(item._id));
const bool mustSort = !_timer_ids.empty();
_timer_ids.push_front(item);
if (mustSort)
_timer_ids.sort(); // TD-er: Must check if this is an expensive operation.
// It should be a relative light operation, to insert into a sorted list.
// Perhaps it is better to use std::set ????
// Keep in mind: order is based on timer, uniqueness is based on id.
}
void recordIdle() {
if (is_idle) return;
last_exec_time_usec = micros();
is_idle = true;
yield(); // Nothing to do, so call yield for backgroundtasks
}
void recordRunning() {
if (!is_idle) return;
is_idle = false;
total_idle_time_usec += usecPassedSince(last_exec_time_usec);
}
// Statistics
unsigned long get_called;
unsigned long get_called_ret_id;
unsigned long max_queue_length;
// Compute idle system time
unsigned long last_exec_time_usec;
unsigned long total_idle_time_usec;
unsigned long last_log_start_time;
bool is_idle;
float idle_time_pct;
// The list of set timers
std::list<timer_id_couple> _timer_ids;
};
#endif /* ESPEASY_TIMETYPES_H_ */
+151 -109
View File
@@ -11,19 +11,21 @@ void processConnect() {
++wifi_reconnects;
if (wifiStatus < ESPEASY_WIFI_CONNECTED) return;
const long connect_duration = timeDiff(last_wifi_connect_attempt_moment, lastConnectMoment);
String log = F("WIFI : Connected! AP: ");
log += WiFi.SSID();
log += F(" (");
log += WiFi.BSSIDstr();
log += F(") Ch: ");
log += last_channel;
if (connect_duration > 0 && connect_duration < 30000) {
// Just log times when they make sense.
log += F(" Duration: ");
log += connect_duration;
log += F(" ms");
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("WIFI : Connected! AP: ");
log += WiFi.SSID();
log += F(" (");
log += WiFi.BSSIDstr();
log += F(") Ch: ");
log += last_channel;
if (connect_duration > 0 && connect_duration < 30000) {
// Just log times when they make sense.
log += F(" Duration: ");
log += connect_duration;
log += F(" ms");
}
addLog(LOG_LEVEL_INFO, log);
}
addLog(LOG_LEVEL_INFO, log);
if (Settings.UseRules && bssid_changed) {
String event = F("WiFi#ChangedAccesspoint");
rulesProcessing(event);
@@ -42,14 +44,16 @@ void processDisconnect() {
String event = F("WiFi#Disconnected");
rulesProcessing(event);
}
String log = F("WIFI : Disconnected! Reason: '");
log += getLastDisconnectReason();
log += F("'");
if (lastConnectedDuration > 0) {
log += F(" Connected for ");
log += format_msec_duration(lastConnectedDuration);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("WIFI : Disconnected! Reason: '");
log += getLastDisconnectReason();
log += F("'");
if (lastConnectedDuration > 0) {
log += F(" Connected for ");
log += format_msec_duration(lastConnectedDuration);
}
addLog(LOG_LEVEL_INFO, log);
}
addLog(LOG_LEVEL_INFO, log);
logConnectionStatus();
}
@@ -64,52 +68,57 @@ void processGotIP() {
processedGetIP = true;
const IPAddress gw = WiFi.gatewayIP();
const IPAddress subnet = WiFi.subnetMask();
String log = F("WIFI : ");
if (useStaticIP()) {
log += F("Static IP: ");
} else {
log += F("DHCP IP: ");
}
log += formatIP(ip);
log += F(" (");
log += WifiGetHostname();
log += F(") GW: ");
log += formatIP(gw);
log += F(" SN: ");
log += formatIP(subnet);
const long dhcp_duration = timeDiff(lastConnectMoment, lastGetIPmoment);
if (dhcp_duration > 0 && dhcp_duration < 30000) {
// Just log times when they make sense.
log += F(" duration: ");
log += dhcp_duration;
log += F(" ms");
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("WIFI : ");
if (useStaticIP()) {
log += F("Static IP: ");
} else {
log += F("DHCP IP: ");
}
log += formatIP(ip);
log += F(" (");
log += WifiGetHostname();
log += F(") GW: ");
log += formatIP(gw);
log += F(" SN: ");
log += formatIP(subnet);
if (dhcp_duration > 0 && dhcp_duration < 30000) {
// Just log times when they make sense.
log += F(" duration: ");
log += dhcp_duration;
log += F(" ms");
}
addLog(LOG_LEVEL_INFO, log);
}
addLog(LOG_LEVEL_INFO, log);
// fix octet?
if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255)
{
ip[3] = Settings.IP_Octet;
log = F("IP : Fixed IP octet:");
log += formatIP(ip);
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("IP : Fixed IP octet:");
log += formatIP(ip);
addLog(LOG_LEVEL_INFO, log);
}
WiFi.config(ip, gw, subnet);
}
#ifdef FEATURE_MDNS
log = F("WIFI : ");
if (MDNS.begin(WifiGetHostname().c_str(), WiFi.localIP())) {
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("WIFI : ");
if (MDNS.begin(WifiGetHostname().c_str(), WiFi.localIP())) {
log += F("mDNS started, with name: ");
log += WifiGetHostname();
log += F(".local");
log += F("mDNS started, with name: ");
log += WifiGetHostname();
log += F(".local");
}
else{
log += F("mDNS failed");
}
addLog(LOG_LEVEL_INFO, log);
}
else{
log += F("mDNS failed");
}
addLog(LOG_LEVEL_INFO, log);
#endif
// First try to get the time, since that may be used in logs
@@ -118,7 +127,7 @@ void processGotIP() {
}
mqtt_reconnect_count = 0;
timermqtt_interval = 100;
timermqtt = millis() + timermqtt_interval;
setIntervalTimer(TIMER_MQTT);
if (Settings.UseRules)
{
String event = F("WiFi#Connected");
@@ -140,11 +149,13 @@ void processGotIP() {
void processConnectAPmode() {
if (processedConnectAPmode) return;
processedConnectAPmode = true;
String log = F("AP Mode: Client connected: ");
log += formatMAC(lastMacConnectedAPmode);
log += F(" Connected devices: ");
log += WiFi.softAPgetStationNum();
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("AP Mode: Client connected: ");
log += formatMAC(lastMacConnectedAPmode);
log += F(" Connected devices: ");
log += WiFi.softAPgetStationNum();
addLog(LOG_LEVEL_INFO, log);
}
timerAPoff = 0; // Disable timer to switch AP off
setWebserverRunning(true);
// Start DNS, only used if the ESP has no valid WiFi config
@@ -160,11 +171,13 @@ void processDisconnectAPmode() {
if (processedDisconnectAPmode) return;
processedDisconnectAPmode = true;
const int nrStationsConnected = WiFi.softAPgetStationNum();
String log = F("AP Mode: Client disconnected: ");
log += formatMAC(lastMacDisconnectedAPmode);
log += F(" Connected devices: ");
log += nrStationsConnected;
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("AP Mode: Client disconnected: ");
log += formatMAC(lastMacDisconnectedAPmode);
log += F(" Connected devices: ");
log += nrStationsConnected;
addLog(LOG_LEVEL_INFO, log);
}
if (nrStationsConnected == 0) {
timerAPoff = millis() + WIFI_AP_OFF_TIMER_DURATION;
}
@@ -183,9 +196,11 @@ void processDisableAPmode() {
void processScanDone() {
if (processedScanDone) return;
processedScanDone = true;
String log = F("WIFI : Scan finished, found: ");
log += scan_done_number;
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("WIFI : Scan finished, found: ");
log += scan_done_number;
addLog(LOG_LEVEL_INFO, log);
}
int bestScanID = -1;
int32_t bestRssi = -1000;
@@ -207,9 +222,11 @@ void processScanDone() {
if (!selectNextWiFiSettings()) done = true;
}
if (bestScanID >= 0) {
log = F("WIFI : Selected: ");
log += formatScanResult(bestScanID, " ");
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("WIFI : Selected: ");
log += formatScanResult(bestScanID, " ");
addLog(LOG_LEVEL_INFO, log);
}
lastWiFiSettings = bestWiFiSettings;
uint8_t * scanbssid = WiFi.BSSID(bestScanID);
if (scanbssid) {
@@ -333,17 +350,21 @@ void setAPinternal(bool enable)
addLog(LOG_LEVEL_ERROR, F("WIFI : [AP] softAPConfig failed!"));
}
if (WiFi.softAP(softAPSSID.c_str(),pwd.c_str())) {
String log(F("WIFI : AP Mode ssid will be "));
log += softAPSSID;
log += F(" with address ");
log += WiFi.softAPIP().toString();
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log(F("WIFI : AP Mode ssid will be "));
log += softAPSSID;
log += F(" with address ");
log += WiFi.softAPIP().toString();
addLog(LOG_LEVEL_INFO, log);
}
} else {
String log(F("WIFI : Error while starting AP Mode with SSID: "));
log += softAPSSID;
log += F(" IP: ");
log += apIP.toString();
addLog(LOG_LEVEL_ERROR, log);
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
String log(F("WIFI : Error while starting AP Mode with SSID: "));
log += softAPSSID;
log += F(" IP: ");
log += apIP.toString();
addLog(LOG_LEVEL_ERROR, log);
}
}
#ifdef ESP32
@@ -445,7 +466,6 @@ bool prepareWiFi() {
return false;
}
setSTA(true);
String log = "";
char hostname[40];
strncpy(hostname, WifiGetHostname().c_str(), sizeof(hostname));
#if defined(ESP8266)
@@ -524,15 +544,17 @@ void setupStaticIPconfig() {
const IPAddress gw = Settings.Gateway;
const IPAddress subnet = Settings.Subnet;
const IPAddress dns = Settings.DNS;
String log = F("IP : Static IP : ");
log += formatIP(ip);
log += F(" GW: ");
log += formatIP(gw);
log += F(" SN: ");
log += formatIP(subnet);
log += F(" DNS: ");
log += formatIP(dns);
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("IP : Static IP : ");
log += formatIP(ip);
log += F(" GW: ");
log += formatIP(gw);
log += F(" SN: ");
log += formatIP(subnet);
log += F(" DNS: ");
log += formatIP(dns);
addLog(LOG_LEVEL_INFO, log);
}
WiFi.config(ip, gw, subnet, dns);
}
@@ -564,11 +586,13 @@ bool tryConnectWiFi() {
}
const char* ssid = getLastWiFiSettingsSSID();
const char* passphrase = getLastWiFiSettingsPassphrase();
String log = F("WIFI : Connecting ");
log += ssid;
log += F(" attempt #");
log += wifi_connect_attempt;
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("WIFI : Connecting ");
log += ssid;
log += F(" attempt #");
log += wifi_connect_attempt;
addLog(LOG_LEVEL_INFO, log);
}
setupStaticIPconfig();
last_wifi_connect_attempt_moment = millis();
switch (wifi_connect_attempt) {
@@ -585,15 +609,19 @@ bool tryConnectWiFi() {
logConnectionStatus();
switch (WiFi.status()) {
case WL_NO_SSID_AVAIL: {
log = F("WIFI : No SSID found matching: ");
log += ssid;
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("WIFI : No SSID found matching: ");
log += ssid;
addLog(LOG_LEVEL_INFO, log);
}
return false;
}
case WL_CONNECT_FAILED: {
log = F("WIFI : Connection failed to: ");
log += ssid;
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("WIFI : Connection failed to: ");
log += ssid;
addLog(LOG_LEVEL_INFO, log);
}
return false;
}
default:
@@ -728,18 +756,22 @@ void logConnectionStatus() {
#ifndef ESP32
const uint8_t sdk_wifistatus = wifi_station_get_connect_status();
if ((arduino_corelib_wifistatus == WL_CONNECTED) != (sdk_wifistatus == STATION_GOT_IP)) {
log = F("WIFI : SDK station status differs from Arduino status. SDK-status: ");
log += SDKwifiStatusToString(sdk_wifistatus);
log += F(" Arduino status: ");
log += ArduinoWifiStatusToString(arduino_corelib_wifistatus);
addLog(LOG_LEVEL_ERROR, log);
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
String log = F("WIFI : SDK station status differs from Arduino status. SDK-status: ");
log += SDKwifiStatusToString(sdk_wifistatus);
log += F(" Arduino status: ");
log += ArduinoWifiStatusToString(arduino_corelib_wifistatus);
addLog(LOG_LEVEL_ERROR, log);
}
}
#endif
log = F("WIFI : Arduino wifi status: ");
log += ArduinoWifiStatusToString(arduino_corelib_wifistatus);
log += F(" ESPeasy internal wifi status: ");
log += ESPeasyWifiStatusToString();
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
String log = F("WIFI : Arduino wifi status: ");
log += ArduinoWifiStatusToString(arduino_corelib_wifistatus);
log += F(" ESPeasy internal wifi status: ");
log += ESPeasyWifiStatusToString();
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
}
@@ -752,6 +784,16 @@ void WifiCheck()
return;
processDisableAPmode();
IPAddress ip = WiFi.localIP();
if (!useStaticIP()) {
if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0) {
if (WiFiConnected()) {
// Some strange situation where the DHCP renew probably has failed and erased the config.
resetWiFi();
}
}
}
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) {
if (timeOutReached(last_wifi_connect_attempt_moment + (1000 + wifi_connect_attempt * 200))) {
WiFiConnectRelaxed();
+254 -712
View File
File diff suppressed because it is too large Load Diff
+17 -12
View File
@@ -121,9 +121,11 @@ void checkUDP()
formatMAC(mac, macaddress);
char ipaddress[20];
formatIP(ip, ipaddress);
char log[80];
sprintf_P(log, PSTR("UDP : %s,%s,%u"), macaddress, ipaddress, unit);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
char log[80];
sprintf_P(log, PSTR("UDP : %s,%s,%u"), macaddress, ipaddress, unit);
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
break;
}
@@ -181,9 +183,12 @@ void sendUDP(byte unit, byte* data, byte size)
if (unit != 255)
if (Nodes[unit].ip[0] == 0)
return;
String log = F("UDP : Send UDP message to ");
log += unit;
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
String log = F("UDP : Send UDP message to ");
log += unit;
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
statusLED(true);
@@ -220,7 +225,6 @@ void refreshNodeList()
\*********************************************************************************************/
void sendSysInfoUDP(byte repeats)
{
char log[80];
if (Settings.UDPPort == 0 || !WiFiConnected(100))
return;
@@ -235,8 +239,7 @@ void sendSysInfoUDP(byte repeats)
// 1 byte node type id
// send my info to the world...
strcpy_P(log, PSTR("UDP : Send Sysinfo message"));
addLog(LOG_LEVEL_DEBUG_MORE, log);
addLog(LOG_LEVEL_DEBUG_MORE, F("UDP : Send Sysinfo message"));
for (byte counter = 0; counter < repeats; counter++)
{
uint8_t mac[] = {0, 0, 0, 0, 0, 0};
@@ -635,9 +638,11 @@ bool hostReachable(const IPAddress& ip) {
delay(50);
--retry;
}
String log = F("Host unreachable: ");
log += formatIP(ip);
addLog(LOG_LEVEL_ERROR, log);
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
String log = F("Host unreachable: ");
log += formatIP(ip);
addLog(LOG_LEVEL_ERROR, log);
}
if (ip[1] == 0 && ip[2] == 0 && ip[3] == 0) {
// Work-around to fix connected but not able to communicate.
addLog(LOG_LEVEL_ERROR, F("Wifi : Detected strange behavior, reconnect wifi."));
+194
View File
@@ -0,0 +1,194 @@
#define TIMER_ID_SHIFT 28
#define CONST_INTERVAL_TIMER 1
#define GENERIC_TIMER 2
#define SYSTEM_TIMER 3
#define TASK_DEVICE_TIMER 4
void setTimer(unsigned long id) {
setTimer(GENERIC_TIMER, id, 0);
}
void setIntervalTimer(unsigned long id) {
setIntervalTimer(id, millis());
}
void setIntervalTimerOverride(unsigned long id, unsigned long msecFromNow) {
unsigned long timer = millis();
setNextTimeInterval(timer, msecFromNow);
setNewTimerAt(getMixedId(CONST_INTERVAL_TIMER, id), timer);
}
void setIntervalTimer(unsigned long id, unsigned long lasttimer) {
// Set the initial timers for the regular runs
unsigned long interval = 0;
switch (id) {
case TIMER_20MSEC: interval = 20; break;
case TIMER_100MSEC: interval = 100; break;
case TIMER_1SEC: interval = 1000; break;
case TIMER_30SEC: interval = 30000; break;
case TIMER_MQTT: interval = timermqtt_interval; break;
case TIMER_STATISTICS: interval = 30000; break;
}
unsigned long timer = lasttimer;
setNextTimeInterval(timer, interval);
setNewTimerAt(getMixedId(CONST_INTERVAL_TIMER, id), timer);
}
void setTimer(unsigned long timerType, unsigned long id, unsigned long msecFromNow) {
setNewTimerAt(getMixedId(timerType, id), millis() + msecFromNow);
}
void setSystemTimer(unsigned long timer, byte plugin, short taskIndex, int Par1, int Par2, int Par3, int Par4, int Par5)
{
// plugin number and par1 form a unique key that can be used to restart a timer
const unsigned long systemTimerId = createSystemTimerId(plugin, Par1);
systemTimerStruct timer_data;
timer_data.TaskIndex = taskIndex;
timer_data.Par1 = Par1;
timer_data.Par2 = Par2;
timer_data.Par3 = Par3;
timer_data.Par4 = Par4;
timer_data.Par5 = Par5;
systemTimers[systemTimerId] = timer_data;
setTimer(SYSTEM_TIMER, systemTimerId, timer);
}
void setNewTimerAt(unsigned long id, unsigned long timer) {
START_TIMER;
msecTimerHandler.registerAt(id, timer);
STOP_TIMER(SET_NEW_TIMER);
}
unsigned long createSystemTimerId(byte plugin, int Par1) {
const unsigned long mask = (1 << TIMER_ID_SHIFT) -1;
const unsigned long mixed = (Par1 << 8) + plugin;
return (mixed & mask);
}
/* // Not (yet) used
void splitSystemTimerId(const unsigned long mixed_id, byte& plugin, int& Par1) {
const unsigned long mask = (1 << TIMER_ID_SHIFT) -1;
plugin = mixed_id & 0xFF;
Par1 = (mixed_id & mask) >> 8;
}
*/
unsigned long getMixedId(unsigned long timerType, unsigned long id) {
return (timerType << TIMER_ID_SHIFT) + id;
}
void handle_schedule() {
unsigned long timer;
const unsigned long mixed_id = msecTimerHandler.getNextId(timer);
if (mixed_id == 0) return;
const unsigned long timerType = (mixed_id >> TIMER_ID_SHIFT);
const unsigned long mask = (1 << TIMER_ID_SHIFT) -1;
const unsigned long id = mixed_id & mask;
switch (timerType) {
case CONST_INTERVAL_TIMER:
setIntervalTimer(id, timer);
process_interval_timer(id);
break;
case SYSTEM_TIMER:
process_system_timer(id);
break;
case TASK_DEVICE_TIMER:
process_task_device_timer(id, timer);
break;
}
}
void process_interval_timer(unsigned long id) {
switch (id) {
case TIMER_20MSEC:
run50TimesPerSecond();
break;
case TIMER_100MSEC:
if(!UseRTOSMultitasking)
run10TimesPerSecond();
break;
case TIMER_1SEC:
runOncePerSecond();
break;
case TIMER_30SEC:
runEach30Seconds();
break;
case TIMER_MQTT:
runPeriodicalMQTT();
break;
case TIMER_STATISTICS:
logTimerStatistics();
break;
}
}
void process_system_timer(unsigned long id) {
START_TIMER;
const systemTimerStruct timer_data = systemTimers[id];
struct EventStruct TempEvent;
TempEvent.TaskIndex = timer_data.TaskIndex;
TempEvent.Par1 = timer_data.Par1;
TempEvent.Par2 = timer_data.Par2;
TempEvent.Par3 = timer_data.Par3;
TempEvent.Par4 = timer_data.Par4;
TempEvent.Par5 = timer_data.Par5;
// TD-er: Not sure if we have to keep original source for notifications.
TempEvent.Source = VALUE_SOURCE_SYSTEM;
const int y = getPluginId(timer_data.TaskIndex);
/*
String log = F("proc_system_timer: Pluginid: ");
log += y;
log += F(" taskIndex: ");
log += timer_data.TaskIndex;
log += F(" sysTimerID: ");
log += id;
addLog(LOG_LEVEL_INFO, log);
*/
if (y >= 0) {
String dummy;
Plugin_ptr[y](PLUGIN_TIMER_IN, &TempEvent, dummy);
}
systemTimers.erase(id);
STOP_TIMER(PROC_SYS_TIMER);
}
void schedule_task_device_timer_at_init(unsigned long task_index) {
unsigned long runAt = millis();
if (!isDeepSleepEnabled()) {
// Deepsleep is not enabled, add some offset based on the task index
// to make sure not all are run at the same time.
// This scheduled time may be overriden by the plugin's own init.
runAt += (task_index * 37) + Settings.MessageDelay;
}
schedule_task_device_timer(task_index, runAt);
}
void schedule_task_device_timer(unsigned long task_index, unsigned long runAt) {
/*
String log = F("schedule_task_device_timer: task: ");
log += task_index;
log += F(" @ ");
log += runAt;
if (Settings.TaskDeviceEnabled[task_index]) {
log += F(" (enabled)");
}
addLog(LOG_LEVEL_INFO, log);
*/
if (task_index >= TASKS_MAX) return;
if (Settings.TaskDeviceEnabled[task_index]) {
setNewTimerAt(getMixedId(TASK_DEVICE_TIMER, task_index), runAt);
}
}
void process_task_device_timer(unsigned long task_index, unsigned long lasttimer) {
unsigned long newtimer = Settings.TaskDeviceTimer[task_index];
if (newtimer != 0) {
newtimer = lasttimer + (newtimer * 1000);
schedule_task_device_timer(task_index, newtimer);
}
START_TIMER;
SensorSendTask(task_index);
STOP_TIMER(SENSOR_SEND_TASK);
}
+144 -39
View File
@@ -60,14 +60,18 @@ String formatMAC(const uint8_t* mac) {
return String(str);
}
String formatToHex(unsigned long value) {
String result = F("0x");
String formatToHex(unsigned long value, const String& prefix) {
String result = prefix;
String hex(value, HEX);
hex.toUpperCase();
result += hex;
return result;
}
String formatToHex(unsigned long value) {
return formatToHex(value, F("0x"));
}
String formatHumanReadable(unsigned long value, unsigned long factor) {
float floatValue(value);
byte steps = 0;
@@ -83,7 +87,7 @@ String formatHumanReadable(unsigned long value, unsigned long factor) {
case 2: result += 'M'; break;
case 3: result += 'G'; break;
case 4: result += 'T'; break;
default:
default:
result += '*';
result += factor;
result += '^';
@@ -135,10 +139,10 @@ String toString(WiFiMode_t mode)
break;
case WIFI_AP_STA:
result = F("AP+STA");
break;
break;
default:
break;
}
}
return result;
}
@@ -229,49 +233,123 @@ String to_json_object_value(const String& object, const String& value) {
return result;
}
/*********************************************************************************************\
Parse a string and get the xth command or parameter
Strip wrapping chars (e.g. quotes)
\*********************************************************************************************/
String parseString(String& string, byte indexFind)
{
String tmpString = string;
tmpString += ',';
tmpString.replace(' ', ',');
String locateString = "";
byte count = 0;
int index = tmpString.indexOf(',');
while (index > 0)
{
count++;
locateString = tmpString.substring(0, index);
tmpString = tmpString.substring(index + 1);
index = tmpString.indexOf(',');
if (count == indexFind)
{
locateString.toLowerCase();
return locateString;
}
String stripWrappingChar(const String& text, char wrappingChar) {
unsigned int length = text.length();
if (length >= 2 && stringWrappedWithChar(text, wrappingChar)) {
return text.substring(1, length -1);
}
return "";
return text;
}
bool stringWrappedWithChar(const String& text, char wrappingChar) {
unsigned int length = text.length();
if (length < 2) return false;
if (text.charAt(0) != wrappingChar) return false;
return (text.charAt(length - 1) == wrappingChar);
}
bool isQuoteChar(char c) {
return (c == '\'' || c == '"');
}
bool isParameterSeparatorChar(char c) {
return (c == ',' || c == ' ');
}
String stripQuotes(const String& text) {
if (text.length() >= 2) {
char c = text.charAt(0);
if (isQuoteChar(c)) {
return stripWrappingChar(text, c);
}
}
return text;
}
/*********************************************************************************************\
Parse a string and get the xth command or parameter in lower case
\*********************************************************************************************/
String parseString(const String& string, byte indexFind, bool toEndOfString, bool toLowerCase) {
int startpos = 0;
if (indexFind > 0) {
startpos = getParamStartPos(string, indexFind);
if (startpos < 0) {
return "";
}
}
const int endpos = getParamStartPos(string, indexFind + 1);
String result;
if (toEndOfString || endpos <= 0) {
result = string.substring(startpos);
} else {
result = string.substring(startpos, endpos - 1);
}
if (toLowerCase)
result.toLowerCase();
return stripQuotes(result);
}
String parseString(const String& string, byte indexFind) {
return parseString(string, indexFind, false, true);
}
String parseStringKeepCase(const String& string, byte indexFind) {
return parseString(string, indexFind, false, false);
}
String parseStringToEnd(const String& string, byte indexFind) {
return parseString(string, indexFind, true, true);
}
String parseStringToEndKeepCase(const String& string, byte indexFind) {
return parseString(string, indexFind, true, false);
}
/*********************************************************************************************\
Parse a string and get the xth command or parameter
\*********************************************************************************************/
int getParamStartPos(String& string, byte indexFind)
int getParamStartPos(const String& string, byte indexFind)
{
String tmpString = string;
byte count = 0;
tmpString.replace(' ', ',');
for (unsigned int x = 0; x < tmpString.length(); x++)
// We need to find the xth command, so we need to find the position of the (X-1)th separator.
if (indexFind <= 1) return 0;
byte count = 1;
bool quotedStringActive = false;
char quoteStartChar = '"';
unsigned int lastParamStartPos = 0;
const unsigned int strlength = string.length();
if (strlength < indexFind) return -1;
for (unsigned int x = 0; x < (strlength - 1); ++x)
{
if (tmpString.charAt(x) == ',')
{
count++;
if (count == (indexFind - 1))
return x + 1;
const char c = string.charAt(x);
// Check if we are parsing a quoted string parameter
if (!quotedStringActive) {
if (isQuoteChar(c)) {
// Only allow ' or " right after parameter separator.
if (lastParamStartPos == x ) {
quotedStringActive = true;
quoteStartChar = c;
}
}
} else {
if (c == quoteStartChar) {
// Found end of quoted string
quotedStringActive = false;
}
}
// Do further parsing.
if (!quotedStringActive) {
if (isParameterSeparatorChar(c))
{
lastParamStartPos = x + 1;
++count;
if (count == indexFind) {
return lastParamStartPos;
}
}
}
}
return -1;
@@ -386,6 +464,7 @@ void parseSpecialCharacters(String& s, boolean useURLencode)
// Simple macro to create the replacement string only when needed.
#define SMART_REPL(T,S) if (s.indexOf(T) != -1) { repl((T), (S), s, useURLencode);}
#define SMART_REPL_T(T,S) if (s.indexOf(T) != -1) { (S((T), s, useURLencode));}
void parseSystemVariables(String& s, boolean useURLencode)
{
parseSpecialCharacters(s, useURLencode);
@@ -398,6 +477,8 @@ void parseSystemVariables(String& s, boolean useURLencode)
repl(F("%CR%"), F("\r"), s, useURLencode);
repl(F("%LF%"), F("\n"), s, useURLencode);
repl(F("%SP%"), F(" "), s, useURLencode); //space
repl(F("%R%"), F("\\r"), s, useURLencode);
repl(F("%N%"), F("\\n"), s, useURLencode);
SMART_REPL(F("%ip4%"),WiFi.localIP().toString().substring(WiFi.localIP().toString().lastIndexOf('.')+1)) //4th IP octet
SMART_REPL(F("%ip%"),WiFi.localIP().toString())
SMART_REPL(F("%rssi%"), String((wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? 0 : WiFi.RSSI()))
@@ -438,9 +519,10 @@ void parseSystemVariables(String& s, boolean useURLencode)
SMART_REPL(F("%lcltime_am%"), getDateTimeString_ampm('-',':',' '))
SMART_REPL(F("%uptime%"), String(wdcounter / 2))
SMART_REPL(F("%unixtime%"), String(getUnixTime()))
SMART_REPL(F("%sunrise%"), getSunriseTimeString(':'))
SMART_REPL(F("%sunset%"), getSunsetTimeString(':'))
SMART_REPL_T(F("%sunset"), replSunSetTimeString)
SMART_REPL_T(F("%sunrise"), replSunRiseTimeString)
// FIXME TD-er: Must make sure LoadTaskSettings has been performed before this is called.
repl(F("%tskname%"), ExtraTaskSettings.TaskDeviceName, s, useURLencode);
if (s.indexOf(F("%vname")) != -1) {
repl(F("%vname1%"), ExtraTaskSettings.TaskDeviceValueNames[0], s, useURLencode);
@@ -450,6 +532,28 @@ void parseSystemVariables(String& s, boolean useURLencode)
}
}
String getReplacementString(const String& format, String& s) {
int startpos = s.indexOf(format);
int endpos = s.indexOf('%', startpos + 1);
String R = s.substring(startpos, endpos + 1);
String log = F("ReplacementString SunTime: ");
log += R;
log += F(" offset: ");
log += getSecOffset(R);
addLog(LOG_LEVEL_DEBUG, log);
return R;
}
void replSunRiseTimeString(const String& format, String& s, boolean useURLencode) {
String R = getReplacementString(format, s);
repl(R, getSunriseTimeString(':', getSecOffset(R)), s, useURLencode);
}
void replSunSetTimeString(const String& format, String& s, boolean useURLencode) {
String R = getReplacementString(format, s);
repl(R, getSunsetTimeString(':', getSecOffset(R)), s, useURLencode);
}
void parseEventVariables(String& s, struct EventStruct *event, boolean useURLencode)
{
SMART_REPL(F("%id%"), String(event->idx))
@@ -464,6 +568,7 @@ void parseEventVariables(String& s, struct EventStruct *event, boolean useURLenc
}
}
}
#undef SMART_REPL_T
#undef SMART_REPL
bool getConvertArgument(const String& marker, const String& s, float& argument, int& startIndex, int& endIndex) {
+75 -10
View File
@@ -17,6 +17,7 @@ uint32_t syncInterval = 3600; // time sync will be attempted after this many se
uint32_t sysTime = 0;
uint32_t prevMillis = 0;
uint32_t nextSyncTime = 0;
timeStruct tsRise, tsSet;
timeStruct sunRise;
timeStruct sunSet;
@@ -62,7 +63,6 @@ void calcSunRiseAndSet() {
float da = diurnalArc(dec, Settings.Latitude);
float rise = 12 - da - eqt - Settings.Longitude / 15.0;
float set = 12 + da - eqt - Settings.Longitude / 15.0;
timeStruct tsRise, tsSet;
tsRise.Hour = (int)rise;
tsRise.Minute = (rise - (int)rise) * 60.0;
tsSet.Hour = (int)set;
@@ -74,6 +74,25 @@ void calcSunRiseAndSet() {
breakTime(toLocal(makeTime(tsSet)), sunSet);
}
timeStruct getSunRise(int secOffset) {
return addSeconds(tsRise, secOffset, true);
}
timeStruct getSunSet(int secOffset) {
return addSeconds(tsSet, secOffset, true);
}
timeStruct addSeconds(const timeStruct& ts, int seconds, bool toLocalTime) {
unsigned long time = makeTime(ts);
time += seconds;
if (toLocalTime) {
time = toLocal(time);
}
timeStruct result;
breakTime(time, result);
return result;
}
void breakTime(unsigned long timeInput, struct timeStruct &tm) {
uint8_t year;
uint8_t month, monthLength;
@@ -142,6 +161,30 @@ uint32_t getUnixTime() {
return sysTime;
}
int getSecOffset(const String& format) {
int position_minus = format.indexOf('-');
int position_plus = format.indexOf('+');
if (position_minus == -1 && position_plus == -1)
return 0;
int sign_position = _max(position_minus, position_plus);
int position_percent = format.indexOf('%', sign_position);
if (position_percent == -1) {
return 0;
}
String valueStr = getNumerical(format.substring(sign_position, position_percent), true);
if (!isInt(valueStr)) return 0;
int value = valueStr.toInt();
switch (format.charAt(position_percent - 1)) {
case 'm':
case 'M':
return value * 60;
case 'h':
case 'H':
return value * 3600;
}
return value;
}
String getSunriseTimeString(char delimiter) {
return getTimeString(sunRise, delimiter, false, false);
}
@@ -150,6 +193,19 @@ String getSunsetTimeString(char delimiter) {
return getTimeString(sunSet, delimiter, false, false);
}
String getSunriseTimeString(char delimiter, int secOffset) {
if (secOffset == 0)
return getSunriseTimeString(delimiter);
return getTimeString(getSunRise(secOffset), delimiter, false, false);
}
String getSunsetTimeString(char delimiter, int secOffset) {
if (secOffset == 0)
return getSunsetTimeString(delimiter);
return getTimeString(getSunSet(secOffset), delimiter, false, false);
}
unsigned long now() {
// calculate number of seconds passed since last call to now()
bool timeSynced = false;
@@ -331,16 +387,17 @@ unsigned long getNtpTime()
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
log = F("NTP : NTP replied: ");
log += timePassedSince(beginWait);
log += F(" mSec");
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
String log = F("NTP : NTP replied: ");
log += timePassedSince(beginWait);
log += F(" mSec");
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
return secsSince1900 - 2208988800UL;
}
delay(10);
}
log = F("NTP : No reply");
addLog(LOG_LEVEL_DEBUG_MORE, log);
addLog(LOG_LEVEL_DEBUG_MORE, F("NTP : No reply"));
return 0;
}
@@ -355,6 +412,7 @@ unsigned long getNtpTime()
// Returned value is positive when "next" is after "prev"
long timeDiff(const unsigned long prev, const unsigned long next)
{
unsigned long start = ESP.getCycleCount();
long signed_diff = 0;
// To cast a value to a signed long, the difference may not exceed half the ULONG_MAX
const unsigned long half_max_unsigned_long = 2147483647u; // = 2^31 -1
@@ -381,6 +439,11 @@ long timeDiff(const unsigned long prev, const unsigned long next)
signed_diff = static_cast<long>((ULONG_MAX - prev) + next + 1u);
}
}
unsigned long end = ESP.getCycleCount();
if (end > start) {
++timediff_calls;
timediff_cpu_cycles_total += (end - start);
}
return signed_diff;
}
@@ -573,8 +636,9 @@ unsigned long string2TimeLong(const String &str)
// format 0000WWWWAAAABBBBCCCCDDDD
// WWWW=weekday, AAAA=hours tens digit, BBBB=hours, CCCC=minutes tens digit DDDD=minutes
#define TmpStr1Length 10
char command[20];
char TmpStr1[10];
char TmpStr1[TmpStr1Length];
int w, x, y;
unsigned long a;
{
@@ -585,7 +649,7 @@ unsigned long string2TimeLong(const String &str)
}
unsigned long lngTime = 0;
if (GetArgv(command, TmpStr1, 1))
if (GetArgv(command, TmpStr1, TmpStr1Length, 1))
{
String day = TmpStr1;
String weekDays = F("allsunmontuewedthufrisatwrkwkd");
@@ -595,7 +659,7 @@ unsigned long string2TimeLong(const String &str)
lngTime |= (unsigned long)y << 16;
}
if (GetArgv(command, TmpStr1, 2))
if (GetArgv(command, TmpStr1, TmpStr1Length, 2))
{
y = 0;
for (x = strlen(TmpStr1) - 1; x >= 0; x--)
@@ -619,6 +683,7 @@ unsigned long string2TimeLong(const String &str)
}
}
}
#undef TmpStr1Length
return lngTime;
}
+192 -78
View File
@@ -149,15 +149,16 @@ public:
sendContentBlocking(buf);
finalRam = ESP.getFreeHeap();
/*
String log = String("Ram usage: Webserver only: ") + maxServerUsage +
" including Core: " + maxCoreUsage +
" flashStringCalls: " + flashStringCalls +
" flashStringData: " + flashStringData;
addLog(LOG_LEVEL_DEBUG, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = String("Ram usage: Webserver only: ") + maxServerUsage +
" including Core: " + maxCoreUsage +
" flashStringCalls: " + flashStringCalls +
" flashStringData: " + flashStringData;
addLog(LOG_LEVEL_DEBUG, log);
}
*/
} else {
String log = String("Webpage skipped: low memory: ") + finalRam;
addLog(LOG_LEVEL_DEBUG, log);
addLog(LOG_LEVEL_DEBUG, String("Webpage skipped: low memory: ") + finalRam);
lowMemorySkip = false;
}
}
@@ -167,8 +168,7 @@ void sendContentBlocking(String& data) {
checkRAM(F("sendContentBlocking"));
uint32_t freeBeforeSend = ESP.getFreeHeap();
const uint32_t length = data.length();
String log = String("sendcontent free: ") + freeBeforeSend + " chunk size:" + length;
addLog(LOG_LEVEL_DEBUG_DEV, log);
addLog(LOG_LEVEL_DEBUG_DEV, String("sendcontent free: ") + freeBeforeSend + " chunk size:" + length);
freeBeforeSend = ESP.getFreeHeap();
if (TXBuffer.beforeTXRam > freeBeforeSend)
TXBuffer.beforeTXRam = freeBeforeSend;
@@ -355,11 +355,13 @@ boolean clientIPallowed()
String response = F("IP blocked: ");
response += formatIP(client.remoteIP());
WebServer.send(403, "text/html", response);
response += F(" Allowed: ");
response += formatIP(low);
response += F(" - ");
response += formatIP(high);
addLog(LOG_LEVEL_ERROR, response);
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
response += F(" Allowed: ");
response += formatIP(low);
response += F(" - ");
response += formatIP(high);
addLog(LOG_LEVEL_ERROR, response);
}
return false;
}
@@ -425,7 +427,13 @@ bool isFormItem(const String& id)
void addHtmlError(String error){
if (error.length()>0)
{
TXBuffer += F("<div class=\"alert\"><span class=\"closebtn\" onclick=\"this.parentElement.style.display='none';\">&times;</span>");
TXBuffer += F("<div class=\"");
if (error.startsWith(F("Warn"))) {
TXBuffer += F("warning");
} else {
TXBuffer += F("alert");
}
TXBuffer += F("\"><span class=\"closebtn\" onclick=\"this.parentElement.style.display='none';\">&times;</span>");
TXBuffer += error;
TXBuffer += F("</div>");
}
@@ -727,9 +735,11 @@ void getWebPageTemplateVar(const String& varName )
else
{
String log = F("Templ: Unknown Var : ");
log += varName;
addLog(LOG_LEVEL_ERROR, log);
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
String log = F("Templ: Unknown Var : ");
log += varName;
addLog(LOG_LEVEL_ERROR, log);
}
//no return string - eat var name
}
@@ -747,10 +757,12 @@ void writeDefaultCSS(void)
fs::File f = SPIFFS.open(F("esp.css"), "w");
if (f)
{
String log = F("CSS : Writing default CSS file to SPIFFS (");
log += defaultCSS.length();
log += F(" bytes)");
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("CSS : Writing default CSS file to SPIFFS (");
log += defaultCSS.length();
log += F(" bytes)");
addLog(LOG_LEVEL_INFO, log);
}
defaultCSS= PGMT(pgDefaultCSS);
f.write((const unsigned char*)defaultCSS.c_str(), defaultCSS.length()); //note: content must be in RAM - a write of F("XXX") does not work
f.close();
@@ -939,21 +951,18 @@ void handle_root() {
// disconnect here could result into a crash/reboot...
if (strcasecmp_P(sCommand.c_str(), PSTR("wifidisconnect")) == 0)
{
String log = F("WIFI : Disconnecting...");
addLog(LOG_LEVEL_INFO, log);
addLog(LOG_LEVEL_INFO, F("WIFI : Disconnecting..."));
cmd_within_mainloop = CMD_WIFI_DISCONNECT;
}
if (strcasecmp_P(sCommand.c_str(), PSTR("reboot")) == 0)
{
String log = F(" : Rebooting...");
addLog(LOG_LEVEL_INFO, log);
addLog(LOG_LEVEL_INFO, F(" : Rebooting..."));
cmd_within_mainloop = CMD_REBOOT;
}
if (strcasecmp_P(sCommand.c_str(), PSTR("reset")) == 0)
{
String log = F(" : factory reset...");
addLog(LOG_LEVEL_INFO, log);
addLog(LOG_LEVEL_INFO, F(" : factory reset..."));
cmd_within_mainloop = CMD_REBOOT;
TXBuffer+= F("OK. Please wait > 1 min and connect to Acces point.<BR><BR>PW=configesp<BR>URL=<a href='http://192.168.4.1'>192.168.4.1</a>");
TXBuffer.endStream();
@@ -1818,12 +1827,15 @@ void handle_devices() {
}
const int edit = getFormItemInt(F("edit"), 0);
// taskIndex in the URL is 1 ... TASKS_MAX
// For use in other functions, set it to 0 ... (TASKS_MAX - 1)
byte taskIndex = getFormItemInt(F("index"), 0);
boolean taskIndexNotSet = taskIndex == 0;
--taskIndex;
byte DeviceIndex = 0;
LoadTaskSettings(taskIndex); // Make sure ExtraTaskSettings are up-to-date
// FIXME TD-er: Might have to clear any caches here.
if (edit != 0 && !taskIndexNotSet) // when form submitted
{
if (Settings.TaskDeviceNumber[taskIndex] != taskdevicenumber) // change of device: cleanup old device and reset default settings
@@ -1841,7 +1853,7 @@ void handle_devices() {
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) // if field set empty, reload defaults
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, &TempEvent, dummyString); //the plugin should populate ExtraTaskSettings with its default values.
ClearCustomTaskSettings(taskIndex);
ClearCustomTaskSettings(taskIndex);
}
}
else if (taskdevicenumber != 0) //save settings
@@ -2118,13 +2130,16 @@ void handle_devices() {
addFormNote(F("This plugin is only supported on task 1-4 for now"));
}
addFormTextBox( F("Name"), F("TDN"), ExtraTaskSettings.TaskDeviceName, 40); //="taskdevicename"
addFormTextBox( F("Name"), F("TDN"), ExtraTaskSettings.TaskDeviceName, NAME_FORMULA_LENGTH_MAX); //="taskdevicename"
addFormCheckBox(F("Enabled"), F("TDE"), Settings.TaskDeviceEnabled[taskIndex]); //="taskdeviceenabled"
// section: Sensor / Actuator
if (!Device[DeviceIndex].Custom && Settings.TaskDeviceDataFeed[taskIndex] == 0 &&
((Device[DeviceIndex].Ports != 0) || (Device[DeviceIndex].PullUpOption) || (Device[DeviceIndex].InverseLogicOption) || (Device[DeviceIndex].Type >= DEVICE_TYPE_SINGLE && Device[DeviceIndex].Type <= DEVICE_TYPE_TRIPLE)) )
((Device[DeviceIndex].Ports != 0) ||
(Device[DeviceIndex].PullUpOption) ||
(Device[DeviceIndex].InverseLogicOption) ||
(Device[DeviceIndex].connectedToGPIOpins())) )
{
addFormSubHeader((Device[DeviceIndex].SendDataOption) ? F("Sensor") : F("Actuator"));
@@ -2150,12 +2165,14 @@ void handle_devices() {
TempEvent.String3 = F("3rd GPIO");
PluginCall(PLUGIN_GET_DEVICEGPIONAMES, &TempEvent, dummyString);
if (Device[DeviceIndex].Type >= DEVICE_TYPE_SINGLE && Device[DeviceIndex].Type <= DEVICE_TYPE_TRIPLE)
addFormPinSelect(TempEvent.String1, F("taskdevicepin1"), Settings.TaskDevicePin1[taskIndex]);
if (Device[DeviceIndex].Type >= DEVICE_TYPE_DUAL && Device[DeviceIndex].Type <= DEVICE_TYPE_TRIPLE)
addFormPinSelect( TempEvent.String2, F("taskdevicepin2"), Settings.TaskDevicePin2[taskIndex]);
if (Device[DeviceIndex].Type == DEVICE_TYPE_TRIPLE)
addFormPinSelect(TempEvent.String3, F("taskdevicepin3"), Settings.TaskDevicePin3[taskIndex]);
if (Device[DeviceIndex].connectedToGPIOpins()) {
if (Device[DeviceIndex].Type >= DEVICE_TYPE_SINGLE)
addFormPinSelect(TempEvent.String1, F("taskdevicepin1"), Settings.TaskDevicePin1[taskIndex]);
if (Device[DeviceIndex].Type >= DEVICE_TYPE_DUAL)
addFormPinSelect( TempEvent.String2, F("taskdevicepin2"), Settings.TaskDevicePin2[taskIndex]);
if (Device[DeviceIndex].Type == DEVICE_TYPE_TRIPLE)
addFormPinSelect(TempEvent.String3, F("taskdevicepin3"), Settings.TaskDevicePin3[taskIndex]);
}
}
//add plugins content
@@ -2193,7 +2210,7 @@ void handle_devices() {
TXBuffer += F("<TR><TD>IDX:<TD>");
id = F("TDID"); //="taskdeviceid"
id += controllerNr + 1;
addNumericBox(id, Settings.TaskDeviceID[controllerNr][taskIndex], 0, 9999);
addNumericBox(id, Settings.TaskDeviceID[controllerNr][taskIndex], 0, 999999999); // Looks like it is an unsigned int, so could be up to 4 bln.
}
}
}
@@ -2239,14 +2256,14 @@ void handle_devices() {
TXBuffer += F("<TD>");
String id = F("TDVN"); //="taskdevicevaluename"
id += (varNr + 1);
addTextBox(id, ExtraTaskSettings.TaskDeviceValueNames[varNr], 40);
addTextBox(id, ExtraTaskSettings.TaskDeviceValueNames[varNr], NAME_FORMULA_LENGTH_MAX);
if (Device[DeviceIndex].FormulaOption)
{
TXBuffer += F("<TD>");
String id = F("TDF"); //="taskdeviceformula"
id += (varNr + 1);
addTextBox(id, ExtraTaskSettings.TaskDeviceFormula[varNr], 40);
addTextBox(id, ExtraTaskSettings.TaskDeviceFormula[varNr], NAME_FORMULA_LENGTH_MAX);
}
if (Device[DeviceIndex].FormulaOption || Device[DeviceIndex].DecimalsOnly)
@@ -2280,9 +2297,11 @@ void handle_devices() {
checkRAM(F("handle_devices"));
String log = F("DEBUG: String size:");
log += String(TXBuffer.sentBytes);
addLog(LOG_LEVEL_DEBUG_DEV, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_DEV)) {
String log = F("DEBUG: String size:");
log += String(TXBuffer.sentBytes);
addLog(LOG_LEVEL_DEBUG_DEV, log);
}
sendHeadandTail(F("TmplStd"),_TAIL);
TXBuffer.endStream();
}
@@ -3607,6 +3626,7 @@ void stream_last_json_object_value(const String& object, const String& value) {
void handle_json()
{
const int taskNr = getFormItemInt(F("tasknr"), -1);
const bool showSpecificTask = taskNr > 0;
bool showSystem = true;
bool showWifi = true;
bool showDataAcquisition = true;
@@ -3623,7 +3643,7 @@ void handle_json()
}
}
TXBuffer.startJsonStream();
if (taskNr == -1)
if (!showSpecificTask)
{
TXBuffer += '{';
if (showSystem) {
@@ -3675,7 +3695,7 @@ void handle_json()
byte firstTaskIndex = 0;
byte lastTaskIndex = TASKS_MAX - 1;
if (taskNr > 0 )
if (showSpecificTask)
{
firstTaskIndex = taskNr - 1;
lastTaskIndex = taskNr - 1;
@@ -3686,7 +3706,7 @@ void handle_json()
lastActiveTaskIndex = TaskIndex;
}
if (taskNr == 0 ) TXBuffer += F("\"Sensors\":[\n");
if (!showSpecificTask) TXBuffer += F("\"Sensors\":[\n");
unsigned long ttl_json = 60; // The shortest interval per enabled task (with output values) in seconds
for (byte TaskIndex = firstTaskIndex; TaskIndex <= lastActiveTaskIndex; TaskIndex++)
{
@@ -3714,7 +3734,7 @@ void handle_json()
}
TXBuffer += F("],\n");
}
if (taskNr != 0) {
if (showSpecificTask) {
stream_next_json_object_value(F("TTL"), String(ttl_json * 1000));
}
if (showDataAcquisition) {
@@ -3742,7 +3762,7 @@ void handle_json()
TXBuffer += F("\n");
}
}
if (taskNr == 0) {
if (!showSpecificTask) {
TXBuffer += F("],\n");
stream_last_json_object_value(F("TTL"), String(ttl_json * 1000));
}
@@ -3790,12 +3810,13 @@ void handle_advanced() {
if (dst_end.isValid()) { Settings.DST_End = dst_end.toFlashStoredValue(); }
str2ip(syslogip.c_str(), Settings.Syslog_IP);
Settings.UDPPort = getFormItemInt(F("udpport"));
Settings.SyslogLevel = getFormItemInt(F("sysloglevel"));
Settings.SyslogFacility = getFormItemInt(F("syslogfacility"));
Settings.UseSerial = isFormItemChecked(F("useserial"));
Settings.SerialLogLevel = getFormItemInt(F("serialloglevel"));
Settings.WebLogLevel = getFormItemInt(F("webloglevel"));
Settings.SDLogLevel = getFormItemInt(F("sdloglevel"));
setLogLevelFor(LOG_TO_SYSLOG, getFormItemInt(F("sysloglevel")));
setLogLevelFor(LOG_TO_SERIAL, getFormItemInt(F("serialloglevel")));
setLogLevelFor(LOG_TO_WEBLOG, getFormItemInt(F("webloglevel")));
setLogLevelFor(LOG_TO_SDCARD, getFormItemInt(F("sdloglevel")));
Settings.UseValueLogger = isFormItemChecked(F("valuelogger"));
Settings.BaudRate = getFormItemInt(F("baudrate"));
Settings.UseNTP = isFormItemChecked(F("usentp"));
@@ -4088,7 +4109,6 @@ void handleFileUpload() {
if (!isLoggedIn()) return;
static boolean valid = false;
String log = "";
HTTPUpload& upload = WebServer.upload();
@@ -4100,9 +4120,11 @@ void handleFileUpload() {
if (upload.status == UPLOAD_FILE_START)
{
log = F("Upload: START, filename: ");
log += upload.filename;
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("Upload: START, filename: ");
log += upload.filename;
addLog(LOG_LEVEL_INFO, log);
}
valid = false;
uploadResult = 0;
}
@@ -4139,16 +4161,20 @@ void handleFileUpload() {
}
}
if (uploadFile) uploadFile.write(upload.buf, upload.currentSize);
log = F("Upload: WRITE, Bytes: ");
log += upload.currentSize;
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("Upload: WRITE, Bytes: ");
log += upload.currentSize;
addLog(LOG_LEVEL_INFO, log);
}
}
else if (upload.status == UPLOAD_FILE_END)
{
if (uploadFile) uploadFile.close();
log = F("Upload: END, Size: ");
log += upload.totalSize;
addLog(LOG_LEVEL_INFO, log);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("Upload: END, Size: ");
log += upload.totalSize;
addLog(LOG_LEVEL_INFO, log);
}
}
if (valid)
@@ -4182,8 +4208,11 @@ bool loadFromFS(boolean spiffs, String path) {
else if (path.endsWith(F(".txt"))) dataType = F("application/octet-stream");
else if (path.endsWith(F(".dat"))) dataType = F("application/octet-stream");
else if (path.endsWith(F(".esp"))) return handle_custom(path);
String log = F("HTML : Request file ");
log += path;
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = F("HTML : Request file ");
log += path;
addLog(LOG_LEVEL_DEBUG, log);
}
path = path.substring(1);
if (spiffs)
@@ -4215,8 +4244,6 @@ bool loadFromFS(boolean spiffs, String path) {
#endif
}
statusLED(true);
addLog(LOG_LEVEL_DEBUG, log);
return true;
}
@@ -4689,9 +4716,11 @@ void handle_setup() {
strncpy(SecuritySettings.WifiKey, password.c_str(), sizeof(SecuritySettings.WifiKey));
strncpy(SecuritySettings.WifiSSID, ssid.c_str(), sizeof(SecuritySettings.WifiSSID));
wifiSetupConnect = true;
String reconnectlog = F("WIFI : Credentials Changed, retry connection. SSID: ");
reconnectlog += ssid;
addLog(LOG_LEVEL_INFO, reconnectlog);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String reconnectlog = F("WIFI : Credentials Changed, retry connection. SSID: ");
reconnectlog += ssid;
addLog(LOG_LEVEL_INFO, reconnectlog);
}
status = 1;
refreshCount = 0;
}
@@ -5222,15 +5251,15 @@ void handle_sysinfo() {
addHelpButton(F("https://dl.espressif.com/doc/esp-idf/latest/api-guides/partition-tables.html"));
TXBuffer += F("</H3></TD></TR>");
TXBuffer += F("<TR><TD>Data Partition Table<TD><tt>");
TXBuffer += getPartitionTableHeader(F(" - "), F("<BR>"));
TXBuffer += getPartitionTable(ESP_PARTITION_TYPE_DATA, F(" - "), F("<BR>"));
TXBuffer += F("</tt>");
TXBuffer += F("<TR><TD>Data Partition Table<TD>");
// TXBuffer += getPartitionTableHeader(F(" - "), F("<BR>"));
// TXBuffer += getPartitionTable(ESP_PARTITION_TYPE_DATA, F(" - "), F("<BR>"));
getPartitionTableSVG(ESP_PARTITION_TYPE_DATA, 0x5856e6);
TXBuffer += F("<TR><TD>App Partition Table<TD><tt>");
TXBuffer += getPartitionTableHeader(F(" - "), F("<BR>"));
TXBuffer += getPartitionTable(ESP_PARTITION_TYPE_APP , F(" - "), F("<BR>"));
TXBuffer += F("</tt>");
TXBuffer += F("<TR><TD>App Partition Table<TD>");
// TXBuffer += getPartitionTableHeader(F(" - "), F("<BR>"));
// TXBuffer += getPartitionTable(ESP_PARTITION_TYPE_APP , F(" - "), F("<BR>"));
getPartitionTableSVG(ESP_PARTITION_TYPE_APP, 0xab56e6);
#endif
TXBuffer += F("</table></form>");
@@ -5286,3 +5315,88 @@ void handle_favicon() {
checkRAM(F("handle_favicon"));
WebServer.send_P(200, PSTR("image/x-icon"), favicon_8b_ico, favicon_8b_ico_len);
}
#ifdef ESP32
void createSvgRectPath(unsigned int color, int xoffset, int yoffset, int size, int height, int range, float svgBarWidth) {
float width = svgBarWidth * size / range;
if (width < 2) width = 2;
TXBuffer += formatToHex(color, F("<path fill=\"#"));
TXBuffer += F("\" d=\"M");
TXBuffer += toString(svgBarWidth * xoffset / range, 2);
TXBuffer += ' ';
TXBuffer += yoffset;
TXBuffer += 'h';
TXBuffer += toString(width, 2);
TXBuffer += 'v';
TXBuffer += height;
TXBuffer += 'H';
TXBuffer += toString(svgBarWidth * xoffset / range, 2);
TXBuffer += F("z\"/>\n");
}
int getPartionCount(byte pType) {
esp_partition_type_t partitionType = static_cast<esp_partition_type_t>(pType);
esp_partition_iterator_t _mypartiterator = esp_partition_find(partitionType, ESP_PARTITION_SUBTYPE_ANY, NULL);
int nrPartitions = 0;
if (_mypartiterator) {
do {
++nrPartitions;
} while ((_mypartiterator = esp_partition_next(_mypartiterator)) != NULL);
}
esp_partition_iterator_release(_mypartiterator);
return nrPartitions;
}
void createSvgTextElement(const String& text, float textXoffset, float textYoffset) {
TXBuffer += F("<text style=\"line-height:1.25\" x=\"");
TXBuffer += toString(textXoffset, 2);
TXBuffer += F("\" y=\"");
TXBuffer += toString(textYoffset, 2);
TXBuffer += F("\" stroke-width=\".3\" font-family=\"sans-serif\" font-size=\"8\" letter-spacing=\"0\" word-spacing=\"0\">\n");
TXBuffer += F("<tspan x=\"");
TXBuffer += toString(textXoffset, 2);
TXBuffer += F("\" y=\"");
TXBuffer += toString(textYoffset, 2);
TXBuffer += F("\">");
TXBuffer += text;
TXBuffer += F("</tspan>\n</text>");
}
void getPartitionTableSVG(byte pType, unsigned int partitionColor) {
int nrPartitions = getPartionCount(pType);
if (nrPartitions == 0) return;
const int barHeight = 16;
const int svgBarWidth = 200;
const int shiftY = 2;
uint32_t realSize = getFlashRealSizeInBytes();
esp_partition_type_t partitionType = static_cast<esp_partition_type_t>(pType);
const esp_partition_t * _mypart;
esp_partition_iterator_t _mypartiterator = esp_partition_find(partitionType, ESP_PARTITION_SUBTYPE_ANY, NULL);
TXBuffer += F("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"500\" height=\"");
TXBuffer += nrPartitions * barHeight + shiftY;
TXBuffer += F("\">");
int partNr = 0;
if (_mypartiterator) {
do {
_mypart = esp_partition_get(_mypartiterator);
float yOffset = partNr * barHeight + shiftY;
createSvgRectPath(0xcdcdcd, 0, yOffset, realSize, barHeight - 2, realSize, svgBarWidth);
createSvgRectPath(partitionColor, _mypart->address, yOffset, _mypart->size, barHeight - 2, realSize, svgBarWidth);
float textXoffset = svgBarWidth + 2;
float textYoffset = yOffset + 0.9 * barHeight;
createSvgTextElement(formatHumanReadable(_mypart->size, 1024), textXoffset, textYoffset);
textXoffset = svgBarWidth + 60;
createSvgTextElement(_mypart->label, textXoffset, textYoffset);
textXoffset = svgBarWidth + 130;
createSvgTextElement(getPartitionType(_mypart->type, _mypart->subtype), textXoffset, textYoffset);
++partNr;
} while ((_mypartiterator = esp_partition_next(_mypartiterator)) != NULL);
}
TXBuffer += F("</svg>\n");
esp_partition_iterator_release(_mypartiterator);
}
#endif
+18 -26
View File
@@ -255,6 +255,7 @@ static const char pgDefaultCSS[] PROGMEM = {
".div_br {clear: both; }"
// The alert message box
".alert {padding: 20px; background-color: #f44336; color: white; margin-bottom: 15px; }"
".warning {padding: 20px; background-color: #ffca17; color: white; margin-bottom: 15px; }"
// The close button
".closebtn {margin-left: 15px; color: white; font-weight: bold; float: right; font-size: 22px; line-height: 20px; cursor: pointer; transition: 0.3s; }"
// When moving the mouse over the close button
@@ -463,11 +464,11 @@ static const char jsFetchAndParseLog[] PROGMEM = {
"textToDisplay = 'Fetching log entries...';"
"}"
"document.getElementById('copyText_1').innerHTML = textToDisplay;"
"loopDeLoop(1000, 0, 0);"
"loopDeLoop(1000, 0);"
"const logLevel = new Array('Unused','Error','Info','Debug','Debug More','Undefined','Undefined','Undefined','Undefined','Debug Dev');"
"function loopDeLoop(timeForNext, activeRequests, reRunCount) {"
"function loopDeLoop(timeForNext, activeRequests) {"
"const maximumRequests = 1;"
"const url = '/logjson';"
"if (isNaN(activeRequests)){activeRequests = maximumRequests;}"
@@ -504,7 +505,7 @@ static const char jsFetchAndParseLog[] PROGMEM = {
"if (logEntriesChunk == null) {"
"logEntriesChunk = '';"
"}"
"for (c = 0; c < data.Log.nrEntries + 1; c++) {"
"for (c = 0; c < data.Log.nrEntries; ++c) {"
"try {"
"logEntry = data.Log.Entries[c].timestamp;"
"} catch (err) {"
@@ -517,32 +518,23 @@ static const char jsFetchAndParseLog[] PROGMEM = {
"}"
"}"
"timeForNext = data.Log.TTL;"
"if (timeForNext < 1000) {"
"reRunCount++;"
"} else {"
"reRunCount = 3;"
"}"
//"console.log(reRunCount + ' : ' + logEntriesChunk.length);"
"if (reRunCount > 2) {"
"if (logEntriesChunk !== '') {"
"if (document.getElementById('copyText_1').innerHTML == 'Fetching log entries...') {"
"document.getElementById('copyText_1').innerHTML = '';"
"}"
"document.getElementById('copyText_1').innerHTML += logEntriesChunk;"
"}"
"logEntriesChunk = '';"
"reRunCount = 0;"
"autoscroll_on = document.getElementById('autoscroll').checked;"
"if (autoscroll_on == true && currentIDtoScrollTo !== '') {"
"document.getElementById(currentIDtoScrollTo).scrollIntoView({"
"behavior: scrolling_type"
"});"
"}"
"if (logEntriesChunk !== '') {"
"if (document.getElementById('copyText_1').innerHTML == 'Fetching log entries...') {"
"document.getElementById('copyText_1').innerHTML = '';"
"}"
"document.getElementById('copyText_1').innerHTML += logEntriesChunk;"
"}"
"logEntriesChunk = '';"
"autoscroll_on = document.getElementById('autoscroll').checked;"
"if (autoscroll_on == true && currentIDtoScrollTo !== '') {"
"document.getElementById(currentIDtoScrollTo).scrollIntoView({"
"behavior: scrolling_type"
"});"
"}"
"document.getElementById('current_loglevel').innerHTML = 'Logging: ' + logLevel[data.Log.SettingsWebLogLevel] + ' (' + data.Log.SettingsWebLogLevel + ')';"
//"console.log('Next fetch in: ' + timeForNext + 'mSec, active requests: ' + activeRequests);"
"clearInterval(i);"
"loopDeLoop(timeForNext, 0, reRunCount);"
"loopDeLoop(timeForNext, 0);"
"return;"
"})"
"})"
@@ -552,7 +544,7 @@ static const char jsFetchAndParseLog[] PROGMEM = {
"document.getElementById('copyText_1').scrollTop = document.getElementById('copyText_1').scrollHeight;"
"timeForNext = 5000;"
"clearInterval(i);"
"loopDeLoop(timeForNext, 0, 0);"
"loopDeLoop(timeForNext, 0);"
"return;"
"})};"
"check = 1;"
+16 -8
View File
@@ -59,8 +59,10 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
if (!ControllerSettings.connectToHost(client))
{
connectionFailures++;
strcpy_P(log, PSTR("HTTP : connection failed"));
addLog(LOG_LEVEL_ERROR, log);
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
strcpy_P(log, PSTR("HTTP : connection failed"));
addLog(LOG_LEVEL_ERROR, log);
}
return false;
}
statusLED(true);
@@ -107,18 +109,24 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
String line;
safeReadStringUntil(client, line, '\n');
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
if (line.substring(0, 15) == F("HTTP/1.1 200 OK"))
{
strcpy_P(log, PSTR("HTTP : Success!"));
addLog(LOG_LEVEL_DEBUG, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
strcpy_P(log, PSTR("HTTP : Success!"));
addLog(LOG_LEVEL_DEBUG, log);
}
success = true;
}
delay(1);
}
strcpy_P(log, PSTR("HTTP : closing connection"));
addLog(LOG_LEVEL_DEBUG, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
strcpy_P(log, PSTR("HTTP : closing connection"));
addLog(LOG_LEVEL_DEBUG, log);
}
client.flush();
client.stop();
+4 -2
View File
@@ -102,8 +102,10 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
String line;
safeReadStringUntil(client, line, '\n');
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
line.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
if (line.substring(0, 15) == F("HTTP/1.1 200 OK"))
{
strcpy_P(log, PSTR("HTTP : Success!"));
+1 -1
View File
@@ -100,7 +100,7 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
// Each sensor value get an own object (0..n)
// sprintf(itemNames[x],"%d",x);
JsonObject& val = SENSOR.createNestedObject(String(x));
val[F("deviceName")] = ExtraTaskSettings.TaskDeviceName;
val[F("deviceName")] = getTaskDeviceName(event->TaskIndex);
val[F("valueName")] = ExtraTaskSettings.TaskDeviceValueNames[x];
val[F("type")] = event->sensorType;
val[F("value")] = formatUserVarNoCheck(event, x);
+5 -4
View File
@@ -71,7 +71,6 @@ void C010_Send(struct EventStruct *event, byte varIndex, const String& formatted
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
char log[80];
// boolean success = false;
addLog(LOG_LEVEL_DEBUG, String(F("UDP : sending to ")) + ControllerSettings.getHostPortString());
statusLED(true);
@@ -91,8 +90,10 @@ void C010_Send(struct EventStruct *event, byte varIndex, const String& formatted
portUDP.endPacket();
}
msg.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
char log[80];
msg.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
}
#endif
+17 -12
View File
@@ -117,7 +117,7 @@ void C013_SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskInde
infoReply.destTaskIndex = destTaskIndex;
LoadTaskSettings(infoReply.sourceTaskIndex);
infoReply.deviceNumber = Settings.TaskDeviceNumber[infoReply.sourceTaskIndex];
strcpy(infoReply.taskName, ExtraTaskSettings.TaskDeviceName);
strcpy(infoReply.taskName, getTaskDeviceName(infoReply.sourceTaskIndex).c_str());
for (byte x = 0; x < VARS_PER_TASK; x++)
strcpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x]);
@@ -180,9 +180,11 @@ void C013_sendUDP(byte unit, byte* data, byte size)
if (unit != 255)
if (Nodes[unit].ip[0] == 0)
return;
String log = F("C013 : Send UDP message to ");
log += unit;
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
String log = F("C013 : Send UDP message to ");
log += unit;
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
statusLED(true);
@@ -197,16 +199,17 @@ void C013_sendUDP(byte unit, byte* data, byte size)
}
void C013_Receive(struct EventStruct *event) {
if (event->Data[1] > 1 && event->Data[1] < 6)
{
String log = (F("C013 : msg "));
for (byte x = 1; x < 6; x++)
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
if (event->Data[1] > 1 && event->Data[1] < 6)
{
log += " ";
log += (int)event->Data[x];
String log = (F("C013 : msg "));
for (byte x = 1; x < 6; x++)
{
log += " ";
log += (int)event->Data[x];
}
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
switch (event->Data[1]) {
@@ -225,6 +228,7 @@ void C013_Receive(struct EventStruct *event) {
// so it will write only once and has to be cleared manually through webgui
if (Settings.TaskDeviceNumber[infoReply.destTaskIndex] == 0)
{
taskClear(infoReply.destTaskIndex, false);
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed
for (byte x = 0; x < CONTROLLER_MAX; x++)
@@ -232,6 +236,7 @@ void C013_Receive(struct EventStruct *event) {
strcpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName);
for (byte x = 0; x < VARS_PER_TASK; x++)
strcpy( ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x]);
ExtraTaskSettings.TaskIndex = infoReply.destTaskIndex;
SaveTaskSettings(infoReply.destTaskIndex);
SaveSettings();
}
+12 -6
View File
@@ -141,10 +141,12 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
String device = parseString(string, 1);
String command = parseString(string, 2);
String strPar1 = parseString(string, 3);
int par1 = strPar1.toInt();
if (device == F("gpio") && command == F("pinstate"))
{
string = digitalRead(par1);
int par1;
if (validIntFromString(strPar1, par1)) {
string = digitalRead(par1);
}
success = true;
}
break;
@@ -324,11 +326,15 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
success = true;
if (event->Par1 >= 0 && event->Par1 <= PIN_D_MAX)
{
const bool pinStateHigh = event->Par2 != 0;
const uint16_t pinStateValue = pinStateHigh ? 1 : 0;
const uint16_t inversePinStateValue = pinStateHigh ? 0 : 1;
pinMode(event->Par1, OUTPUT);
digitalWrite(event->Par1, event->Par2);
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
setSystemTimer(time_in_msec ? event->Par3 : event->Par3 * 1000,
PLUGIN_ID_001, event->Par1, !event->Par2, 0);
digitalWrite(event->Par1, pinStateValue);
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, pinStateValue);
unsigned long timer = time_in_msec ? event->Par3 : event->Par3 * 1000;
// Create a future system timer call to set the GPIO pin back to its normal value.
setSystemTimer(timer, PLUGIN_ID_001, event->TaskIndex, event->Par1, inversePinStateValue);
log = String(F("SW : GPIO ")) + String(event->Par1) +
String(F(" Pulse set for ")) + String(event->Par3) + String(time_in_msec ? F(" msec") : F(" sec"));
addLog(LOG_LEVEL_INFO, log);
+1 -1
View File
@@ -146,7 +146,7 @@ boolean Plugin_009(byte function, struct EventStruct *event, String& string)
{
Plugin_009_Write(event->Par1, event->Par2);
setPinState(PLUGIN_ID_009, event->Par1, PIN_MODE_OUTPUT, event->Par2);
setSystemTimer(event->Par3 * 1000, PLUGIN_ID_009, event->Par1, !event->Par2, 0);
setSystemTimer(event->Par3 * 1000, PLUGIN_ID_009, event->TaskIndex, event->Par1, !event->Par2);
log = String(F("MCP : GPIO ")) + String(event->Par1) + String(F(" Pulse set for ")) + String(event->Par3) + String(F(" S"));
addLog(LOG_LEVEL_INFO, log);
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_009, event->Par1, log, 0));
+1 -1
View File
@@ -123,7 +123,7 @@ boolean Plugin_011(byte function, struct EventStruct *event, String& string)
if (event->Par1 >= 0 && event->Par1 <= 13)
{
Plugin_011_Write(event->Par1, event->Par2);
setSystemTimer(event->Par3 * 1000, PLUGIN_ID_011, event->Par1, !event->Par2, 0);
setSystemTimer(event->Par3 * 1000, PLUGIN_ID_011, event->TaskIndex, event->Par1, !event->Par2);
setPinState(PLUGIN_ID_011, event->Par1, PIN_MODE_OUTPUT, event->Par2);
log = String(F("PME : GPIO ")) + String(event->Par1) + String(F(" Pulse set for ")) + String(event->Par3) + String(F(" S"));
addLog(LOG_LEVEL_INFO, log);
+25 -1
View File
@@ -27,6 +27,7 @@
#define PN532_COMMAND_INLISTPASSIVETARGET (0x4A)
#define PN532_RESPONSE_INLISTPASSIVETARGET (0x4B)
#define PN532_MIFARE_ISO14443A (0x00)
#define PN532_COMMAND_POWERDOWN (0x16)
uint8_t Plugin_017_pn532_packetbuffer[64];
uint8_t Plugin_017_command;
@@ -95,7 +96,7 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string)
static byte errorCount=0;
counter++;
if (counter == 3)
if (counter == 3 )
{
if (digitalRead(4) == 0 || digitalRead(5) == 0)
{
@@ -123,6 +124,7 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string)
Plugin_017_Init(Settings.TaskDevicePin3[event->TaskIndex]);
}
if (error == 0) {
unsigned long key = uid[0];
for (uint8_t i = 1; i < 4; i++) {
@@ -232,6 +234,23 @@ uint32_t getFirmwareVersion(void)
}
void Plugin_017_powerDown(void)
{
Plugin_017_pn532_packetbuffer[0] = PN532_COMMAND_POWERDOWN;
Plugin_017_pn532_packetbuffer[1] = 1 << 7; //allowed wakeup source is i2c
if (Plugin_017_writeCommand(Plugin_017_pn532_packetbuffer, 2)) {
return;
}
// delay(50); // we can try to read faster, but it will only put extra load on the I2C bus...
// read and ignore response
Plugin_017_readResponse(Plugin_017_pn532_packetbuffer, sizeof(Plugin_017_pn532_packetbuffer));
}
/*********************************************************************************************\
* PN532 read tag
\*********************************************************************************************/
@@ -273,6 +292,10 @@ byte Plugin_017_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t
uid[i] = Plugin_017_pn532_packetbuffer[6 + i];
}
// Plugin_017_Init(-1);
Plugin_017_powerDown();
return 0;
}
@@ -325,6 +348,7 @@ int16_t Plugin_017_readResponse(uint8_t buf[], uint8_t len)
if (!Wire.requestFrom(PN532_I2C_ADDRESS, len + 2))
return -1;
if (!(Wire.read() & 1))
return -1;
+1 -1
View File
@@ -145,7 +145,7 @@ boolean Plugin_019(byte function, struct EventStruct *event, String& string)
success = true;
Plugin_019_Write(event->Par1, event->Par2);
setPinState(PLUGIN_ID_019, event->Par1, PIN_MODE_OUTPUT, event->Par2);
setSystemTimer(event->Par3 * 1000, PLUGIN_ID_019, event->Par1, !event->Par2, 0);
setSystemTimer(event->Par3 * 1000, PLUGIN_ID_019, event->TaskIndex, event->Par1, !event->Par2);
log = String(F("PCF : GPIO ")) + String(event->Par1) + String(F(" Pulse set for ")) + String(event->Par3) + String(F(" S"));
addLog(LOG_LEVEL_INFO, log);
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_019, event->Par1, log, 0));
+12 -12
View File
@@ -23,12 +23,12 @@
#define PCA9685_ALLLED_REG (byte)0xFA
/*
is bit flag any bit rapresent the initialization state of PCA9685
is bit flag any bit rapresent the initialization state of PCA9685
es: bit 3 is set 1 PCA9685 with address 0X40 + 0x03 is intin
*/
#define IS_INIT(state, bit) ((state & 1 << bit) == 1 << bit)
#define SET_INIT(state, bit) (state|= 1 << bit)
long long initializeState; //
long long initializeState; //
boolean Plugin_022(byte function, struct EventStruct *event, String& string)
{
@@ -85,7 +85,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
Settings.TaskDevicePort[event->TaskIndex] = getFormItemInt(F("i2c_addr"));
success = true;
break;
}
}
case PLUGIN_WRITE:
{
@@ -100,7 +100,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
String name = line.substring(0,dotPos);
name.replace(F("["),F(""));
name.replace(F("]"),F(""));
if(name.equalsIgnoreCase(ExtraTaskSettings.TaskDeviceName) == true)
if(name.equalsIgnoreCase(getTaskDeviceName(event->TaskIndex)) == true)
{
line = line.substring(dotPos + 1);
istanceCommand = true;
@@ -121,7 +121,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
if(event->Par2 >=0 && event->Par2 <= PCA9685_MAX_PWM)
{
if (!IS_INIT(initializeState, (address - PCA9685_ADDRESS))) Plugin_022_initialize(address);
Plugin_022_Write(address, event->Par1, event->Par2);
setPinState(PLUGIN_ID_022, event->Par1, PIN_MODE_PWM, event->Par2);
addLog(LOG_LEVEL_INFO, log);
@@ -139,7 +139,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
{
success = true;
if(event->Par1 >= PCA9685_MIN_FREQUENCY && event->Par1 <= PCA9685_MAX_FREQUENCY)
{
{
if (!IS_INIT(initializeState, (address - PCA9685_ADDRESS))) Plugin_022_initialize(address);
Plugin_022_Frequency(address, event->Par1);
@@ -150,7 +150,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
}
else{
addLog(LOG_LEVEL_ERROR,String(F("PCA ")) + String(address, HEX) + String(F(" The frequesncy ")) + String(event->Par1) + String(F(" is out of range.")));
}
}
}
@@ -175,7 +175,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
if(parseString(line,2) == "all")
{
pin = -1;
log += String(F("all"));
log += String(F("all"));
}
else
{
@@ -189,10 +189,10 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
else
{
log += F(" on");
Plugin_022_On(address, pin);
Plugin_022_On(address, pin);
}
addLog(LOG_LEVEL_INFO, log);
setPinState(PLUGIN_ID_022, pin, PIN_MODE_OUTPUT, event->Par2);
setPinState(PLUGIN_ID_022, pin, PIN_MODE_OUTPUT, event->Par2);
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_022, pin, log, 0));
}
else{
@@ -237,7 +237,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
log += String(autoreset);
}
}
}
setSystemTimer(event->Par3 , PLUGIN_ID_022
, event->TaskIndex
@@ -286,7 +286,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
, autoreset);
}
setPinState(PLUGIN_ID_022, event->Par1, PIN_MODE_OUTPUT, event->Par2);
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_022, event->Par1, log, 0));
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_022, event->Par1, log, 0));
break;
}
}
+4 -4
View File
@@ -235,7 +235,7 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
String name = arguments.substring(0,dotPos);
name.replace(F("["),F(""));
name.replace(F("]"),F(""));
if(name.equalsIgnoreCase(ExtraTaskSettings.TaskDeviceName) == true)
if(name.equalsIgnoreCase(getTaskDeviceName(event->TaskIndex)) == true)
{
arguments = arguments.substring(dotPos+1);
}
@@ -244,7 +244,7 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
return false;
}
}
int argIndex = arguments.indexOf(',');
if (argIndex)
arguments = arguments.substring(0, argIndex);
@@ -492,7 +492,7 @@ void Plugin_023_reset_display(struct Plugin_023_OLED_SettingStruct &oled)
void Plugin_023_StartUp_OLED(struct Plugin_023_OLED_SettingStruct &oled)
{
{
Plugin_023_init_OLED(oled);
Plugin_023_reset_display(oled);
Plugin_023_displayOff(oled);
@@ -644,7 +644,7 @@ void Plugin_023_init_OLED(struct Plugin_023_OLED_SettingStruct &oled)
multiplex = 0x3F;
compins = 0x12;
}
Plugin_023_sendcommand(address, 0xAE); //display off
Plugin_023_sendcommand(address, 0xD5); //SETDISPLAYCLOCKDIV
Plugin_023_sendcommand(address, 0x80); // the suggested ratio 0x80
+55 -39
View File
@@ -312,26 +312,28 @@ boolean Plugin_028(byte function, struct EventStruct *event, String& string)
} else {
UserVar[event->BaseVarIndex + 2] = sensor.last_press_val;
}
String log;
log.reserve(40); // Prevent re-allocation
log = sensor.getDeviceName();
log += F(" : Address: 0x");
log += String(i2cAddress,HEX);
addLog(LOG_LEVEL_INFO, log);
log = sensor.getDeviceName();
log += F(" : Temperature: ");
log += UserVar[event->BaseVarIndex];
addLog(LOG_LEVEL_INFO, log);
if (sensor.hasHumidity()) {
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log;
log.reserve(40); // Prevent re-allocation
log = sensor.getDeviceName();
log += F(" : Humidity: ");
log += UserVar[event->BaseVarIndex + 1];
log += F(" : Address: 0x");
log += String(i2cAddress,HEX);
addLog(LOG_LEVEL_INFO, log);
log = sensor.getDeviceName();
log += F(" : Temperature: ");
log += UserVar[event->BaseVarIndex];
addLog(LOG_LEVEL_INFO, log);
if (sensor.hasHumidity()) {
log = sensor.getDeviceName();
log += F(" : Humidity: ");
log += UserVar[event->BaseVarIndex + 1];
addLog(LOG_LEVEL_INFO, log);
}
log = sensor.getDeviceName();
log += F(" : Barometric Pressure: ");
log += UserVar[event->BaseVarIndex + 2];
addLog(LOG_LEVEL_INFO, log);
}
log = sensor.getDeviceName();
log += F(" : Barometric Pressure: ");
log += UserVar[event->BaseVarIndex + 2];
addLog(LOG_LEVEL_INFO, log);
success = true;
break;
}
@@ -395,9 +397,11 @@ bool Plugin_028_update_measurements(const uint8_t i2cAddress, float tempOffset)
String log;
log.reserve(120); // Prevent re-allocation
log = sensor.getDeviceName();
log += F(":");
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
log.reserve(120); // Prevent re-allocation
log = sensor.getDeviceName();
log += F(":");
}
boolean logAdded = false;
if (sensor.hasHumidity()) {
// Apply half of the temp offset, to correct the dew point offset.
@@ -409,34 +413,46 @@ bool Plugin_028_update_measurements(const uint8_t i2cAddress, float tempOffset)
}
if (tempOffset > 0.1 || tempOffset < -0.1) {
// There is some offset to apply.
log += F(" Apply temp offset ");
log += tempOffset;
log += F("C");
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
log += F(" Apply temp offset ");
log += tempOffset;
log += F("C");
}
if (sensor.hasHumidity()) {
log += F(" humidity ");
log += sensor.last_hum_val;
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
log += F(" humidity ");
log += sensor.last_hum_val;
}
sensor.last_hum_val = compute_humidity_from_dewpoint(sensor.last_temp_val + tempOffset, sensor.last_dew_temp_val);
log += F("% => ");
log += sensor.last_hum_val;
log += F("%");
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
log += F("% => ");
log += sensor.last_hum_val;
log += F("%");
}
} else {
sensor.last_hum_val = 0.0;
}
log += F(" temperature ");
log += sensor.last_temp_val;
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
log += F(" temperature ");
log += sensor.last_temp_val;
}
sensor.last_temp_val = sensor.last_temp_val + tempOffset;
log += F("C => ");
log += sensor.last_temp_val;
log += F("C");
logAdded = true;
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
log += F("C => ");
log += sensor.last_temp_val;
log += F("C");
logAdded = true;
}
}
if (sensor.hasHumidity()) {
log += F(" dew point ");
log += sensor.last_dew_temp_val;
log += F("C");
logAdded = true;
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
log += F(" dew point ");
log += sensor.last_dew_temp_val;
log += F("C");
logAdded = true;
}
}
if (logAdded)
if (logAdded && loglevelActiveFor(LOG_LEVEL_INFO))
addLog(LOG_LEVEL_INFO, log);
return true;
}
+10 -10
View File
@@ -80,7 +80,7 @@ boolean Plugin_035(byte function, struct EventStruct *event, String& string)
if (irReceiver != 0) irReceiver->disableIRIn(); // Stop the receiver
#endif
if (GetArgv(command, TmpStr1, 2)) IrType = TmpStr1;
if (GetArgv(command, TmpStr1, 100, 2)) IrType = TmpStr1;
if (IrType.equalsIgnoreCase(F("RAW"))) {
String IrRaw;
@@ -88,10 +88,10 @@ boolean Plugin_035(byte function, struct EventStruct *event, String& string)
unsigned int IrPLen=0;
unsigned int IrBLen=0;
if (GetArgv(command, TmpStr1, 3)) IrRaw = TmpStr1;
if (GetArgv(command, TmpStr1, 4)) IrHz = str2int(TmpStr1);
if (GetArgv(command, TmpStr1, 5)) IrPLen = str2int(TmpStr1);
if (GetArgv(command, TmpStr1, 6)) IrBLen = str2int(TmpStr1);
if (GetArgv(command, TmpStr1, 100, 3)) IrRaw = TmpStr1;
if (GetArgv(command, TmpStr1, 100, 4)) IrHz = str2int(TmpStr1);
if (GetArgv(command, TmpStr1, 100, 5)) IrPLen = str2int(TmpStr1);
if (GetArgv(command, TmpStr1, 100, 6)) IrBLen = str2int(TmpStr1);
printWebString += F("<a href='https://en.wikipedia.org/wiki/Base32#base32hex'>Base32Hex</a> RAW Code: ");
printWebString += IrRaw;
@@ -200,11 +200,11 @@ boolean Plugin_035(byte function, struct EventStruct *event, String& string)
unsigned int IrRepeat=0;
unsigned long IrSecondCode=0UL;
if (GetArgv(command, TmpStr1, 2)) IrType = TmpStr1;
if (GetArgv(command, TmpStr1, 3)) IrCode = strtoul(TmpStr1, NULL, 16); //(long) TmpStr1
if (GetArgv(command, TmpStr1, 4)) IrBits = str2int(TmpStr1);
if (GetArgv(command, TmpStr1, 5)) IrRepeat = str2int(TmpStr1);
if (GetArgv(command, TmpStr1, 6)) IrSecondCode = strtoul(TmpStr1, NULL, 16);
if (GetArgv(command, TmpStr1, 100, 2)) IrType = TmpStr1;
if (GetArgv(command, TmpStr1, 100, 3)) IrCode = strtoul(TmpStr1, NULL, 16); //(long) TmpStr1
if (GetArgv(command, TmpStr1, 100, 4)) IrBits = str2int(TmpStr1);
if (GetArgv(command, TmpStr1, 100, 5)) IrRepeat = str2int(TmpStr1);
if (GetArgv(command, TmpStr1, 100, 6)) IrSecondCode = strtoul(TmpStr1, NULL, 16);
if (IrType.equalsIgnoreCase(F("NEC"))) Plugin_035_irSender->sendNEC(IrCode, IrBits);
if (IrType.equalsIgnoreCase(F("JVC"))) Plugin_035_irSender->sendJVC(IrCode, IrBits, 2);
+2 -1
View File
@@ -168,7 +168,8 @@ boolean Plugin_036(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
//update now
timerSensor[event->TaskIndex] = millis() + (Settings.TaskDeviceTimer[event->TaskIndex] * 1000);
schedule_task_device_timer(event->TaskIndex,
millis() + (Settings.TaskDeviceTimer[event->TaskIndex] * 1000));
frameCounter=0;
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_036_adr"));
+4 -4
View File
@@ -200,7 +200,7 @@ boolean Plugin_037(byte function, struct EventStruct *event, String& string)
log = F("ERR : Illegal Payload ");
log += Payload;
log += " ";
log += ExtraTaskSettings.TaskDeviceName;
log += getTaskDeviceName(event->TaskIndex);
addLog(LOG_LEVEL_INFO, log);
success = false;
break;
@@ -227,7 +227,7 @@ boolean Plugin_037(byte function, struct EventStruct *event, String& string)
// Log the event
String log = F("IMPT : [");
log += ExtraTaskSettings.TaskDeviceName;
log += getTaskDeviceName(event->TaskIndex);
log += F("#");
log += ExtraTaskSettings.TaskDeviceValueNames[x];
log += F("] : ");
@@ -239,7 +239,7 @@ boolean Plugin_037(byte function, struct EventStruct *event, String& string)
if (Settings.UseRules)
{
String RuleEvent = F("");
RuleEvent += ExtraTaskSettings.TaskDeviceName;
RuleEvent += getTaskDeviceName(event->TaskIndex);
RuleEvent += F("#");
RuleEvent += ExtraTaskSettings.TaskDeviceValueNames[x];
RuleEvent += F("=");
@@ -287,7 +287,7 @@ boolean MQTTSubscribe_037()
{
String log = F("IMPT : [");
LoadTaskSettings(y);
log += ExtraTaskSettings.TaskDeviceName;
log += getTaskDeviceName(y);
log += F("#");
log += ExtraTaskSettings.TaskDeviceValueNames[x];
log += F("] subscribed to ");
+1
View File
@@ -359,6 +359,7 @@ boolean Plugin_042(byte function, struct EventStruct *event, String& string)
UserVar[event->BaseVarIndex + 2] = Candle_type;
success = true;
break;
}
case PLUGIN_WRITE:
+1 -1
View File
@@ -317,7 +317,7 @@ boolean Plugin_044(byte function, struct EventStruct *event, String& string)
if (Settings.UseRules)
{
LoadTaskSettings(event->TaskIndex);
String eventString = ExtraTaskSettings.TaskDeviceName;
String eventString = getTaskDeviceName(event->TaskIndex);
eventString += F("#Data");
rulesProcessing(eventString);
}
+30 -26
View File
@@ -98,21 +98,23 @@ boolean Plugin_048(byte function, struct EventStruct *event, String& string) {
}
case PLUGIN_WRITE: {
String tmpString = string;
String cmd = parseString(tmpString, 1);
String cmd = parseString(string, 1);
// Commands:
// MotorShieldCMD,<DCMotor>,<Motornumber>,<Forward/Backward/Release>,<Speed>
if (cmd.equalsIgnoreCase(F("MotorShieldCMD")))
{
String param1 = parseString(tmpString, 2);
String param2 = parseString(tmpString, 3);
String param3 = parseString(tmpString, 4);
String param4 = parseString(tmpString, 5);
String param5 = parseString(tmpString, 6);
String param1 = parseString(string, 2);
String param2 = parseString(string, 3);
String param3 = parseString(string, 4);
String param4 = parseString(string, 5);
String param5 = parseString(string, 6);
int p2_int;
int p4_int;
const bool param2_is_int = validIntFromString(param2, p2_int);
const bool param4_is_int = validIntFromString(param4, p4_int);
// Create the motor shield object with the default I2C address
AFMS = Adafruit_MotorShield(Plugin_048_MotorShield_address);
@@ -121,15 +123,15 @@ boolean Plugin_048(byte function, struct EventStruct *event, String& string) {
addLog(LOG_LEVEL_DEBUG, log);
if (param1.equalsIgnoreCase(F("DCMotor"))) {
if (param2.toInt() > 0 && param2.toInt() < 5)
if (param2_is_int && p2_int > 0 && p2_int < 5)
{
Adafruit_DCMotor *myMotor;
myMotor = AFMS.getMotor(param2.toInt());
myMotor = AFMS.getMotor(p2_int);
if (param3.equalsIgnoreCase(F("Forward")))
{
byte speed = 255;
if (param4.toInt() >= 0 && param4.toInt() <= 255)
speed = param4.toInt();
if (param4_is_int && p4_int >= 0 && p4_int <= 255)
speed = p4_int;
AFMS.begin();
addLog(LOG_LEVEL_INFO, String(F("DCMotor")) + param2 + String(F("->Forward Speed: ")) + String(speed));
myMotor->setSpeed(speed);
@@ -139,8 +141,8 @@ boolean Plugin_048(byte function, struct EventStruct *event, String& string) {
if (param3.equalsIgnoreCase(F("Backward")))
{
byte speed = 255;
if (param4.toInt() >= 0 && param4.toInt() <= 255)
speed = param4.toInt();
if (param4_is_int && p4_int >= 0 && p4_int <= 255)
speed = p4_int;
AFMS.begin();
addLog(LOG_LEVEL_INFO, String(F("DCMotor")) + param2 + String(F("->Backward Speed: ")) + String(speed));
myMotor->setSpeed(speed);
@@ -162,22 +164,24 @@ boolean Plugin_048(byte function, struct EventStruct *event, String& string) {
{
// Stepper# is which port it is connected to. If you're using M1 and M2, its port 1.
// If you're using M3 and M4 indicate port 2
if (param2.toInt() > 0 && param2.toInt() < 3)
if (param2_is_int && p2_int > 0 && p2_int < 3)
{
Adafruit_StepperMotor *myStepper;
myStepper = AFMS.getStepper(Plugin_048_MotorStepsPerRevolution, param2.toInt());
myStepper = AFMS.getStepper(Plugin_048_MotorStepsPerRevolution, p2_int);
myStepper->setSpeed(Plugin_048_StepperSpeed);
String log = F("MotorShield: StepsPerRevolution: ");
log += String(Plugin_048_MotorStepsPerRevolution);
log += F(" Stepperspeed: ");
log += String(Plugin_048_StepperSpeed);
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
String log = F("MotorShield: StepsPerRevolution: ");
log += String(Plugin_048_MotorStepsPerRevolution);
log += F(" Stepperspeed: ");
log += String(Plugin_048_StepperSpeed);
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
if (param3.equalsIgnoreCase(F("Forward")))
{
if (param4.toInt())
if (param4_is_int && p4_int != 0)
{
int steps = param4.toInt();
int steps = p4_int;
if (param5.equalsIgnoreCase(F("SINGLE")))
{
AFMS.begin();
@@ -215,9 +219,9 @@ boolean Plugin_048(byte function, struct EventStruct *event, String& string) {
if (param3.equalsIgnoreCase(F("Backward")))
{
if (param4.toInt())
if (param4_is_int && p4_int != 0)
{
int steps = param4.toInt();
int steps = p4_int;
if (param5.equalsIgnoreCase(F("SINGLE")))
{
AFMS.begin();
+1 -1
View File
@@ -247,7 +247,7 @@ boolean Plugin_049(byte function, struct EventStruct *event, String& string)
//delay first read, because hardware needs to initialize on cold boot
//otherwise we get a weird value or read error
timerSensor[event->TaskIndex] = millis() + 15000;
schedule_task_device_timer(event->TaskIndex, millis() + 15000);
Plugin_049_init = true;
success = true;
+2
View File
@@ -81,6 +81,7 @@ boolean Plugin_051(byte function, struct EventStruct *event, String& string)
addLog(LOG_LEVEL_ERROR, F("AM2320: Sensor offline"));
break;
case 0:
{
UserVar[event->BaseVarIndex] = th.t;
UserVar[event->BaseVarIndex + 1] = th.h;
@@ -92,6 +93,7 @@ boolean Plugin_051(byte function, struct EventStruct *event, String& string)
addLog(LOG_LEVEL_INFO, log);
success = true;
break;
}
}
+8 -8
View File
@@ -65,17 +65,17 @@ boolean Plugin_052(byte function, struct EventStruct *event, String& string)
case PLUGIN_WRITE:
{
String tmpString = string;
String cmd = parseString(tmpString, 1);
String param1 = parseString(tmpString, 2);
String cmd = parseString(string, 1);
String param1 = parseString(string, 2);
if (cmd.equalsIgnoreCase(F("senseair_setrelay")))
{
if (param1.toInt() == 0 || param1.toInt() == 1 || param1.toInt() == -1) {
Plugin_052_setRelayStatus(param1.toInt());
addLog(LOG_LEVEL_INFO, String(F("Senseair command: relay=")) + param1);
int par1;
if (validIntFromString(param1, par1)) {
if (par1 == 0 || par1 == 1 || par1 == -1) {
Plugin_052_setRelayStatus(par1);
addLog(LOG_LEVEL_INFO, String(F("Senseair command: relay=")) + param1);
}
}
success = true;
}
+36 -30
View File
@@ -100,7 +100,6 @@ boolean PacketAvailable(void)
}
boolean Plugin_053_process_data(struct EventStruct *event) {
String log;
uint16_t checksum = 0, checksum2 = 0;
uint16_t framelength = 0;
uint16 packet_header = 0;
@@ -113,9 +112,11 @@ boolean Plugin_053_process_data(struct EventStruct *event) {
SerialRead16(&framelength, &checksum);
if (framelength != (PMSx003_SIZE - 4))
{
log = F("PMSx003 : invalid framelength - ");
log += framelength;
addLog(LOG_LEVEL_ERROR, log);
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
String log = F("PMSx003 : invalid framelength - ");
log += framelength;
addLog(LOG_LEVEL_ERROR, log);
}
return false;
}
@@ -123,33 +124,37 @@ boolean Plugin_053_process_data(struct EventStruct *event) {
for (int i = 0; i < 13; i++)
SerialRead16(&data[i], &checksum);
log = F("PMSx003 : pm1.0=");
log += data[0];
log += F(", pm2.5=");
log += data[1];
log += F(", pm10=");
log += data[2];
log += F(", pm1.0a=");
log += data[3];
log += F(", pm2.5a=");
log += data[4];
log += F(", pm10a=");
log += data[5];
addLog(LOG_LEVEL_DEBUG, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = F("PMSx003 : pm1.0=");
log += data[0];
log += F(", pm2.5=");
log += data[1];
log += F(", pm10=");
log += data[2];
log += F(", pm1.0a=");
log += data[3];
log += F(", pm2.5a=");
log += data[4];
log += F(", pm10a=");
log += data[5];
addLog(LOG_LEVEL_DEBUG, log);
}
log = F("PMSx003 : count/0.1L : 0.3um=");
log += data[6];
log += F(", 0.5um=");
log += data[7];
log += F(", 1.0um=");
log += data[8];
log += F(", 2.5um=");
log += data[9];
log += F(", 5.0um=");
log += data[10];
log += F(", 10um=");
log += data[11];
addLog(LOG_LEVEL_DEBUG_MORE, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
String log = F("PMSx003 : count/0.1L : 0.3um=");
log += data[6];
log += F(", 0.5um=");
log += data[7];
log += F(", 1.0um=");
log += data[8];
log += F(", 2.5um=");
log += data[9];
log += F(", 5.0um=");
log += data[10];
log += F(", 10um=");
log += data[11];
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
// Compare checksums
SerialRead16(&checksum2, NULL);
@@ -296,6 +301,7 @@ boolean Plugin_053(byte function, struct EventStruct *event, String& string)
// When new data is available, return true
success = values_received;
values_received = false;
break;
}
}
return success;
+8 -6
View File
@@ -160,13 +160,15 @@ boolean Plugin_054(byte function, struct EventStruct *event, String& string)
if (param == F("log"))
{
String log = F("DMX : ");
for (int16_t i = 0; i < Plugin_054_DMXSize; i++)
{
log += Plugin_054_DMXBuffer[i];
log += F(", ");
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("DMX : ");
for (int16_t i = 0; i < Plugin_054_DMXSize; i++)
{
log += Plugin_054_DMXBuffer[i];
log += F(", ");
}
addLog(LOG_LEVEL_INFO, log);
}
addLog(LOG_LEVEL_INFO, log);
success = true;
}
+14 -10
View File
@@ -214,26 +214,30 @@ boolean Plugin_055(byte function, struct EventStruct *event, String& string)
if (command == F("chime"))
{
int paramPos = getParamStartPos(string, 2);
String param = string.substring(paramPos);
Plugin_055_AddStringFIFO(param);
String param = parseStringToEndKeepCase(string, 2);
if (param.length() > 0) {
Plugin_055_AddStringFIFO(param);
}
success = true;
}
if (command == F("chimeplay"))
{
String name = parseString(string, 2);
String param;
Plugin_055_ReadChime(name, param);
Plugin_055_AddStringFIFO(param);
if (name.length() > 0) {
String param;
Plugin_055_ReadChime(name, param);
Plugin_055_AddStringFIFO(param);
}
success = true;
}
if (command == F("chimesave"))
{
String name = parseString(string, 2);
int paramPos = getParamStartPos(string, 3);
String param = string.substring(paramPos);
Plugin_055_WriteChime(name, param);
Plugin_055_AddStringFIFO(F("1"));
String param = parseStringToEndKeepCase(string, 3);
if (name.length() > 0 && param.length() > 0) {
Plugin_055_WriteChime(name, param);
Plugin_055_AddStringFIFO(F("1"));
}
success = true;
}
+32 -26
View File
@@ -1,4 +1,4 @@
#ifdef USES_P057
#ifdef USES_P057
//#######################################################################################################
//#################################### Plugin 057: HT16K33 LED ##########################################
//#######################################################################################################
@@ -150,31 +150,33 @@ boolean Plugin_057(byte function, struct EventStruct *event, String& string)
if (!Plugin_057_M)
return false;
String lowerString=string;
lowerString.toLowerCase();
String command = parseString(lowerString, 1);
String command = parseString(string, 1);
if (command == F("mprint"))
{
int paramPos = getParamStartPos(lowerString, 2);
String text = lowerString.substring(paramPos);
byte seg = 0;
String text = parseStringToEnd(string, 2);
if (text.length() > 0) {
byte seg = 0;
Plugin_057_M->ClearRowBuffer();
while (text[seg] && seg < 8)
{
// uint16_t value = 0;
char c = text[seg];
Plugin_057_M->SetDigit(seg, c);
seg++;
Plugin_057_M->ClearRowBuffer();
while (text[seg] && seg < 8)
{
// uint16_t value = 0;
char c = text[seg];
Plugin_057_M->SetDigit(seg, c);
seg++;
}
Plugin_057_M->TransmitRowBuffer();
success = true;
}
Plugin_057_M->TransmitRowBuffer();
success = true;
}
else if (command == F("mbr")) {
int paramPos = getParamStartPos(lowerString, 2);
uint8_t brightness = lowerString.substring(paramPos).toInt();
Plugin_057_M->SetBrightness(brightness);
String param = parseString(string, 2);
int brightness;
if (validIntFromString(param, brightness)) {
if (brightness >= 0 && brightness <= 255)
Plugin_057_M->SetBrightness(brightness);
}
success = true;
}
else if (command == F("m") || command == F("mx") || command == F("mnum"))
@@ -186,6 +188,8 @@ boolean Plugin_057(byte function, struct EventStruct *event, String& string)
uint8_t seg = 0;
uint16_t value = 0;
String lowerString=string;
lowerString.toLowerCase();
lowerString.replace(F(" "), " ");
lowerString.replace(F(" ="), "=");
lowerString.replace(F("= "), "=");
@@ -199,13 +203,15 @@ boolean Plugin_057(byte function, struct EventStruct *event, String& string)
if (param == F("log"))
{
String log = F("MX : ");
for (byte i = 0; i < 8; i++)
{
log += String(Plugin_057_M->GetRow(i), 16);
log += F("h, ");
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("MX : ");
for (byte i = 0; i < 8; i++)
{
log += String(Plugin_057_M->GetRow(i), 16);
log += F("h, ");
}
addLog(LOG_LEVEL_INFO, log);
}
addLog(LOG_LEVEL_INFO, log);
success = true;
}
@@ -323,4 +329,4 @@ boolean Plugin_057(byte function, struct EventStruct *event, String& string)
return success;
}
#endif // USES_P057
#endif // USES_P057
+11 -11
View File
@@ -121,20 +121,20 @@ boolean Plugin_065(byte function, struct EventStruct *event, String& string)
if (!Plugin_065_SoftSerial)
break;
String lowerString=string;
lowerString.toLowerCase();
String command = parseString(lowerString, 1);
String param = parseString(lowerString, 2);
String command = parseString(string, 1);
String param = parseString(string, 2);
if (command == F("play"))
{
String log = F("MP3 : play=");
uint16_t track = param.toInt();
Plugin_065_Play(track);
log += track;
addLog(LOG_LEVEL_INFO, log);
int track;
if (validIntFromString(param, track)) {
Plugin_065_Play(track);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("MP3 : play=");
log += track;
addLog(LOG_LEVEL_INFO, log);
}
}
success = true;
}
+1 -4
View File
@@ -266,10 +266,7 @@ boolean Plugin_067(byte function, struct EventStruct *event, String& string)
case PLUGIN_WRITE:
{
String lowerString=string;
lowerString.toLowerCase();
String command = parseString(lowerString, 1);
String command = parseString(string, 1);
if (command == F("tare"))
{
String log = F("HX711: tare");
+7 -7
View File
@@ -153,22 +153,22 @@ boolean Plugin_070(byte function, struct EventStruct *event, String& string)
String param3 = parseString(lowerString, 4);
if (command == F("clock")) {
if (param1 != "") {
int val_Mode = param1.toInt();
int val_Mode;
if (validIntFromString(param1, val_Mode)) {
if (val_Mode > -1 && val_Mode < 2) {
Plugin_070_enabled = val_Mode;
CONFIG(0) = Plugin_070_enabled;
}
}
if (param2 != "") {
int val_Bright = param2.toInt();
int val_Bright;
if (validIntFromString(param2, val_Bright)) {
if (val_Bright > -1 && val_Bright < 256) {
Plugin_070_brightness = val_Bright;
CONFIG(1) = Plugin_070_brightness;
}
}
if (param3 != "") {
int val_Marks = param3.toInt();
int val_Marks;
if (validIntFromString(param3, val_Marks)) {
if (val_Marks > -1 && val_Marks < 256) {
Plugin_070_marks = val_Marks;
CONFIG(2) = Plugin_070_marks;
@@ -281,5 +281,5 @@ void timeToStrip(int hours, int minutes, int seconds) {
}
}
#endif // PLUGIN_BUILD_DISABLED
#endif // PLUGIN_BUILD_DISABLED
#endif // USES_P070
+2 -1
View File
@@ -252,11 +252,12 @@ boolean Plugin_074(byte function, struct EventStruct *event, String& string)
log += F(" IR: ");
log += String(ir);
addLog(LOG_LEVEL_INFO,log);
success = true;
}
else {
addLog(LOG_LEVEL_ERROR,F("TSL2591: Sensor not initialized!?"));
}
break;
}
}
+1 -1
View File
@@ -138,8 +138,8 @@ boolean Plugin_076(byte function, struct EventStruct *event, String& string)
UserVar[event->BaseVarIndex + 2] = hpower;
UserVar[event->BaseVarIndex + 3] = hpowfact;
//Plugin_076_hlw->toggleMode();
success = true;
}
success = true;
break;
case PLUGIN_INIT:
+247 -239
View File
@@ -27,7 +27,7 @@ boolean Plugin_077_init = false;
unsigned long energy_power_calibration = HLW_PREF_PULSE;
unsigned long energy_voltage_calibration = HLW_UREF_PULSE;
unsigned long energy_current_calibration = HLW_IREF_PULSE;
*/
*/
uint8_t cse_receive_flag = 0;
@@ -48,272 +48,280 @@ float energy_power = 0; // 123.1 W
boolean Plugin_077(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
boolean success = false;
switch (function) {
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_077;
Device[deviceCount].VType = SENSOR_TYPE_QUAD;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = true;
Device[deviceCount].ValueCount = 4;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = true;
Device[deviceCount].TimerOptional = true;
Device[deviceCount].GlobalSyncOption = true;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_077);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_077));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_077));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_077));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[3], PSTR(PLUGIN_VALUENAME4_077));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(F("U Ref"), F("plugin_077_URef"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
addUnit(F("uSec"));
addFormNumericBox(F("I Ref"), F("plugin_077_IRef"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
addUnit(F("uSec"));
addFormNumericBox(F("P Ref"), F("plugin_077_PRef"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
addUnit(F("uSec"));
addFormNote(F("Use 0 to read values stored on chip / default values"));
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_077_URef"));;
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_077_IRef"));
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_077_PRef"));
success = true;
break;
}
case PLUGIN_INIT:
{
Plugin_077_init = true;
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 0) Settings.TaskDevicePluginConfig[event->TaskIndex][0] = HLW_UREF_PULSE;
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 0) Settings.TaskDevicePluginConfig[event->TaskIndex][1] = HLW_IREF_PULSE;
if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] == 0) Settings.TaskDevicePluginConfig[event->TaskIndex][2] = HLW_PREF_PULSE;
Settings.UseSerial = true; // Enable Serial port
Settings.SerialLogLevel = 0; // disable logging on serial port (used for CSE7766 communication)
Settings.BaudRate = 4800; // set BaudRate for CSE7766
Serial.flush();
Serial.begin(Settings.BaudRate);
success = true;
break;
}
/* currently not needed!
case PLUGIN_TEN_PER_SECOND:
switch (function) {
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_077;
Device[deviceCount].VType = SENSOR_TYPE_QUAD;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = true;
Device[deviceCount].ValueCount = 4;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = true;
Device[deviceCount].TimerOptional = true;
Device[deviceCount].GlobalSyncOption = true;
break;
}
long cf_frequency = 0;
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_077);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_077));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_077));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_077));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[3], PSTR(PLUGIN_VALUENAME4_077));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(F("U Ref"), F("plugin_077_URef"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
addUnit(F("uSec"));
addFormNumericBox(F("I Ref"), F("plugin_077_IRef"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
addUnit(F("uSec"));
addFormNumericBox(F("P Ref"), F("plugin_077_PRef"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
addUnit(F("uSec"));
addFormNote(F("Use 0 to read values stored on chip / default values"));
if (CSE_PULSES_NOT_INITIALIZED == cf_pulses_last_time) {
cf_pulses_last_time = cf_pulses; // Init after restart
} else {
if (cf_pulses < cf_pulses_last_time) { // Rolled over after 65535 pulses
cf_frequency = (65536 - cf_pulses_last_time) + cf_pulses;
} else {
cf_frequency = cf_pulses - cf_pulses_last_time;
}
if (cf_frequency) {
cf_pulses_last_time = cf_pulses;
// energy_kWhtoday_delta += (cf_frequency * energy_power_calibration) / 36;
// EnergyUpdateToday();
}
}
success = true;
break;
}
*/
case PLUGIN_READ:
{
// We do not actually read as this is already done by reading the serial output
// Instead we just send the last known state stored in Uservar
addLog(LOG_LEVEL_DEBUG_DEV, F("CSE: plugin read"));
case PLUGIN_WEBFORM_SAVE:
{
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_077_URef"));;
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_077_IRef"));
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_077_PRef"));
success = true;
break;
}
case PLUGIN_INIT:
{
Plugin_077_init = true;
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 0) Settings.TaskDevicePluginConfig[event->TaskIndex][0] = HLW_UREF_PULSE;
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 0) Settings.TaskDevicePluginConfig[event->TaskIndex][1] = HLW_IREF_PULSE;
if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] == 0) Settings.TaskDevicePluginConfig[event->TaskIndex][2] = HLW_PREF_PULSE;
Settings.UseSerial = true; // Enable Serial port
disableSerialLog(); // disable logging on serial port (used for CSE7766 communication)
Settings.BaudRate = 4800; // set BaudRate for CSE7766
Serial.flush();
Serial.begin(Settings.BaudRate);
success = true;
break;
}
/* currently not needed!
case PLUGIN_TEN_PER_SECOND:
{
long cf_frequency = 0;
if (CSE_PULSES_NOT_INITIALIZED == cf_pulses_last_time) {
cf_pulses_last_time = cf_pulses; // Init after restart
} else {
if (cf_pulses < cf_pulses_last_time) { // Rolled over after 65535 pulses
cf_frequency = (65536 - cf_pulses_last_time) + cf_pulses;
} else {
cf_frequency = cf_pulses - cf_pulses_last_time;
}
if (cf_frequency) {
cf_pulses_last_time = cf_pulses;
// energy_kWhtoday_delta += (cf_frequency * energy_power_calibration) / 36;
// EnergyUpdateToday();
}
}
success = true;
break;
}
*/
case PLUGIN_READ:
{
addLog(LOG_LEVEL_DEBUG_DEV, F("CSE: plugin read"));
// sendData(event);
success = true;
break;
}
// Variables set in PLUGIN_SERIAL_IN as soon as there are new values!
// UserVar[event->BaseVarIndex] = energy_voltage;
// UserVar[event->BaseVarIndex + 1] = energy_power;
// UserVar[event->BaseVarIndex + 2] = energy_current;
// UserVar[event->BaseVarIndex + 3] = cf_pulses;
success = true;
break;
}
case PLUGIN_SERIAL_IN:
{
if (Plugin_077_init) {
if (Serial.available() > 0) {
serial_in_byte = Serial.read();
success = true;
}
case PLUGIN_SERIAL_IN:
{
if (Plugin_077_init) {
if (Serial.available() > 0) {
serial_in_byte = Serial.read();
success = true;
if (cse_receive_flag) {
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
if (24 == serial_in_byte_counter) {
addLog(LOG_LEVEL_DEBUG_DEV, F("CSE: packet received"));
CseReceived(event);
cse_receive_flag = 0;
break;
}
} else {
if (0x5A == serial_in_byte) { // 0x5A - Packet header 2
cse_receive_flag = 1;
addLog(LOG_LEVEL_DEBUG_DEV, F("CSE: Header received"));
} else {
serial_in_byte_counter = 0;
}
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
}
serial_in_byte = 0; // Discard
if (cse_receive_flag) {
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
if (24 == serial_in_byte_counter) {
addLog(LOG_LEVEL_DEBUG_DEV, F("CSE: packet received"));
CseReceived(event);
cse_receive_flag = 0;
serial_in_byte_counter = 0;
// new packet received, update values
UserVar[event->BaseVarIndex] = energy_voltage;
UserVar[event->BaseVarIndex + 1] = energy_power;
UserVar[event->BaseVarIndex + 2] = energy_current;
UserVar[event->BaseVarIndex + 3] = cf_pulses;
// break;
}
} else {
if (0x5A == serial_in_byte) { // 0x5A - Packet header 2
cse_receive_flag = 1;
addLog(LOG_LEVEL_DEBUG_DEV, F("CSE: Header received"));
} else {
serial_in_byte_counter = 0;
}
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
}
serial_in_byte = 0; // Discard
UserVar[event->BaseVarIndex] = energy_voltage;
UserVar[event->BaseVarIndex + 1] = energy_power;
UserVar[event->BaseVarIndex + 2] = energy_current;
UserVar[event->BaseVarIndex + 3] = cf_pulses;
// String log = F("Variable: Tag: ");
// log += key;
// addLog(LOG_LEVEL_INFO, log);
// success = true;
}
break;
}
}
return success;
// String log = F("Variable: Tag: ");
// log += key;
// addLog(LOG_LEVEL_INFO, log);
// success = true;
}
}
break;
}
}
return success;
}
void CseReceived(struct EventStruct *event)
{
String log;
uint8_t header = serial_in_buffer[0];
if ((header & 0xFC) == 0xFC) {
addLog(LOG_LEVEL_DEBUG, F("CSE: Abnormal hardware"));
return;
}
uint8_t header = serial_in_buffer[0];
if ((header & 0xFC) == 0xFC) {
addLog(LOG_LEVEL_DEBUG, F("CSE: Abnormal hardware"));
return;
}
// Calculate checksum
uint8_t checksum = 0;
for (byte i = 2; i < 23; i++) checksum += serial_in_buffer[i];
if (checksum != serial_in_buffer[23]) {
addLog(LOG_LEVEL_DEBUG, F("CSE: Checksum Failure"));
return;
}
// Calculate checksum
uint8_t checksum = 0;
for (byte i = 2; i < 23; i++) checksum += serial_in_buffer[i];
if (checksum != serial_in_buffer[23]) {
addLog(LOG_LEVEL_DEBUG, F("CSE: Checksum Failure"));
return;
}
// Get chip calibration data (coefficients) and use as initial defaults
if (HLW_UREF_PULSE == Settings.TaskDevicePluginConfig[event->TaskIndex][0]) {
long voltage_coefficient = 191200; // uSec
if (CSE_NOT_CALIBRATED != header) {
voltage_coefficient = serial_in_buffer[2] << 16 | serial_in_buffer[3] << 8 | serial_in_buffer[4];
}
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = voltage_coefficient / CSE_UREF;
}
if (HLW_IREF_PULSE == Settings.TaskDevicePluginConfig[event->TaskIndex][1]) {
long current_coefficient = 16140; // uSec
if (CSE_NOT_CALIBRATED != header) {
current_coefficient = serial_in_buffer[8] << 16 | serial_in_buffer[9] << 8 | serial_in_buffer[10];
}
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = current_coefficient;
}
if (HLW_PREF_PULSE == Settings.TaskDevicePluginConfig[event->TaskIndex][2]) {
long power_coefficient = 5364000; // uSec
if (CSE_NOT_CALIBRATED != header) {
power_coefficient = serial_in_buffer[14] << 16 | serial_in_buffer[15] << 8 | serial_in_buffer[16];
}
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = power_coefficient / CSE_PREF;
}
// Get chip calibration data (coefficients) and use as initial defaults
if (HLW_UREF_PULSE == Settings.TaskDevicePluginConfig[event->TaskIndex][0]) {
long voltage_coefficient = 191200; // uSec
if (CSE_NOT_CALIBRATED != header) {
voltage_coefficient = serial_in_buffer[2] << 16 | serial_in_buffer[3] << 8 | serial_in_buffer[4];
}
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = voltage_coefficient / CSE_UREF;
}
if (HLW_IREF_PULSE == Settings.TaskDevicePluginConfig[event->TaskIndex][1]) {
long current_coefficient = 16140; // uSec
if (CSE_NOT_CALIBRATED != header) {
current_coefficient = serial_in_buffer[8] << 16 | serial_in_buffer[9] << 8 | serial_in_buffer[10];
}
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = current_coefficient;
}
if (HLW_PREF_PULSE == Settings.TaskDevicePluginConfig[event->TaskIndex][2]) {
long power_coefficient = 5364000; // uSec
if (CSE_NOT_CALIBRATED != header) {
power_coefficient = serial_in_buffer[14] << 16 | serial_in_buffer[15] << 8 | serial_in_buffer[16];
}
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = power_coefficient / CSE_PREF;
}
uint8_t adjustement = serial_in_buffer[20];
voltage_cycle = serial_in_buffer[5] << 16 | serial_in_buffer[6] << 8 | serial_in_buffer[7];
current_cycle = serial_in_buffer[11] << 16 | serial_in_buffer[12] << 8 | serial_in_buffer[13];
power_cycle = serial_in_buffer[17] << 16 | serial_in_buffer[18] << 8 | serial_in_buffer[19];
cf_pulses = serial_in_buffer[21] << 8 | serial_in_buffer[22];
uint8_t adjustement = serial_in_buffer[20];
voltage_cycle = serial_in_buffer[5] << 16 | serial_in_buffer[6] << 8 | serial_in_buffer[7];
current_cycle = serial_in_buffer[11] << 16 | serial_in_buffer[12] << 8 | serial_in_buffer[13];
power_cycle = serial_in_buffer[17] << 16 | serial_in_buffer[18] << 8 | serial_in_buffer[19];
cf_pulses = serial_in_buffer[21] << 8 | serial_in_buffer[22];
log = F("CSE: adjustement ");
log += adjustement;
addLog(LOG_LEVEL_DEBUG_DEV, log);
log = F("CSE: voltage_cycle ");
log += voltage_cycle;
addLog(LOG_LEVEL_DEBUG_DEV, log);
log = F("CSE: current_cycle ");
log += current_cycle;
addLog(LOG_LEVEL_DEBUG_DEV, log);
log = F("CSE: power_cycle ");
log += power_cycle;
addLog(LOG_LEVEL_DEBUG_DEV, log);
log = F("CSE: cf_pulses ");
log += cf_pulses;
addLog(LOG_LEVEL_DEBUG_DEV, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG_DEV)) {
String log = F("CSE: adjustement ");
log += adjustement;
addLog(LOG_LEVEL_DEBUG_DEV, log);
log = F("CSE: voltage_cycle ");
log += voltage_cycle;
addLog(LOG_LEVEL_DEBUG_DEV, log);
log = F("CSE: current_cycle ");
log += current_cycle;
addLog(LOG_LEVEL_DEBUG_DEV, log);
log = F("CSE: power_cycle ");
log += power_cycle;
addLog(LOG_LEVEL_DEBUG_DEV, log);
log = F("CSE: cf_pulses ");
log += cf_pulses;
addLog(LOG_LEVEL_DEBUG_DEV, log);
}
// if (energy_power_on) { // Powered on
// if (energy_power_on) { // Powered on
if (adjustement & 0x40) { // Voltage valid
energy_voltage = (float)(Settings.TaskDevicePluginConfig[event->TaskIndex][0] * CSE_UREF) / (float)voltage_cycle;
}
if (adjustement & 0x10) { // Power valid
if ((header & 0xF2) == 0xF2) { // Power cycle exceeds range
energy_power = 0;
} else {
if (0 == power_cycle_first) power_cycle_first = power_cycle; // Skip first incomplete power_cycle
if (power_cycle_first != power_cycle) {
power_cycle_first = -1;
energy_power = (float)(Settings.TaskDevicePluginConfig[event->TaskIndex][2] * CSE_PREF) / (float)power_cycle;
} else {
energy_power = 0;
}
}
} else {
power_cycle_first = 0;
energy_power = 0; // Powered on but no load
}
if (adjustement & 0x20) { // Current valid
if (0 == energy_power) {
energy_current = 0;
} else {
energy_current = (float)Settings.TaskDevicePluginConfig[event->TaskIndex][1] / (float)current_cycle;
}
}
if (adjustement & 0x40) { // Voltage valid
energy_voltage = (float)(Settings.TaskDevicePluginConfig[event->TaskIndex][0] * CSE_UREF) / (float)voltage_cycle;
}
if (adjustement & 0x10) { // Power valid
if ((header & 0xF2) == 0xF2) { // Power cycle exceeds range
energy_power = 0;
} else {
if (0 == power_cycle_first) power_cycle_first = power_cycle; // Skip first incomplete power_cycle
if (power_cycle_first != power_cycle) {
power_cycle_first = -1;
energy_power = (float)(Settings.TaskDevicePluginConfig[event->TaskIndex][2] * CSE_PREF) / (float)power_cycle;
} else {
energy_power = 0;
}
}
} else {
power_cycle_first = 0;
energy_power = 0; // Powered on but no load
}
if (adjustement & 0x20) { // Current valid
if (0 == energy_power) {
energy_current = 0;
} else {
energy_current = (float)Settings.TaskDevicePluginConfig[event->TaskIndex][1] / (float)current_cycle;
}
}
// } else { // Powered off
// power_cycle_first = 0;
// energy_voltage = 0;
// energy_power = 0;
// energy_current = 0;
// }
// } else { // Powered off
// power_cycle_first = 0;
// energy_voltage = 0;
// energy_power = 0;
// energy_current = 0;
// }
log = F("CSE voltage: ");
log += energy_voltage;
addLog(LOG_LEVEL_DEBUG, log);
log = F("CSE power: ");
log += energy_power;
addLog(LOG_LEVEL_DEBUG, log);
log = F("CSE current: ");
log += energy_current;
addLog(LOG_LEVEL_DEBUG, log);
log = F("CSE piulses: ");
log += cf_pulses;
addLog(LOG_LEVEL_DEBUG, log);
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = F("CSE voltage: ");
log += energy_voltage;
addLog(LOG_LEVEL_DEBUG, log);
log = F("CSE power: ");
log += energy_power;
addLog(LOG_LEVEL_DEBUG, log);
log = F("CSE current: ");
log += energy_current;
addLog(LOG_LEVEL_DEBUG, log);
log = F("CSE piulses: ");
log += cf_pulses;
addLog(LOG_LEVEL_DEBUG, log);
}
}
#endif // USES_P077
+21 -5
View File
@@ -1137,9 +1137,9 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
TempEvent.sensorType = Device[DeviceIndex].VType;
checkRAM(F("PluginCall_s"),x);
START_TIMER;
bool retval = (Plugin_ptr[x](Function, event, str));
bool retval = (Plugin_ptr[x](Function, &TempEvent, str));
STOP_TIMER_TASK(x,Function);
if (retval) return true;
if (retval) return true;
}
}
}
@@ -1168,7 +1168,7 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
//TempEvent.idx = Settings.TaskDeviceID[y]; todo check
TempEvent.sensorType = Device[DeviceIndex].VType;
START_TIMER;
bool retval = (Plugin_ptr[x](Function, event, str));
bool retval = (Plugin_ptr[x](Function, &TempEvent, str));
STOP_TIMER_TASK(x,Function);
if (retval){
checkRAM(F("PluginCallUDP"),x);
@@ -1206,6 +1206,10 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
TempEvent.sensorType = Device[DeviceIndex].VType;
TempEvent.OriginTaskIndex = event->TaskIndex;
checkRAM(F("PluginCall_s"),x);
if (Function == PLUGIN_INIT) {
// Schedule the plugin to be read.
schedule_task_device_timer_at_init(TempEvent.TaskIndex);
}
START_TIMER;
Plugin_ptr[x](Function, &TempEvent, str);
STOP_TIMER_TASK(x,Function);
@@ -1228,17 +1232,29 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
case PLUGIN_GET_DEVICEGPIONAMES:
case PLUGIN_READ:
case PLUGIN_SET_CONFIG:
case PLUGIN_GET_CONFIG:
case PLUGIN_GET_CONFIG:
{
const int x = getPluginId(event->TaskIndex);
if (x >= 0) {
if (Plugin_id[x] != 0 ) {
if (Function == PLUGIN_INIT) {
// Schedule the plugin to be read.
schedule_task_device_timer_at_init(event->TaskIndex);
}
if (Function != PLUGIN_GET_DEVICEVALUENAMES) {
// LoadTaskSettings may call PLUGIN_GET_DEVICEVALUENAMES.
LoadTaskSettings(event->TaskIndex);
}
event->BaseVarIndex = event->TaskIndex * VARS_PER_TASK;
checkRAM(F("PluginCall_init"),x);
START_TIMER;
bool retval = Plugin_ptr[x](Function, event, str);
if (Function == PLUGIN_GET_DEVICEVALUENAMES) {
ExtraTaskSettings.TaskIndex = event->TaskIndex;
}
STOP_TIMER_TASK(x,Function);
return retval;
return retval;
}
}
return false;