Compare commits

...
Author SHA1 Message Date
ESPEasy release bot fdf8a40acf automatically updated release notes for mega-20180514 2018-05-14 04:00:09 +02:00
Gijs NoorlanderandGitHub 547f3643ff Merge pull request #1421 from TD-er/bugfix_issue#1411
Memory optimizations
2018-05-13 23:46:12 +02:00
TD-er 83d0980248 [ESP32] ESP.getResetReason() is unknown to ESP32 2018-05-13 23:25:08 +02:00
TD-er 0b1f9a81b5 [memory corruption] LWIP data corrupts log buffer
Not sure how, but the headers of new JSON message can corrupt the buffer in the web log buffer.
In this attempt the log buffer lines are now moved to heap instead of stack. 
Also the streaming webserver is given a bit more time to handle requests.

Steps to reproduce:
Set web log level to maximum and open web log viewer.
Then wait a few seconds to minutes to let the JSON stream stop and look at the last sent Json message. This will contain some typical Json web headers and thus no valid Json anymore.

Also added a quick fix for #1419
2018-05-13 23:12:02 +02:00
TD-er 0e8b333f48 [issue #1380] Prevent memory leaks in WiFiClient
See described work-around in https://github.com/esp8266/Arduino/issues/4497#issuecomment-373023864
2018-05-13 23:04:45 +02:00
TD-er 67098c2539 [memory] use "-DNDEBUG" to disable ASSERT macros
See https://github.com/esp8266/Arduino/issues/3978
2018-05-13 22:58:10 +02:00
Gijs NoorlanderandGitHub 700b14b8ff Merge pull request #1420 from ZericE/mega
[#1404] Change email notify protocol to better comply with RFC2821. Rewrite line breaks for content-type: text/html
2018-05-13 19:05:03 +02:00
ZericE 9175cd3a17 use reference to free up mem. 2018-05-13 09:23:23 -07:00
ZericE c16f27af1b remove unneeded use of bMesg to free up mem. 2018-05-13 08:45:43 -07:00
Gijs NoorlanderandGitHub cc60b8a05d Merge pull request #1382 from flexiti/mega
ESP32 OTA amendments
2018-05-13 11:42:33 +02:00
Gijs NoorlanderandGitHub d7b46b3395 Merge pull request #1416 from giig1967g/new/formats
Added more #formats transformations
2018-05-13 11:41:12 +02:00
ESPEasy release bot 701677274f automatically updated release notes for mega-20180513 2018-05-13 04:00:08 +02:00
ZericE ebfffb8d43 updated comment 2018-05-12 18:08:47 -07:00
ZericE f5fd624739 remove debug lines in email notify 2018-05-12 18:06:00 -07:00
ZericE abdf011a2d undo unnecessary changes in email body
Previously I thought the body wasn't working correctly in email, however it was, with the exception of line breaks for text/html that have to be rewritten.
2018-05-12 18:03:59 -07:00
ZericE 4ece42bdc9 Merge branch 'mega' of https://github.com/ZericE/ESPEasy into mega 2018-05-12 16:48:17 -07:00
ZericE b0961c15a3 [#1404] Fix email notification for RFC2821, fix so msg body included.
In communicating with the server, the sender and receiver needed to be surrounded by <> to be RFC2821 compliant.
The message body was coming out blank as an empty string was being sent instead of the correct string.
2018-05-12 16:43:30 -07:00
Plebs 70a422bdfd Added more #formats transformations
New Transformations:
#H: Hot/Cold
#A: Man/Auto
#a: M/A

New Justifications:
#Lx: Left (x=number of chars)
#Rx: Right (x=number of chars)
#Ux.y: Substring (x=first char; y=number of chars)
2018-05-12 23:57:58 +02:00
Gijs NoorlanderandGitHub 5449d82639 [PR #1304] Rename file before running crc2.py
Quick patch of PR #1304
2018-05-12 22:57:17 +02:00
ZericEandGitHub 7e5577b30b Merge pull request #1 from letscontrolit/mega
update latest changes from main repository
2018-05-12 13:14:39 -07:00
Gijs NoorlanderandGitHub 0d95fd12fe Fix debug code (commented) in _P045_MPU6050.ino
Original PR was https://github.com/letscontrolit/ESPEasy/pull/1389
Found by @maartenpaauw
2018-05-12 22:10:33 +02:00
flexitiandGitHub b7df21a1d5 Merge pull request #4 from letscontrolit/mega
Sat May 12 04:00:06 CEST 2018
2018-05-12 11:00:14 +02:00
ESPEasy release bot 431b94c587 automatically updated release notes for mega-20180512 2018-05-12 04:00:06 +02:00
GrovkillenandGitHub 10e912f46f Merge pull request #1413 from Grovkillen/optimized-log-a-tiny-bit-(feels-good)
Optimized log a tiny bit (feels good)
2018-05-12 00:25:26 +02:00
GrovkillenandGitHub c90174712b [web log] safety net not needed anymore 2018-05-12 00:14:54 +02:00
GrovkillenandGitHub 1d71d362b9 Merge pull request #19 from letscontrolit/mega
update from master
2018-05-12 00:06:39 +02:00
Gijs NoorlanderandGitHub 73fbe04981 Merge pull request #1410 from TD-er/bugfix/nightlybuilds
[build] Do builds twice on the nightly builds
2018-05-11 22:11:08 +02:00
flexitiandGitHub 469735b5fd Merge pull request #3 from letscontrolit/mega
Commits on May 10, 2018
2018-05-11 17:42:10 +02:00
TD-er cf13024175 [#1411] Add SensorTypeNone to indicate no sensor values for Domoticz
Some plugins which do not output any values had this setting set to "Switch" or "single".
2018-05-11 17:20:32 +02:00
Gijs NoorlanderandGitHub eaf6488b0c Merge pull request #1409 from Grovkillen/device-page]-added-max-request
[Device page] added max request
2018-05-11 14:44:32 +02:00
GrovkillenandGitHub 4d067f010f [device page] added dynamic length to loop 2018-05-11 14:41:01 +02:00
GrovkillenandGitHub e6db005dba [web log] also taking care of disconnects 2018-05-11 14:19:16 +02:00
GrovkillenandGitHub 7a03802c15 [device page] added max request here too 2018-05-11 14:00:17 +02:00
GrovkillenandGitHub 1e2e750b3b Merge pull request #18 from letscontrolit/mega
update from master
2018-05-11 13:59:23 +02:00
Gijs NoorlanderandGitHub 50a19692b5 Merge pull request #1408 from Grovkillen/fix-request-issue
[web log] Fix request issue
2018-05-11 13:46:52 +02:00
TD-er b6284f2701 [build] Do builds twice on the nightly builds
And added build for ESP32 and Sonoff POW
2018-05-11 13:42:41 +02:00
GrovkillenandGitHub b3db6621e2 [web log] fixed wait on requests 2018-05-11 13:33:28 +02:00
GrovkillenandGitHub 2d32fe3e32 Merge pull request #17 from letscontrolit/mega
update from master
2018-05-11 11:33:28 +02:00
GrovkillenandGitHub 241f21b87c Merge pull request #1407 from Grovkillen/fix-for-sub-second-timers
[web log] Fix for sub second timers
2018-05-11 10:58:45 +02:00
GrovkillenandGitHub 4f18f81522 [web log] fixed overflow when set to "debug dev" 2018-05-11 10:50:47 +02:00
GrovkillenandGitHub b860f79e77 Merge pull request #16 from letscontrolit/mega
update from master
2018-05-11 10:44:17 +02:00
Gijs NoorlanderandGitHub 8966e1680b Merge pull request #1403 from Grovkillen/fix-timer-in-javascript
Fix timer in javascript
2018-05-11 10:03:34 +02:00
GrovkillenandGitHub 01436201a3 Added ";" 2018-05-11 09:59:31 +02:00
GrovkillenandGitHub 1ac94bf6db Merge pull request #15 from letscontrolit/mega
Update from master
2018-05-11 09:44:20 +02:00
GrovkillenandGitHub ed66a98e08 Fix for decimals on auto update device page 2018-05-11 09:43:07 +02:00
Gijs NoorlanderandGitHub 5a0c2e2353 Merge pull request #1405 from TD-er/bugfix/json_nr_decimals
[JSON] Add number of decimals to the JSON output
2018-05-11 09:42:01 +02:00
TD-er 06bc63e385 [JSON] Add number of decimals to the JSON output 2018-05-11 09:40:32 +02:00
GrovkillenandGitHub d3ebe3ec46 Fixed scrolling issue when fetch <450mSec 2018-05-11 09:32:23 +02:00
GrovkillenandGitHub 2282288030 Added check to stop flooding 2018-05-11 09:17:17 +02:00
GrovkillenandGitHub e5766bee46 Fixed some small syntax missing 2018-05-11 08:31:04 +02:00
flexitiandGitHub c5bbfd1b4c Merge pull request #2 from letscontrolit/mega
Fri May 11 04:00:08 CEST 2018
2018-05-11 08:18:27 +02:00
ESPEasy release bot 652ce2f809 automatically updated release notes for mega-20180511 2018-05-11 04:00:08 +02:00
GrovkillenandGitHub f3fd3900e5 Removed a timer reset... 2018-05-11 00:44:49 +02:00
GrovkillenandGitHub 07b726d4b1 Preparation for fixed decimals... 2018-05-11 00:30:58 +02:00
GrovkillenandGitHub 648d960bf5 Fixed format (I like tabs, Platformio like spaces) 2018-05-10 23:25:45 +02:00
GrovkillenandGitHub 1829a35df2 Fixed the timers for log + devices 2018-05-10 23:23:06 +02:00
GrovkillenandGitHub c5bb6700d9 Merge pull request #14 from letscontrolit/mega
update from master
2018-05-10 22:45:00 +02:00
Gijs NoorlanderandGitHub 3b2dd86280 Merge pull request #1402 from TD-er/feature/ImproveWebserver
[Web] Improve serving large blobs directly from flash
2018-05-10 22:27:38 +02:00
TD-er 11563469d0 [Web] Improve serving large blobs directly from flash
Serve PROGMEM data directly from flash.
This makes it easier to add Javascript code to the source and it will be served directly from flash
2018-05-10 22:13:56 +02:00
Gijs NoorlanderandGitHub fcea12b515 Merge pull request #1400 from TD-er/bugfix/JSONoutput
Format user values + Legend for log JSON
2018-05-10 18:48:33 +02:00
TD-er 2b72ad2088 [log JSON] Add log level legend to the logjson output
To be shown on the  web log viewer as legend
2018-05-10 18:10:40 +02:00
TD-er 30acf569e7 [cleanup] Simplify formatting user variables and allow checking
Extended the way a user variable is formatted to allow checking the value.
Also made clear when values are actually checked.
2018-05-10 18:05:14 +02:00
GrovkillenandGitHub cb71f73b56 Merge pull request #13 from letscontrolit/mega
update from master
2018-05-10 13:11:14 +02:00
flexitiandGitHub 521ca465e5 Merge pull request #1 from letscontrolit/mega
Thu May 10 04:00:13 CEST 2018
2018-05-10 10:51:44 +02:00
ESPEasy release bot ca10c834cc automatically updated release notes for mega-20180510 2018-05-10 04:00:13 +02:00
Gijs NoorlanderandGitHub ef90c84506 Merge pull request #1393 from Grovkillen/color-scheme-for-web-log
Color scheme for web log
2018-05-09 23:34:47 +02:00
Gijs NoorlanderandGitHub 3c2f539ec3 Merge pull request #1390 from workgroupengineering/HotFix/Device_Plugin_ID
Fix plugin_id visualization
2018-05-09 23:34:22 +02:00
Gijs NoorlanderandGitHub 30419c9932 Merge pull request #1378 from TD-er/feature/Ventus_W266_build_selection
[build] Special build config for Ventus W266
2018-05-09 23:33:44 +02:00
Gijs NoorlanderandGitHub a340b4dedc Merge pull request #1385 from Grovkillen/auto-update-values
Auto update values on device page
2018-05-09 23:32:58 +02:00
Gijs NoorlanderandGitHub 69e4d1ec7a Merge pull request #1384 from ZericE/mega
[#1368] Remove call to Plugin_041_update in _P041_NeoClock that caused a hard crash.
2018-05-09 23:29:55 +02:00
GrovkillenandGitHub 91570e9df5 Fixed copy to clipboard (handle HTML tags) 2018-05-09 20:48:03 +02:00
GrovkillenandGitHub 53e9a8f4a3 Fixed the log level colors 2018-05-09 19:51:21 +02:00
GrovkillenandGitHub 71c9b772fe Removed auto update of values... wrong branch 2018-05-09 19:34:40 +02:00
Saverio Cisternino 3ff96a5bec Fix plugin_id visualization on devices view that afflict Development build 2018-05-09 18:54:00 +02:00
GrovkillenandGitHub 32f8edb1ce Added div to web log (color scheme)
Need to add clean up to copy button.
2018-05-09 16:04:40 +02:00
GrovkillenandGitHub 977611b39c Wrap up for the PR 2018-05-08 00:09:22 +02:00
GrovkillenandGitHub 52979cafba Values are updated (1-4 values per task) 2018-05-07 23:47:36 +02:00
ZericE b0a1b95f64 Merge remote-tracking branch 'upstream/mega' into mega 2018-05-07 12:58:07 -07:00
ZericE 04f323b902 [#1368] Remove call to Plugin_041_update causing a hard crash.
Plugin_041_update was being called before the plugin has been initialized, this resulted in an exception 28 type crash. Plugin_041_update clears the display and isn't required at the time of webform save.
2018-05-07 12:34:38 -07:00
GrovkillenandGitHub c20656fe77 First draft of auto update of task/device values 2018-05-07 20:41:55 +02:00
GrovkillenandGitHub 6d3b2d1b18 Merge pull request #12 from letscontrolit/mega
update from master
2018-05-07 12:52:02 +02:00
flexitiandGitHub 388b8f4feb ESP32 OTA port setting 2018-05-07 11:57:32 +02:00
flexitiandGitHub 7b6b72b912 ESP32 OTA port is set to 3232 2018-05-07 11:53:06 +02:00
flexitiandGitHub 5e9ad087b9 OTA check box
if Arduino OTA is not compiled, a button to choose  it is not available
2018-05-07 11:50:03 +02:00
flexitiandGitHub ca5a1bdba1 Improvement in the file platformio.ini 2018-05-07 11:46:50 +02:00
ESPEasy release bot 98522d7cfc automatically updated release notes for mega-20180507 2018-05-07 04:00:08 +02:00
GrovkillenandGitHub 30ab8aef9e [issue template] extra reminder to self compilers 2018-05-06 23:35:59 +02:00
TD-er 22593d7116 [Ventus W266] Fix signed/unsigned warning 2018-05-06 22:52:04 +02:00
TD-er a8f3ad1be2 [build] Special build config for Ventus W266 2018-05-06 22:29:25 +02:00
ESPEasy release bot d54a01a3e6 automatically updated release notes for mega-20180506 2018-05-06 04:00:08 +02:00
Gijs NoorlanderandGitHub 226b3f3d54 Merge pull request #1344 from giig1967g/bugfix/960
fix for #960: new command: TaskValueSetAndRun
2018-05-05 23:47:52 +02:00
Gijs NoorlanderandGitHub 1e4a0858c1 Merge branch 'mega' into bugfix/960 2018-05-05 23:34:02 +02:00
Gijs NoorlanderandGitHub 379c4fccd1 Merge pull request #1347 from Grovkillen/Infinitive-web-log
This one is not yet complete, way more features and improvements are coming. 
But for now it is already much much better than the old log viewer :)
So I'll merge it now and we'll see what it will become.
2018-05-05 23:30:41 +02:00
Gijs NoorlanderandGitHub 886d46fd4c Merge pull request #1370 from ZericE/mega
[#1356] Remove redundant call to MQTTCheck
2018-05-05 22:47:35 +02:00
Gijs NoorlanderandGitHub 5184cba646 Merge pull request #1374 from giig1967g/new/logentry
new command: logentry #1183
2018-05-05 22:46:57 +02:00
Gijs NoorlanderandGitHub b8c4215a27 Merge pull request #1373 from TD-er/feature/optimize_json_pages
Feature/optimize json pages
2018-05-05 22:46:24 +02:00
TD-er d1b017b287 [JSON] Fix for single task view of json output. 2018-05-05 22:26:56 +02:00
TD-er a5421e816c [JSON] Add TTL, task interval and task enabled
TTL = The shortest interval per enabled task (with output values) in msec.
2018-05-05 22:14:42 +02:00
GrovkillenandGitHub d6ca15671d Forgot the auto-scroll function... now added 2018-05-05 21:14:51 +02:00
GrovkillenandGitHub 24231cdc56 Updated to compile with TD-er's update on JSON 2018-05-05 21:05:31 +02:00
TD-er 30e192f041 [JSON] Sanitize JSON value strings
May not contain newline nor "
2018-05-05 17:15:46 +02:00
Plebs 38472a3d6b new command logentry
Command:
usage: logentry,anything (including system variables, task#values with formatting, text, etc.)

Example:
logentry,S=[task#value] T=[task1#value]:

Log output:
ACT  : logentry,S=24 T=23.1
Command: logentry
2018-05-05 16:58:58 +02:00
TD-er d54af04a79 [JSON] Make proper log JSON output for log viewer 2018-05-05 16:52:55 +02:00
TD-er 056e7a7a40 [JSON] Use streaming webserver for serving JSON page
Reduces memory and load times.
2018-05-05 13:31:02 +02:00
ESPEasy release bot f69e476174 automatically updated release notes for mega-20180505 2018-05-05 04:00:07 +02:00
Gijs NoorlanderandGitHub b368252db8 Merge pull request #1371 from TD-er/bugfix/wifi_scan_hidden
[#1337]  Include hidden SSID in wifi scans
2018-05-05 00:55:55 +02:00
TD-er ea3389f792 [#1337] WiFi.isHidden() is unknown to ESP32 2018-05-05 00:55:19 +02:00
TD-er 33b8570c33 [#1337] Include hidden SSID in wifi scans
When found, they appear with "#Hidden#" in the list.
2018-05-04 23:38:48 +02:00
ZericE 76ff83e3f4 [#1356] Remove redundant call to MQTTCheck
A redundant call to MQTTcheck in runEach30Seconds was adding to the blocking issue when attempting to connect to unavailable broker.
2018-05-04 10:00:20 -07:00
mvdbro 92680c5542 Fix corruption of task settings 2018-05-04 15:43:24 +02:00
ESPEasy release bot e568bbed7c automatically updated release notes for mega-20180504 2018-05-04 04:00:10 +02:00
Gijs NoorlanderandGitHub 82bfadd77a Merge pull request #1367 from TD-er/bugfix/20180503
Bugfix/20180503
2018-05-04 00:49:02 +02:00
TD-er b636959cc7 [LWIP2] Change LWIP1.4 => LWIP2 Low Memory
Please make sure to restart PlatformIO after loading this changed ini file and do a clean build (twice???)
2018-05-04 00:42:07 +02:00
TD-er 2a1f6eebe7 [Settings] Add checks to investigate issues with overlap in settings
See #1361
2018-05-04 00:40:44 +02:00
Gijs NoorlanderandGitHub b7b8ceebcf Merge pull request #1366 from Grovkillen/fix-dropdown-a-bit
Fix dropdown a bit
2018-05-04 00:30:12 +02:00
GrovkillenandGitHub 9f6f39053e Added a break under the hamburger
to have a bit of a buffer zone. Or else you'll accidently click the "main" button....
2018-05-04 00:01:33 +02:00
GrovkillenandGitHub 8eed47393f Merge pull request #11 from letscontrolit/mega
update from master
2018-05-03 23:54:15 +02:00
TD-er cc0c2c0f8b [rules timer] revert treating the rules timer as periodical timer
May have unexpected effects, so if a more accurate timer is needed, a new timer type should be used, not setting an interval in the rules.
2018-05-03 23:13:21 +02:00
Gijs NoorlanderandGitHub 0450d8a106 Merge pull request #1352 from Grovkillen/Menu-for-phone
Dropdown menu for phone
2018-05-03 21:36:30 +02:00
Gijs NoorlanderandGitHub e96de4a988 Merge branch 'mega' into Menu-for-phone 2018-05-03 21:36:14 +02:00
Gijs NoorlanderandGitHub 28bdc37d24 Merge pull request #1364 from Grovkillen/fix-checkboxe
Fix checkboxes (#1363)
2018-05-03 21:19:05 +02:00
GrovkillenandGitHub b7ccba979c [#1363] fixed overlapping checkboxes 2018-05-03 20:35:34 +02:00
GrovkillenandGitHub 5132a318af Merge pull request #10 from letscontrolit/mega
Update from master
2018-05-03 09:45:16 +02:00
ESPEasy release bot cfd27b4918 automatically updated release notes for mega-20180503 2018-05-03 04:00:12 +02:00
Gijs NoorlanderandGitHub feba82188a Merge pull request #1359 from TD-er/bugfix/timers
Bugfix/timers
2018-05-03 00:34:25 +02:00
TD-er 1a3274d2c2 [#1353] Remove Domoticz HTTP as default controller 2018-05-03 00:32:18 +02:00
TD-er 0f04456ae6 [timers] Make rules timers more constant and MQTT reconnect less aggressive
See #1356
And #1223
2018-05-02 23:49:50 +02:00
Gijs NoorlanderandGitHub 6016e1b1d3 Merge pull request #1358 from TD-er/bugfix/issue1351_rules
[rules] Make rules start working again.
2018-05-02 23:30:07 +02:00
TD-er 39e391ca0e [rules] Make rules start working again.
See #1351
Whenever a plugin_write returns success = true, the execute command will no longer be called.
It doesn't matter whether the plugin is enabled or present.
It should only return success = true when the command was actually meant for this plugin.
2018-05-02 23:23:19 +02:00
GrovkillenandGitHub 8088ed4ed8 Added some "-" 2018-05-02 23:08:55 +02:00
GrovkillenandGitHub 13bd7ba26b Forgot extra \ for escape in code 2018-05-02 23:06:12 +02:00
GrovkillenandGitHub 3cb90939c4 BR should be \n, now fixed 2018-05-02 23:01:12 +02:00
GrovkillenandGitHub 76cddb7c71 Added break... 2018-05-02 22:56:24 +02:00
GrovkillenandGitHub 3d0f871600 If error make log show this more clear 2018-05-02 22:54:34 +02:00
GrovkillenandGitHub ffb3ee4039 Spelling correction 2018-05-02 22:33:43 +02:00
GrovkillenandGitHub 456796a87d Added dropdown for phones 2018-05-02 15:09:37 +02:00
GrovkillenandGitHub bf512f9da0 Merge pull request #9 from letscontrolit/mega
Update from master
2018-05-02 13:11:04 +02:00
GrovkillenandGitHub d5b8a36acb Web log now inside a textarea 2018-05-02 09:43:40 +02:00
GrovkillenandGitHub f09642101f Merge pull request #8 from letscontrolit/mega
Update from master
2018-05-02 08:23:46 +02:00
ESPEasy release bot cb16773128 automaticly updated release notes for mega-20180502 2018-05-02 04:00:16 +02:00
Gijs NoorlanderandGitHub 2e55b6304c Merge pull request #1348 from TD-er/bugfix/improvetimers
Bugfix/improvetimers
2018-05-02 01:33:40 +02:00
TD-er f61586ebbc [web log] Read all items from the log buffer
This is a very sub optimal implementation. Eventually it should use the streaming web TXBuffer we made. It now uses quite some memory, when called.
2018-05-02 01:19:44 +02:00
TD-er 7f385fc74a [wifi] Make retry intervals to connect increase at each attempt.
There is still an issue when the node is trying to reconnect very hard, it will not react to commands given via the serial port.
2018-05-02 01:18:05 +02:00
TD-er a579c906d5 [timers] Make timers more accurate
Previously the moment a timed function was called, the new timer was set. That would make the timer interval to be the minimum interval, with quite some margin of error.
Now the timers are at a more strict interval, unless the device cannot keep up.
2018-05-02 01:16:39 +02:00
GrovkillenandGitHub a80f3a5f0b Added div to not copy "Fetching log entries...."
Clipboard should not have the fetch info text
2018-05-01 23:27:03 +02:00
GrovkillenandGitHub 7e10fda7e5 Added javascript to handle the log entries 2018-05-01 22:57:03 +02:00
GrovkillenandGitHub 16a6135f53 Merge pull request #7 from letscontrolit/mega
update from master
2018-05-01 22:55:13 +02:00
Gijs NoorlanderandGitHub 343ea459ab Merge pull request #1343 from giig1967g/bugfix/1142
fix for #1142
2018-05-01 22:46:55 +02:00
Gijs NoorlanderandGitHub 0ddcee1f07 Merge pull request #1323 from workgroupengineering/Optimize_setSystemTimer
Optimize setSystemTimer
2018-05-01 22:39:25 +02:00
Gijs NoorlanderandGitHub 07ac4cf8cf Merge pull request #1345 from giig1967g/new/strings
Added 2 system variables
2018-05-01 22:29:23 +02:00
Gijs NoorlanderandGitHub a864aeab1e Merge pull request #1339 from Grovkillen/new-weblog
New web log
2018-05-01 22:25:39 +02:00
Gijs NoorlanderandGitHub 35a7ab94df Merge pull request #1346 from TD-er/bugfix/change_to_LWIP_140
[LWIP 1.4.0] Change to LWIP 1.4.0, to allow large http POST messages
2018-05-01 22:18:07 +02:00
TD-er 44755e83b9 [LWIP] fix ESP32 build 2018-05-01 22:04:29 +02:00
Gijs NoorlanderandGitHub f93b38624d Merge pull request #1342 from giig1967g/bugfix/1170
fix for #1170
2018-05-01 21:10:11 +02:00
TD-er c1cb7d873c [LWIP 1.4.0] Change to LWIP 1.4.0, to allow large http POST messages
See #1296
Rules got truncated when trying to save rules > 1520 Bytes.

Also added a bit more log information and some details about the used libraries in the sysinfo page and json output.
2018-05-01 21:05:50 +02:00
Plebs 62d81325b2 Added 2 system variables
Added 2 system variables

%SP% = space
%ip4% = 4th IP octet
2018-05-01 20:58:13 +02:00
Plebs 5bc2af0e4c deleted comments
deleted comments and moved success outside of the if clause.
2018-05-01 20:52:00 +02:00
Plebs bc5bf7f3f1 fix for #960
Added a new global command: TaskValueSetAndRun.

It changes the value of a task and runs it, so new value is pubished on MQTT and rules are executed.
2018-05-01 19:56:49 +02:00
Plebs 0b4013b33c fix for #1142 2018-05-01 19:51:26 +02:00
Plebs 3c3a11d77b fix for #1170
The reason is that inside PLUGIN_WRITE the variable [event->BaseVarIndex] is not set and is always = 0.
So actually this PR modifies the 1st value of task 1 and not the encoder counter.
Line 183 of P059_Encoder.ino should be removed:
UserVar[event->BaseVarIndex] = (float) event->Par1;
2018-05-01 19:46:51 +02:00
ESPEasy release bot 5876fb84af automaticly updated release notes for mega-20180501 2018-05-01 04:00:17 +02:00
GrovkillenandGitHub 25ab07a9ba Merge pull request #6 from letscontrolit/mega
update from master
2018-04-30 21:41:41 +02:00
GrovkillenandGitHub e6044bdbf8 Added log JSON 2018-04-30 21:40:35 +02:00
mvdbro 572f8bcde7 Fix broken Mini Dashboard feature 2018-04-30 14:28:25 +02:00
Saverio Cisternino c010640aa5 Optimize setSystemTimer; Removed the second "for" cycle for checking the availability of timers 2018-04-30 09:29:50 +02:00
ESPEasy release bot e60c0dc5f0 automaticly updated release notes for mega-20180430 2018-04-30 04:00:08 +02:00
Gijs NoorlanderandGitHub 4e6e31fdae Merge pull request #1335 from TD-er/bugfix/mqtt_timout
Bugfix/mqtt timout
2018-04-29 17:49:01 +02:00
TD-er 77deb3d8b3 [MQTT] Set default timeout to 10 sec, equal to default Mosquito timeout
See https://github.com/knolleary/pubsubclient/issues/239
2018-04-29 17:41:00 +02:00
TD-er 3530027864 [rules] Add log indicating POST request for update rules
There is something strange going on, POST variables may be empty.
2018-04-29 17:40:07 +02:00
Gijs NoorlanderandGitHub 07bfec4234 Merge pull request #1334 from TD-er/bugfix/wifi_connected_check
[wifi] Use internal ESPeasy state to check connected status
2018-04-29 14:59:28 +02:00
TD-er 3476792c58 [wifi] Use internal ESPeasy state to check connected status 2018-04-29 14:58:50 +02:00
Gijs NoorlanderandGitHub 45afaf8d3f Merge pull request #1333 from TD-er/bugfix/displayNamesInLog
[wifi] Do not rely on WiFi.status() and better log of status
2018-04-29 13:45:58 +02:00
TD-er 9084a5542b [wifi] Do not rely on WiFi.status() and better log of status
`WiFi.status() == WL_CONNECTED` may not always be correct.
For ESP82xx check the SDK status.
2018-04-29 13:27:32 +02:00
mvdbro 4ac330ebf6 Changed plugin call debug timers 2018-04-29 11:51:46 +02:00
ESPEasy release bot 49a0476487 automaticly updated release notes for mega-20180429 2018-04-29 04:00:07 +02:00
Gijs NoorlanderandGitHub f606d2c55d Merge pull request #1331 from TD-er/bugfix/ChangeReconnect
[wifi] Force wifi reconnect at lots of MQTT failed connects.
2018-04-29 00:53:27 +02:00
TD-er 4f9a383d93 [wifi] Force wifi reconnect at lots of MQTT failed connects. 2018-04-29 00:52:41 +02:00
Gijs NoorlanderandGitHub d4d0ee3b30 Merge pull request #1328 from TD-er/bugfix/set_static_IP_after_reconnect
[wifi] Setup static IP config after connecting to wifi.
2018-04-28 23:57:42 +02:00
TD-er 9705702f4c [wifi] Added connectionCheckHandler() to force reconnect when needed
Example taken from [this issue discussion](https://github.com/esp8266/Arduino/issues/4445)
2018-04-28 23:42:34 +02:00
TD-er c3e015342c [wifi] ESP32 does not know wifi_station_get_connect_status() 2018-04-28 23:10:24 +02:00
TD-er 209484554e [wifi] Add wifi status log (Debug More) and DHCP/Static config to info page 2018-04-28 23:06:16 +02:00
TD-er 27377ab3ed [wifi] Show number of reconnects in the sysinfo 2018-04-28 19:08:07 +02:00
TD-er 7055d24693 [wifi] Set static IP config before and after connect
Apparently static IP needs to have IP config set before and after connection has been made.
The beginning is needed to make sure no DHCP client is started.
The second one is needed to make sure the wifi status is correct in the core library.
2018-04-28 17:39:47 +02:00
TD-er 62e6317a23 [wifi] Setup static IP config after connecting to wifi. 2018-04-28 15:45:59 +02:00
ESPEasy release bot 29f89b687d automaticly updated release notes for mega-20180428 2018-04-28 04:00:15 +02:00
Gijs NoorlanderandGitHub 697d20a028 Merge pull request #1325 from TD-er/bugfix/wifi_stability
Known issue:   With NTP enabled, it may be possible the connection is not fully operational.
2018-04-28 00:50:52 +02:00
TD-er e9df0e75b9 [Wifi] Avoid doing network communications when not connected.
This may disrupt the network stack.
2018-04-28 00:10:01 +02:00
TD-er f23f49931b [wifi] Just disconnect when DNS lookup is not possible
This may prevent issues with hostname resolving to 0.0.0.0.
2018-04-27 23:45:31 +02:00
TD-er 4af29c405b [PlatformIO] Updated core to 2.4.1
```
[core_2_4_1]
platform         = espressif8266@1.7.0

[common]
build_flags      = -D BUILD_GIT='"${env.TRAVIS_TAG}"'  ; ${compiler_warnings.build_flags}
                   -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH
```
2018-04-27 21:45:30 +02:00
ESPEasy release bot d780f1a07f automaticly updated release notes for mega-20180426 2018-04-26 04:00:14 +02:00
TD-er f9be283cb7 [wifi] Attempt to make event based wifi simpler
With static IP, the connection is lost frequently.
2018-04-26 02:04:18 +02:00
Gijs NoorlanderandGitHub 3f1cda7b81 Change use of core 2_4_0 to 2_3_0 2018-04-25 16:05:05 +02:00
ESPEasy release bot 2fd226d6bd automaticly updated release notes for mega-20180425 2018-04-25 04:00:08 +02:00
Gijs NoorlanderandGitHub 3d1edcf33e Merge pull request #1311 from TD-er/bugfix/more_active_reconnect
[wifi] More active reconnect to wifi when disconnected
2018-04-25 00:44:30 +02:00
TD-er cc740b46f1 [wifi] More active reconnect to wifi when disconnected
And also set ESP32 to a fixed version, since latest versions may cause lots of reboots/bootloops.
2018-04-25 00:43:05 +02:00
Gijs NoorlanderandGitHub e829058c92 Merge pull request #1310 from giig1967g/mega
Fix another bug in LCD plugin
2018-04-25 00:06:03 +02:00
Plebs 685438c35d Fix another bug in LCD plugin
There was another part in the WRITE section where was trying to read the Settings. Fixed with a global variable.
2018-04-24 23:52:22 +02:00
Gijs NoorlanderandGitHub f8a4ef389f Merge pull request #1309 from giig1967g/mega
Adding 3 new http commands: taskrun, taskvalueset and rules
2018-04-24 23:09:43 +02:00
Gijs NoorlanderandGitHub 7e9c31131c Merge pull request #1308 from TD-er/merge/modbus_1128
[Modbus] PR #1128 made by @s0170071
2018-04-24 22:41:07 +02:00
Plebs 99150c4214 Adding 3 new http commands: taskrun, taskvalueset and rules
Usage:
control?cmd=taskrun,n
control?cmd=taskvalueset,t,v,n
control?cmd=rules,n (0 or 1 to activate or deactivate rules
2018-04-24 22:28:18 +02:00
TD-er ec7e6f80b0 [Modbus] PR #1128 made by @s0170071
Was long overdue to merge, a simple re-do to include the Modbus.ino to allow development of Modbus plugins.
2018-04-24 22:21:50 +02:00
Gijs NoorlanderandGitHub dada682ed6 Merge pull request #1307 from giig1967g/mega
Fix for #1300
2018-04-24 21:40:52 +02:00
GrovkillenandGitHub ab31b33a2c Merge pull request #1305 from Grovkillen/added-"addcopybutton"
Added "addcopybutton"
2018-04-24 12:13:32 +02:00
GrovkillenandGitHub 621585901f Added new lines if BR + delimiter if wanted 2018-04-24 11:09:51 +02:00
ESPEasy release bot eaaf1fe888 automaticly updated release notes for mega-20180424 2018-04-24 04:00:13 +02:00
GrovkillenandGitHub 41e4705198 Merge pull request #5 from Grovkillen/mega
Added copy to clipboard on log page
2018-04-23 21:28:35 +02:00
GrovkillenandGitHub c35fe3d500 Added copy to clipboard on log page
The <br> will work as new lines if pasted into issue template but we might add a conversion within the javascript code. I leave as is for now.
2018-04-23 21:27:36 +02:00
GrovkillenandGitHub e2da8ecbb9 Made copy to clipboard JavaScript based instead 2018-04-23 21:15:20 +02:00
Plebs 3dad26a58a Fix for #1300
LCD 1602 and 2004 fixed.
2018-04-23 19:19:08 +02:00
GrovkillenandGitHub ae930a1d36 Added a void addCopyButton
For general use...
2018-04-23 15:47:02 +02:00
GrovkillenandGitHub 45e980beda Merge pull request #4 from letscontrolit/mega
Update from master
2018-04-23 09:23:52 +02:00
GrovkillenandGitHub 8723e177df Added note to self compilers
Many self compilers are reporting stuff, it's near to impossible to also support these since the different environments are so hard to set up for us developers to test.
2018-04-23 08:34:14 +02:00
ESPEasy release bot 8454994023 automaticly updated release notes for mega-20180423 2018-04-23 04:00:10 +02:00
Gijs NoorlanderandGitHub 50732aed8a Merge pull request #1295 from TD-er/bugfix/delay_between_connection_attempts
[wifi] Add delay between connection attempts
2018-04-22 12:28:09 +02:00
TD-er f2888951dc [wifi] Add delay between connection attempts
Accesspoints cannot handle lots of (immediate) reconnect attempts.
Added a delay of up-to a second between new attempts.
2018-04-22 12:27:24 +02:00
Gijs NoorlanderandGitHub 56ac640986 Merge pull request #1294 from giig1967g/mega
Fixing #1289 for backwards compatibility
2018-04-22 11:52:53 +02:00
Plebs df2d7be30b Fixing #1289 for backwards compatibility
I noticed that my latest commit introduced a small issue with Transformations:
The previous transformations were right justified. The new ones are left justified.
To maintain backwards compatibility I have modified the code.
2018-04-22 11:49:51 +02:00
ESPEasy release bot 9e06cf4dc7 automaticly updated release notes for mega-20180422 2018-04-22 04:00:09 +02:00
Gijs NoorlanderandGitHub cd27339b8e Merge pull request #1293 from TD-er/bugfix/remove_crc_from_config_file
[issue #1292] Remove CRC from settings, init settings and wifi fixes
2018-04-22 02:02:23 +02:00
TD-er ec38ba1fb7 [issue #1292] Remove CRC from settings, init settings and wifi fixes
- Reset wifi when DNS lookup returns *.0.0.0 (NTP lookup sometimes returns like these)
- Accept Wifi events out of order.
- Remove CRC from settings struct
- Patch settings with last few added items initialized
- Changed red question mark to white questionmark, for links to wiki.
2018-04-22 02:01:10 +02:00
Gijs NoorlanderandGitHub b8fa42925f Merge pull request #1289 from giig1967g/mega
Syntax: [task#value#transformation#justification]
2018-04-21 14:21:05 +02:00
Plebs 4169ca0ee8 Code changed as per TD-er suggestions 2018-04-21 09:53:19 +02:00
ESPEasy release bot 578477bf6d automaticly updated release notes for mega-20180421 2018-04-21 04:00:08 +02:00
Gijs NoorlanderandGitHub 0803e946b0 Merge pull request #1290 from TD-er/feature/P076_SonoffPOW
[Sonoff Pow] P076 - Add support for HLW8012 by @papperone
2018-04-21 01:42:38 +02:00
TD-er 06001bbc94 [Sonoff POW] Set some proper defaults for the Sonoff POW
I2C pins may conflict with the used energy sensor.
Also the status LED is set to a non standard pin.
2018-04-21 01:24:48 +02:00
TD-er f171d5b211 [Sonoff POW] Change Plugin ID to 76
Nextion was added as P075
2018-04-21 00:18:05 +02:00
TD-er 360b552424 [Sonoff Pow] Add support for HLW8012 2018-04-21 00:17:52 +02:00
Unknown d9597febf8 Merge remote-tracking branch 'papperone/mega' into merge/papperone
Remove edits on P073 to separate PRs
2018-04-21 00:17:43 +02:00
TD-er 6aa21ea6f8 [Sonoff Pow] Add support for HLW8012 2018-04-21 00:17:33 +02:00
Unknown b1de652b62 Merge remote-tracking branch 'papperone/mega' into merge/papperone
Remove edits on P073 to separate PRs
2018-04-21 00:17:22 +02:00
Plebs 5c3bf9e894 Syntax: [task#value#transformation#justification]
Transformations:
Special:
!: negate (only for 0 or 1)
R: RIGHT JUSTIFY

V: value
O: ON/OFF
C: OPEN/CLOSE
U: UP/DOWN
u: U/D
Y: YES/NO
y: Y/N
X: O/X
I: IN/OUT
Z: 0/1
1: 1 decimal
2: 2 decimals
3: 3 decimals
Dx.y: x digits + y decimals
F: floor
E: ceiling

Justification:
P: prefix spaces
S: suffix spaces
2018-04-20 23:21:17 +02:00
Gijs NoorlanderandGitHub 0acd7b0e70 Merge pull request #1288 from TD-er/bugfix/InitStaticIP_before_connect
[WiFi] Init static IP before connect to wifi
2018-04-20 22:08:22 +02:00
TD-er 8bbaffdeb0 [info] Add more build related info to the log and wifi info link to wiki
Add core information to the log and info page
Add "more info" button to main page
Add question mark link button to sysinfo section describing wifi. This links to the wifi page on the wiki.
2018-04-20 21:54:40 +02:00
TD-er 19e86e7df3 [Toast message] Change "Settings saved" to "Submitted"
Message is sent to provide feedback on pressing the 'submit' button.
At that moment, it is not yet clear the data will be saved successful.
To prevent "Settings Saved" and "Error writing to..." to show on the same page, this text was changed.
2018-04-20 20:55:17 +02:00
TD-er 311d6f01df [WiFi] Init static IP before connect to wifi
As suggested by @Feuerreiter  [here](https://github.com/letscontrolit/ESPEasy/issues/1255#issuecomment-383094333)
2018-04-20 20:37:38 +02:00
Gijs NoorlanderandGitHub 61f47d5ffc Merge pull request #1287 from workgroupengineering/feature/elseif
[Feature] Allow elseif
2018-04-20 20:25:16 +02:00
Gijs NoorlanderandGitHub 72f0f95471 Merge pull request #1285 from Grovkillen/toast-mes
Toast message added
2018-04-20 20:24:56 +02:00
Gijs NoorlanderandGitHub 4e33472d81 Merge pull request #1246 from workgroupengineering/feature/timer_pause_resume
[Feature] Timers Pause and Resume
2018-04-20 20:24:33 +02:00
Saverio Cisternino 69c4f970a9 Add debug info 2018-04-20 16:46:04 +02:00
GrovkillenandGitHub 28866bd08c Removed fade in of body added toast message! 2018-04-20 13:01:14 +02:00
GrovkillenandGitHub 0f93e3ed3c Merge pull request #3 from letscontrolit/mega
Update
2018-04-20 12:59:38 +02:00
Saverio Cisternino 59a82ee17f Add support at elseif statment 2018-04-20 11:36:12 +02:00
Saverio Cisternino e8af00f99f Add Trigger Rules#TimerPause= and Rules#TimerResume= 2018-04-20 11:33:05 +02:00
Saverio Cisternino ad4b0f8008 Add Commands timerpause and timerresume 2018-04-20 11:33:05 +02:00
ESPEasy release bot ae2a0b5208 automaticly updated release notes for mega-20180420 2018-04-20 04:00:09 +02:00
Gijs NoorlanderandGitHub 785266bd39 Merge pull request #1283 from TD-er/bugfix/webserver_restart_connection_change
Bugfix/webserver restart connection change
2018-04-20 00:38:10 +02:00
TD-er 2e63e764b2 [wifi] Create event 'gotIP' after processing 'connected' event
And stop webserver when trying to reconnect to WiFi
2018-04-20 00:35:09 +02:00
TD-er f7eaecf5d4 [log] Make web log 30 lines for ESP32 2018-04-20 00:01:52 +02:00
TD-er 1bee80d0ec [wifi] Restart webserver when connection changes. 2018-04-19 23:43:30 +02:00
GrovkillenandGitHub 504a9aa295 Added extra breaks below "back to setup" button 2018-04-19 15:21:24 +02:00
GrovkillenandGitHub 059530a6b7 Merge pull request #1277 from Grovkillen/Update-GUI
Update GUI a bit more
2018-04-19 11:53:22 +02:00
Gijs NoorlanderandGitHub 5b83c634e9 Merge pull request #1278 from TD-er/bugfix/set_static_at_change_mode
[Static IP] Make sure static mode is set correct always
2018-04-19 11:08:09 +02:00
TD-er ff7ab3837e [Static IP] Make sure static mode is set correct always
Also when changing settings from static to DHCP and vice verse.
2018-04-19 11:07:29 +02:00
GrovkillenandGitHub badad651de "bodymenu" was accidentally copied to all body 2018-04-19 11:01:02 +02:00
GrovkillenandGitHub 8a767b77e8 Added small fade in (0.5s)
To make user understand that submit have been clicked (web interface is so fast now).
2018-04-19 10:38:41 +02:00
GrovkillenandGitHub 072a1a4080 Merge pull request #2 from letscontrolit/mega
update
2018-04-19 10:37:20 +02:00
ESPEasy release bot 394e4b095d automaticly updated release notes for mega-20180419 2018-04-19 04:00:17 +02:00
Gijs NoorlanderandGitHub ae1e62c8c6 Merge pull request #1276 from TD-er/bugfix/pr_1257
Bugfix/pr 1257
2018-04-19 01:25:45 +02:00
TD-er 0efb7823d7 [ESP32] Add Generic info plugin 2018-04-19 01:24:40 +02:00
TD-er 3ee7d4d04e [PR #1257] Make it compile again 2018-04-19 01:24:14 +02:00
stefanandTD-er f2d3a5d222 Changes for use of plugin sets
Remove ifdefs for PLUGIN_BUILD_TESTING to make use of USES_ defines and define_plugin_defs.h
2018-04-19 00:42:56 +02:00
Gijs NoorlanderandGitHub 904a5cc612 Merge pull request #1267 from sentinel073/plugin_template_issue_1211
Issue #1211: Plugin template file and hints on writing new plugins
2018-04-19 00:40:37 +02:00
Gijs NoorlanderandGitHub 5241f93f5f Merge pull request #1268 from hansrune/mega
Implemented syslog facilities and levels
2018-04-19 00:38:37 +02:00
Gijs NoorlanderandGitHub 6d33d21f70 Merge pull request #1266 from Grovkillen/CSS-the-reset-of-the-gui
CSS the rest of the GUI
2018-04-19 00:37:56 +02:00
Gijs NoorlanderandGitHub 045e2ef9f4 Merge pull request #1275 from TD-er/bugfix/Static_ip
[Static IP] Work-around for set _use_static_ip
2018-04-19 00:37:32 +02:00
TD-er 527267de62 [Static IP] Work-around for set _use_static_ip
See [this bug report](https://github.com/esp8266/Arduino/issues/4114), which is not fixed in 2.4.0.

This work-around will make sure no dhcp-client will be started when connecting to a network.
The active DHCP client could result in IP conflicts, difficulty in reconnect and other strange issues.
2018-04-19 00:13:53 +02:00
sentinel073 29c01eeb38 Issue #1211: Plugin template file and hints on writing new plugins
Added review comments
2018-04-18 13:01:49 +03:00
GrovkillenandGitHub 1c5a1d3656 Removed unused row on hardware settings page 2018-04-17 17:31:28 +02:00
GrovkillenandGitHub d6fe76750a Added CSS radio buttons to WiFi setup wizard 2018-04-17 17:18:28 +02:00
Hans-Rune Bue 1889c0f9e5 Implemented syslog facilities and levels
Sending LOG_LEVEL_ERROR as syslog error, LOG_LEVEL_INFO as syslog notice, and everything else as syslog deug
Also added Settings.Syslogfacility setting to be able to choose kernel (still default), user, daemon, message and local0-local7
2018-04-17 12:43:52 +02:00
sentinel073 ebc16044e2 Issue #1211: Plugin template file and hints on writing new plugins 2018-04-17 11:57:37 +03:00
GrovkillenandGitHub 5695ea8fa8 Updated the input, select, textareas with CSS 2018-04-17 10:50:52 +02:00
GrovkillenandGitHub 16cc9aaa6b Merge pull request #1 from letscontrolit/mega
Updated from main
2018-04-17 10:48:37 +02:00
ESPEasy release bot 7f393af2a0 automaticly updated release notes for mega-20180417 2018-04-17 04:00:09 +02:00
Gijs NoorlanderandGitHub 3e22607276 Merge pull request #1264 from TD-er/feature/nextion_port_from_playground
Feature/nextion port from playground
2018-04-17 01:35:06 +02:00
TD-er 4de720382d [wifi] Fix build error for ESP32
Shared function was declared within #ifdef scope.
2018-04-17 01:34:07 +02:00
TD-er a718572688 [P075] Nextion plugin (testing)
Added Nextion plugin for testing from the Playground.
It is not yet tested on real hardware, but it has been in development for a while on the forum and playground.
Also requested in issue #1256 and by several others.
2018-04-17 01:29:31 +02:00
Unknown 2d66c9fefa [Nextion] Initial support for Nextion displays
Code taken from playground P117 and added minimal changes.
Still need some work to check and test with real display.
Not tested yet, myself.
2018-04-16 23:47:12 +02:00
Gijs NoorlanderandGitHub de51a130b3 Merge pull request #1262 from TD-er/bugfix/json_oled
[issue #1260] parentheses error on the json page
2018-04-16 23:28:53 +02:00
TD-er a8020c9011 [issue #1260] parentheses error on the json page 2018-04-16 23:28:02 +02:00
Gijs NoorlanderandGitHub a2cbc6d474 Merge pull request #1261 from TD-er/bugfix/fix_disconnects_static_ip
[wifi] Fix wifi reconnects with static IP
2018-04-16 23:03:05 +02:00
TD-er ea5c99431c [NTP] Add more information in the log when connecting to NTP server fail 2018-04-16 22:49:07 +02:00
TD-er 6f68d87f50 [wifi] Fix wifi reconnects with static IP
When a fixed IP setting is used, there will be no "Got IP" event, which will lead to a timeout and thus reconnect.
As a fix, the "Connected" event will also act like when a "Got IP" event was received when configured to use static IP.
2018-04-16 22:48:23 +02:00
Gijs NoorlanderandGitHub 4aa9c5e0ba Merge pull request #1259 from Grovkillen/Updating-gui
Updating gui (max width etc)
2018-04-16 20:49:07 +02:00
GrovkillenandGitHub 7e4666afed "Ctr (IDX)" was accidentally removed, now added 2018-04-16 17:23:37 +02:00
GrovkillenandGitHub 7651a07efc Added max widths for inputs 2018-04-16 17:02:31 +02:00
GrovkillenandGitHub f961a9f331 Made IDX column wider (device list) 2018-04-16 16:37:39 +02:00
GrovkillenandGitHub bb49cbdc89 Added number input to CSS (width 100px) 2018-04-16 16:34:00 +02:00
GrovkillenandGitHub 7fe1b41ea5 Made input type password part of "wide" 2018-04-16 16:26:18 +02:00
GrovkillenandGitHub 358e9f1e24 Change enable "off" to a nicer X 2018-04-16 16:20:14 +02:00
GrovkillenandGitHub 8f77ffc871 Made controller symbols a bit bigger (1)(2)(3) 2018-04-16 16:09:14 +02:00
GrovkillenandGitHub 60faa58894 Moved help button on hardware page
Moved it up (from right of the submit button which wasn't a good place for it)
2018-04-16 14:40:52 +02:00
GrovkillenandGitHub aba095b25d Moved help button for sleep 2018-04-16 14:00:17 +02:00
GrovkillenandGitHub 617ebe96de Re-arranged Rules page
Button moved down
Edit text removed
2018-04-16 13:45:57 +02:00
GrovkillenandGitHub a1bf42dde1 Put borders around checkboxes
Suggested here: #1253
2018-04-16 13:20:04 +02:00
ESPEasy release bot b0b83543eb automaticly updated release notes for mega-20180416 2018-04-16 04:00:09 +02:00
Gijs NoorlanderandGitHub b97be9c718 Merge pull request #1250 from TD-er/bugfix/wifi_start_ap_mode
[wifi] Prevent starting AP+STA mode with correct settings
2018-04-16 00:51:04 +02:00
TD-er 33831b072b [info] Added FW information to help diagnose issues
A lot of issue reports do not include information about the used version of the core libraries and 'normal', 'dev', etc. 
Since this information helps narrowing down the possible causes of the reported issues, it is best to add them in the general log.
2018-04-16 00:49:17 +02:00
TD-er a5f94298d8 [wifi] Proper log of static IP configuration 2018-04-15 14:41:41 +02:00
TD-er d0dc959d31 [Wifi] force STA mode at boot
I finally have one node acting as described by others and this one reported a disconnect before a connect attempt was made.

Now forcing the wifi in STA mode, should resolve this issue.
2018-04-15 14:10:02 +02:00
TD-er 644aa2f65e [wifi] Prevent starting AP+STA mode with correct settings
WiFi persistent settings were disabled after initialisation of the event handler.
This allowed the firmware to start WiFi connection with settings stored in the flash (not our settings, the settings kept by the core library). If these fail, then a connection failed event would occur before a connect attempt was started from ESPeasy, which would lead to strange results on some nodes while others work just fine.
2018-04-15 12:05:07 +02:00
ESPEasy release bot e457fe7597 automaticly updated release notes for mega-20180415 2018-04-15 04:00:08 +02:00
Gijs NoorlanderandGitHub dcd409e9d9 Merge pull request #1249 from TD-er/bugfix/Webserver_appendingStrings
A lot of functions in Webserver.ino were just appending to a ever increasing string. These strings were eventually sent to TXBuffer of the Webinterface.
So why not directly send them to the streaming buffer and thus reduce memory usage and gain speed.
2018-04-15 02:06:34 +02:00
TD-er c227c13ba2 [Merge] Easier to merge, rebased on Mega branch. 2018-04-15 01:55:22 +02:00
TD-er c64566ce49 [PR #1248] Fixed textarea sizes
See #1248
2018-04-15 01:45:52 +02:00
TD-er a9366c8f23 [PR #1247 ] Merged PR into the refactoring of Webserver 2018-04-15 01:45:52 +02:00
TD-er bbf470c61d [WebServer] Cleanup of all functions appending to a big string
A lot of functions in Webserver.ino were just appending to a ever increasing string. These strings were eventually sent to TXBuffer of the Webinterface.
So why not directly send them to the streaming buffer and thus reduce memory usage and gain speed.
2018-04-15 01:45:30 +02:00
GrovkillenandGitHub 1c1211c4f3 Bumped delay timer for MQTT pub 10mSec
Tests showed that instead of publishing "now" a 10mSec delay made the unit respond better and publish faster.
2018-04-15 00:50:30 +02:00
Gijs NoorlanderandGitHub 7da0bc4a44 Merge pull request #1247 from Grovkillen/Fix-some-html
Fix some html
2018-04-14 21:19:52 +02:00
GrovkillenandGitHub 91a0c51ff8 Made addFormSeparator function a lot cleaner
Thanks to da man @TD-er
2018-04-14 21:15:33 +02:00
GrovkillenandGitHub 0aa523a329 Updated some more stuff
Made the call for the function work without the extra (not used) "extra text"... it's still in the base function for future use.
2018-04-14 20:55:52 +02:00
Gijs NoorlanderandGitHub cac7275eb9 Merge pull request #1245 from susisstrolch/ds18b20
ignore power-on reset value (85.0 °C)
2018-04-14 17:29:50 +02:00
Susis Strolch 109eaf7d25 DS_readTemp: handle power-on reset value
return false if DS_readTemp is power-on reset value
(0xaa for DS1820|DS18B20, 0x550 for DS18B20|DS1825|DS1822)
2018-04-14 15:38:11 +02:00
GrovkillenandGitHub 9ba15f2c19 Added column width for separator...
Now variable
2018-04-14 13:51:06 +02:00
GrovkillenandGitHub 1c07d787c5 Fixed missed update. 2018-04-14 13:45:13 +02:00
GrovkillenandGitHub b7ae2ea5fe Made checkmarks CSS
The &nbsp; is made to be able to have text after the custom checkbox... the text itself is not yet styled since we're not using labels like that yet.
2018-04-14 13:40:49 +02:00
Gijs NoorlanderandGitHub b75bb204e3 Merge pull request #1209 from nunofgs/enhancement/replace-ultrasonic-plugin-with-newping-lib
Replace ultrasonic plugin with NewPing lib
2018-04-14 13:11:14 +02:00
Gijs NoorlanderandGitHub bfc8006205 Merge pull request #1242 from susisstrolch/stringConverter
system variables %sysheap%, %syssec_d
2018-04-14 13:08:28 +02:00
Gijs NoorlanderandGitHub aab2e4a442 Added C013 2018-04-14 12:56:41 +02:00
Gijs NoorlanderandGitHub abfdfe014e Merge pull request #1243 from susisstrolch/defineUses
add missing USES_XXX to _C*.ino, _N*.ino
2018-04-14 12:53:42 +02:00
Susis Strolch f82040d2ef ignore power-on reset value (85.0 °C) 2018-04-14 12:31:17 +02:00
Susis Strolch 56f2cf3121 system variables %sysheap%, %syssec_d
- %sysheap%: free heap memory
- %syssec_d%: seconds since midnight
2018-04-14 12:03:23 +02:00
Susis Strolch 6349f07d1a add missing USES_XXX to _C*.ino, _N*.ino 2018-04-14 10:44:25 +02:00
GrovkillenandGitHub 1b44559d3e Merge pull request #2 from letscontrolit/mega
Update source from MAIN
2018-04-14 08:57:26 +02:00
ESPEasy release bot a151e60755 automaticly updated release notes for mega-20180414 2018-04-14 04:00:08 +02:00
Gijs NoorlanderandGitHub ce11c84e74 Merge pull request #1186 from linuxnico/mega
add ds1822 definition to ds_read_temp function
2018-04-14 00:13:39 +02:00
Gijs NoorlanderandGitHub 9808bf86c4 Merge pull request #1078 from GHolli/mega
Sensor MH-Z19: Fixing offsets for the detection range setting command
2018-04-14 00:13:04 +02:00
Gijs NoorlanderandGitHub cfae636e55 Merge pull request #1240 from TD-er/feature/bssid_channel_variables
[issue #1239] %bssid% and %wi_ch% added as variables
2018-04-14 00:09:23 +02:00
Gijs NoorlanderandGitHub ebaaf50df6 Merge pull request #1230 from Grovkillen/Fix-nomenclature-for-delay/interval
Renamed delay to interval/time for better understanding
2018-04-14 00:09:09 +02:00
Gijs NoorlanderandGitHub 5c0be9e89f Merge pull request #1193 from clumsy-stefan/patch-1
_P015_TSL2561 added Broadband and IR Values
2018-04-14 00:07:32 +02:00
Gijs NoorlanderandGitHub 36468663f7 Merge pull request #1210 from giig1967g/mega
Fixes for #1208 and partial #1196
2018-04-14 00:05:36 +02:00
TD-er fba32608ee [issue #1239] %bssid% and %wi_ch% added as variables
See #1239
2018-04-13 23:47:08 +02:00
GrovkillenandGitHub 06848e50c3 Fixed main page!
Table was messed up... also update other tables
2018-04-13 23:46:45 +02:00
GrovkillenandGitHub 879d0d4916 Added better(?) format for tables
Fixed "normal" and "multirow" table css and made some column widths fixed.
2018-04-13 15:47:13 +02:00
ESPEasy release bot d083a58cd7 automaticly updated release notes for mega-20180413 2018-04-13 04:00:09 +02:00
Gijs NoorlanderandGitHub b1e9ff9fdc Merge pull request #1234 from TD-er/bugfix/Wifi_connection_issues
[wifi] Event based wifi, fix set AP and crash on start
2018-04-13 01:51:45 +02:00
TD-er 304280f415 [wifi] Event based wifi, fix set AP and crash on start
The settings had 2 new values which would be overwriten by the checksum and there was still some issue about when to save the settings.

Also added a check to only save changed settings.

Known issue: 
Sometimes after initial setup of wifi credentials, it is best to perform a reset.
2018-04-13 01:48:22 +02:00
GrovkillenandGitHub 2c8ca1421f Removed the serial print "done." 2018-04-12 09:55:11 +02:00
GrovkillenandGitHub 3ce0fb9f75 Merge branch 'mega' into Fix-nomenclature-for-delay/interval 2018-04-12 09:28:48 +02:00
ESPEasy release bot 8a71d2abd6 automaticly updated release notes for mega-20180412 2018-04-12 04:00:14 +02:00
Gijs NoorlanderandGitHub 1b174f4eac Merge pull request #1224 from flexiti/mega
ESP32 cpu speed and Id
2018-04-12 01:25:45 +02:00
Gijs NoorlanderandGitHub f1d18c7b41 Merge pull request #1220 from TD-er/bugfix/SoftAP_event_based_wifi
[issue #1215] Cannot login to accesspoint on new install
2018-04-12 01:22:46 +02:00
TD-er 204d4607ba Merge remote-tracking branch 'upstream/mega' into bugfix/SoftAP_event_based_wifi 2018-04-12 01:12:28 +02:00
TD-er 51f7ce0cb6 [wifi] Event based wifi, improve scan information. 2018-04-12 01:07:39 +02:00
Nuno Sousa 8f73deb133 Replace ultrasonic plugin with NewPing lib 2018-04-11 23:26:58 +01:00
Gijs NoorlanderandGitHub 1d4147309c [MQTT] Process MQTT loop on publish
As [discussed here](https://github.com/letscontrolit/ESPEasy/issues/1228#issuecomment-380420609).
2018-04-11 15:29:49 +02:00
mvdbro a68e4c1456 Merge branch 'mega' of https://github.com/letscontrolit/ESPEasy into mega 2018-04-11 14:57:22 +02:00
mvdbro 2ee51363dd Reboot/Reset pin, build 20101 patch 2018-04-11 14:57:12 +02:00
TD-er 172eb37b5b [wifi] Fix wifi AP setup mode for ESP32. 2018-04-11 01:24:34 +02:00
GrovkillenandGitHub 68e1d8ea69 Added RSSI, BSSID, Channel to WifiScan/Setup
And also delay is now renamed interval.
2018-04-10 15:47:59 +02:00
GrovkillenandGitHub ac8e8db0e7 Merge pull request #1 from letscontrolit/mega
Update
2018-04-10 14:24:17 +02:00
ESPEasy release bot d72bf9b76c automaticly updated release notes for mega-20180410 2018-04-10 04:00:21 +02:00
GeraldandGitHub 6d3f535d16 Merge pull request #3 from letscontrolit/mega
Downstream updates from head fork.
2018-04-09 21:39:15 +02:00
GrovkillenandGitHub 0709763f3a Update issue_template.md
`YOUR TEXT GOES HERE` added
2018-04-09 13:09:59 +02:00
GrovkillenandGitHub 538d843643 Update issue_template.md
Rearranged the topics...
2018-04-09 13:07:56 +02:00
GrovkillenandGitHub 2339ee928c Update issue_template.md
Added code format
2018-04-09 13:05:55 +02:00
GrovkillenandGitHub 9550b951d5 Update issue_template.md
Added a "Summarize" topic
2018-04-09 12:55:43 +02:00
GrovkillenandGitHub 0491af8a2f Added comments that will not show up on issues
Many users forget to "clean" the template from unnecessary text... these are now automatically hidden.
2018-04-09 12:53:05 +02:00
ESPEasy release bot 806a2757b2 automaticly updated release notes for mega-20180409 2018-04-09 04:00:13 +02:00
TD-er 3931b71d00 Merge branch 'mega' into bugfix/SoftAP_event_based_wifi 2018-04-09 00:17:48 +02:00
TD-er af0c3d5f62 [wifi] Make it work for ESP32 again 2018-04-08 23:50:07 +02:00
mvdbro c7a6ca4555 Both reset/factoryreset option 2018-04-08 17:05:59 +02:00
mvdbro 4a01e2eb49 Factory Reset (not enabled yet) 2018-04-08 08:27:25 +02:00
TD-er d6ff20b35d [WiFi] Event based wifi, now AP mode works
It appeared to be related to the core 2.3.0 version. The 2.4.0 does just work. Also changed a number of other things to improve stability.
2018-04-08 00:34:34 +02:00
ESPEasy release bot 0ada9aa105 automaticly updated release notes for mega-20180407 2018-04-07 04:00:12 +02:00
Holli 6b04539571 Disable detection range commands by default. 2018-04-06 18:40:08 +02:00
Plebs 9380ec13dc Added #I
#I: IN/OUT
2018-04-06 12:41:00 +02:00
GrovkillenandGitHub ae946c27c0 Fixed clickable link www.letscontrolit.com (#1192) 2018-04-06 10:02:36 +02:00
Plebs 86cf00759f added more formats
#X
#y
#Z
2018-04-06 08:38:26 +02:00
Plebs 0eb5f55d63 new #formats
Hi, here the new formats:
#O: ON/OFF
#C: Open/Close
#U: UP/Down
#Y: YES/NO
#D: converto to nearest integer
#F: convert to floor
#E: convert to ceiling
2018-04-05 23:39:54 +02:00
flexitiandGitHub f27d2aa7eb ESP CPU speed and ID 2018-04-05 15:09:24 +02:00
flexitiandGitHub 2d3285aaaf Merge pull request #1 from letscontrolit/mega
update
2018-04-05 15:05:25 +02:00
ESPEasy release bot 5bd2532853 automaticly updated release notes for mega-20180405 2018-04-05 04:00:10 +02:00
Plebs 765c56ccef modified float() call 2018-04-05 00:20:38 +02:00
mvdbro 4c755d83a6 ESP32 RTOS 10 per second
Run 10 per seconds call independent from main loop
2018-04-04 21:55:50 +02:00
mvdbro 1b9e1b92aa ESP32 RTOS config setting 2018-04-04 12:32:17 +02:00
Gijs NoorlanderandGitHub a4c73cc91e Merge pull request #1175 from Grovkillen/Fix-parsing-structure-for-JSON-+-upload-file-filter
Updated JSON path for sensor values and names
2018-04-04 10:06:17 +02:00
Gijs NoorlanderandGitHub 736fe2111a Merge pull request #1218 from soif/Fix/PioConfTypo
Unwanted lib_ignore now properly commented
2018-04-04 10:05:22 +02:00
Gijs NoorlanderandGitHub 767b0af733 Merge pull request #1217 from soif/Feat/JsonLoad
Shows CPU Load in JSON page
2018-04-04 10:04:59 +02:00
TD-er 02255180e9 [Wifi] Use statemachine to move between Wifi states
Still existing problems:
- Credentials are not being saved from web interface and thus connection doesn't work from setup page.
- First time connect to SoftAP takes a lot of attempts, when the wifi was searching for an existing accesspoint. This searching does prevent the SoftAP to form a stable connection to the client.

Maybe the entire wifi stack has to be reset before switching to SoftAP. Now it is near to impossible to recover from incorrect settings or a changes accesspoint.
Still under investigation.

It looks to be a problem with the
2018-04-04 03:19:03 +02:00
ESPEasy release bot c3bde94f7a automaticly updated release notes for mega-20180403 2018-04-03 04:00:14 +02:00
TD-er 886958d479 Merge remote-tracking branch 'origin/bugfix/SoftAP_event_based_wifi' into bugfix/SoftAP_event_based_wifi 2018-04-03 01:04:22 +02:00
TD-er 84cbc19f38 [issue #1215] Cannot login to accesspoint on new install
Since event based wifi, it became more apparent the ESP8266 has some issues with running AP and STA mode simultaneous.
It appears this can only work when the channel remains constant. But when trying to connect to an accesspoint that channel will change.
This means Soft AP and STA cannot be active at the same time when searching for an accesspoint to connect to. For example login to the Soft AP to correct some settings or replace an accesspoint would not be possible.

This fix deals with all of these issues and keeps the fast try/fail connection attempts offered by the event based wifi.
In short:
- 3x attempt to connect to AP1 (each attempt takes about 2.5 seconds when failing)
- 3x attempt to connect to AP2
- Enable accesspoint

When accesspoint is active, the connect attempts will be done at a slower pace and STA mode is disabled. STA mode is also disabled as soon as someone connects to the Soft AP.
When the settings are saved, a retry to connect like normal is started almost immediately. N.B. This will result in a disconnect of the connected users to the Soft AP.

So the connection time is:
- AP1 is valid: 4 - 10 seconds
- AP1 is not valid, AP2 is: 12 - 20 seconds
- AP1 and AP2 are not valid: +/- 18 seconds before activating Soft AP
2018-04-03 01:03:27 +02:00
TD-er 178ec9dfa9 [issue #1215] Cannot login to accesspoint on new install
Since event based wifi, it became more apparent the ESP8266 has some issues with running AP and STA mode simultaneous.
It appears this can only work when the channel remains constant. But when trying to connect to an accesspoint that channel will change.
This means Soft AP and STA cannot be active at the same time when searching for an accesspoint to connect to. For example login to the Soft AP to correct some settings or replace an accesspoint would not be possible.

This fix deals with all of these issues and keeps the fast try/fail connection attempts offered by the event based wifi.
In short:
- 3x attempt to connect to AP1 (each attempt takes about 2.5 seconds when failing)
- 3x attempt to connect to AP2
- Enable accesspoint

When accesspoint is active, the connect attempts will be done at a slower pace and STA mode is disabled. STA mode is also disabled as soon as someone connects to the Soft AP.
When the settings are saved, a retry to connect like normal is started almost immediately. N.B. This will result in a disconnect of the connected users to the Soft AP.

So the connection time is:
- AP1 is valid: 4 - 10 seconds
- AP1 is not valid, AP2 is: 12 - 20 seconds
- AP1 and AP2 are not valid: +/- 18 seconds before activating Soft AP
2018-04-03 00:47:06 +02:00
GrovkillenandGitHub 080be1ad0a Update _P029_Output.ino 2018-04-02 20:41:22 +02:00
GrovkillenandGitHub 232ca4f215 Update _P038_NeoPixel.ino 2018-04-02 20:40:08 +02:00
mvdbro bfa6eac538 ESP32 prep for RTOS multitasking 2018-04-02 15:59:01 +02:00
moi 0ca06782b9 unwanted lib_ignore now properly commented 2018-04-02 13:27:02 +02:00
moi 2079b0f28b Adds CPU Load LC in JSON page 2018-04-02 12:39:14 +02:00
moi 32bf45e817 Show CPU Load in JSON page 2018-04-02 12:38:30 +02:00
Plebs e774ef5751 Fixes for #1208 and partial #1196
Fixed #1208
Added dìformat commands:
#C: 1/0 = Open/Close
#U: 1/0 = Up/Down
2018-03-30 21:05:33 +02:00
GeraldandGitHub 5d3f8bf073 Update _P049_MHZ19.ino
Clarification of pin connections.
2018-03-29 21:28:25 +02:00
GHolliandGitHub dd88db1913 Merge pull request #2 from letscontrolit/mega
Downstream updates
2018-03-29 20:10:05 +02:00
GHolliandGitHub aab00567fc Downstream updates (#1)
* Initial re-organisation of plugin sets (#1019)

* 12bit ADC values acceted up to 4095

MCP3221 is a 12bit ADC so accepted values should be up to 40195 not 1024

* automaticly updated release notes for v2.0-20180313

* - move all structs from ESPEasy.ino into header file
- add some fix for headers
- add const to rtttl notes array

* [issue #1066] Fix Webserver handle_control

There wasn't a proper start/end for the streaming webserver.
See discussion on issue #1066

* automaticly updated release notes for mega-20180314

* Custom controller GUI option

* Fixed #433

Not tested!

* #893, part 2 receiving

* Merge branch 'mega' of github.com:letscontrolit/ESPEasy into mega

# Conflicts:
#	src/ESPEasy.ino

* Rules fix

* #893 part1, send messages

* Custom controller GUI option

* #893, part 2 receiving

* Rules fix

* automaticly updated release notes for mega-20180315

* - move all structs from ESPEasy.ino into header file

- add some fix for headers
- add const to rtttl notes array

* Merge branch 'mega' of github.com:letscontrolit/ESPEasy into mega

# Conflicts:
#	src/ESPEasy.ino

* [v2.0 split globals] Base split on v2.0 version of ESPEasy.ino

*  MCP3221 allow values for calibration (#1073)

MCP3221 allow values for calibration

* [issue #1066] Fix Webserver handle_control (#1079)

[issue #1066] Fix Webserver handle_control

* Fixed multi instance problem on SHT3x #433 (#1081)

Fixed multi instance problem on SHT3x #433

* [issue #1057] AM PM display issue

X:XX PM (for hours 1...9)
X:XX AM (for hours 1...9)
XX:XX PM (for hours 10...12)
XX:XX AM (for hours 10...12)

Added for H:MM (without seconds) notations:
- `%systm_hm%`
-`%systm_hm_am%`

* [issue #993] variable in MQTT subscribe topic

As [noted](https://github.com/letscontrolit/ESPEasy/issues/993#issuecomment-373140135) by @kluszcyn

* [issue #951] Changed System#Initialized  => System#Wake

Changed System#Initialized  => System#Wake
New event name makes more sense and Initialized may be used later to indicate all needed connections, etc. are ready.

* [issue #1057] AM PM display issue

X:XX PM (for hours 1...9)
X:XX AM (for hours 1...9)
XX:XX PM (for hours 10...12)
XX:XX AM (for hours 10...12)

Added for H:MM (without seconds) notations:
- `%systm_hm%`
-`%systm_hm_am%`

* [issue #993] variable in MQTT subscribe topic

As [noted](https://github.com/letscontrolit/ESPEasy/issues/993#issuecomment-373140135) by @kluszcyn

* [issue #951] Changed System#Initialized  => System#Wake

Changed System#Initialized  => System#Wake
New event name makes more sense and Initialized may be used later to indicate all needed connections, etc. are ready.

* automaticly updated release notes for mega-20180316

* automaticly updated release notes for v2.0-20180316

* Add download button for current rule set

* - add encoder write #1086

* changed memory tracker to uint64_t for the ESP32

* Changed so that running all tasks immediately with deep sleep enabled only happens on first iteration after wake up

* Keep uint. Just change the init value.

* [WiFi] Try to minimize effect of WiFi interruptions

And send event when connected to a different accesspoint.
Currently the impact on WiFi reconnects is enorm. The ESP stalls, won't react on events, etc.

* - fix success setting

* - fix P073 success setting in PLUGIN_WRITE callback

* - initialize pointer in P073

* [Relaxed WiFi] Perform WiFi initialization in steps

Doing WiFi initialization in multiple steps, will reduce boot time a lot.
For deepsleep the Setup is waiting for wifi initialization to complete, but for normal use the wifi connection is initiated during setup and checked on regular intervals to see if it is available.
The same for WiFi reconnect, which will hopefully not affect the performance of the ESP module during reconnects.

Also added a check + event when connected to another accesspoint with different BSSID (MAC address of accesspoint). Also the last used BSSID is used to reconnect to try to connect to the same device over and over, which may be useful with WiFi repeaters.

* [Travis error] Some #include test that wasn't meant to be included

... in the commit.

* [JSON] Add uint name (#1099) and WiFi information (PR #1113)

As suggested by @Grovkillen on PR #1113.

* [issue #1007] Allow user specific data in separate file

File will be ignored by git and can be simply included using `-D USE_OWN_DEFAULTS` in the build

* #ifndef instead of #ifdef

* [issue #1007] Add other defines as suggested by @uzi18

* [Memory] parseTemplate did not check if markers were found

"Free Mem" reported this function to be using quite a lot of memory.
Maybe that was related to parsing texts without matching ']' or '#'
Just added some checks to see if they were found.

* [issue #1097] MQTT publish after deep sleep

The MQTTConnect was only called after a while. This is a problem for deepsleep.
So now the MQTT connect is done at the first loop when deep sleep is enabled.

* Add download button for current rule set (#1102)

Add download button for current rule set

* - add encoder write command #1086 (#1103)

- add encoder write command #1086

* Changed so that running all tasks immediately with deep sleep enabled… (#1110)

Changed so that running all tasks immediately with deep sleep enabled only happens on first iteration after wake up

* Merge pull request #1112 from uzi18/fix-p073

Fix p073 - #1111

* Merge pull request #1114 from TD-er/feature/wifi_details_json

[JSON] Add uint name (#1099) and WiFi information (PR #1113)

* Merge pull request #1113 from TD-er/feature/reduce_impact_wifi_disconnect

[Relaxed WiFi] Perform WiFi initialization in steps

* Merge pull request #1116 from TD-er/feature/allow_own_defaults

[issue #1007] Allow user specific data in separate file

* Merge pull request #1118 from TD-er/bugfix/mqtt_publish_after_deep_sleep

[issue #1097] MQTT publish after deep sleep

* [merge] MIssing #endif due to merging.

* automaticly updated release notes for mega-20180319

* automaticly updated release notes for v2.0-20180319

* Fix wiring description for SN75176 transceiver

* Revert "Merge pull request #1116 from TD-er/feature/allow_own_defaults"

This reverts commit 8ccbdcadf0.

* Fix wiring description for SN75176 transceiver

* Revert "Merge pull request #1116 from TD-er/feature/allow_own_defaults"

This reverts commit 8ccbdcadf0.

* [issue #1097] WiFi connect with deepsleep enabled trigger watchdog reset

Did not allow for enough time to do background tasks while waiting for wifi connect with DeepSleep enabled.

* [issue #1097] WiFi connect with deepsleep enabled trigger watchdog reset

Did not allow for enough time to do background tasks while waiting for wifi connect with DeepSleep enabled.

* automaticly updated release notes for mega-20180320

* automaticly updated release notes for v2.0-20180320

* [wifi] Setup with factory settings could not complete

* [wifi] Setup with factory settings could not complete

* [merge issue] Forgotten #endif in merge

* - P012 fix command interpretation

* - P023 fix command interpretation

* - P035 move strings to flash

* - P048 fetch params only when needed

* automaticly updated release notes for mega-20180321

* automaticly updated release notes for v2.0-20180321

* Serial WD crash

* [wifi] Make more robust checks and increase timeout

See #1145

* - P012 fix command interpretation

* - P023 fix command interpretation

* - P035 move strings to flash

* - P048 fetch params only when needed

* Serial WD crash

* [wifi] Make more robust checks and increase timeout

See #1145

* [Memory] parseTemplate did not check if markers were found

"Free Mem" reported this function to be using quite a lot of memory.
Maybe that was related to parsing texts without matching ']' or '#'
Just added some checks to see if they were found.

* [WiFi] Take much more time for initial WiFi connect during setup

Accesspoint is still active, so it may take a lot more time to make the initial connection

* [WiFi] Take much more time for initial WiFi connect during setup

Accesspoint is still active, so it may take a lot more time to make the initial connection

* automaticly updated release notes for mega-20180322

* ESP32 fix

* [Command] Parsing improvement for commands

Use more intelligent parsing of commands and switch statement to improve speed

* automaticly updated release notes for mega-20180323

* [WiFi] Reverted those temp String uses for ssid/pass

Was introduced due to misunderstanding of reported issues with WiFi.

* [issue #1131] Add %unixtime%

Show the current time as [Unix time](https://en.wikipedia.org/wiki/Unix_time) (numbers of seconds that have elapsed since midnight 1970-01-01, UTC)

* [issue #1097] Call MQTTclient.loop() during deepsleep

The `MQTTclient.loop()` function should be called quite often.
This does the actual MQTT handling.
In normal operations, this is called quite frequently, but it should also be called when deepsleep is active and right before deepsleep is activated again.

* [P1] Support for latest standard

* [wifi] Event based connect/reconnect

Now using the core WiFiEvents to act on:

- connect
- disconnect
- gotIP

This will make polling for a status no longer needed.
It also allows to get a better understanding in why diconnects happen, since the disconnect reason is given in the events.
This extra information is also present on the information panel on the webinterface and also in the JSON output.

The entire connect/disconnect/reconnect is now done completely asynchronous and thus takes much less resources from the ESP.
A disconnect will now also send an event: "WiFi#Disconnected"

For deepsleep this means there has to be a minimum awake time set and perhaps use rules to set the ESP into sleep again when done.
Typical connection times to an accesspoint are about 3 seconds + about 1 second for DHCP.

This also resolves the issues where services my try to connect while there is a WiFi connection, but not yet an IP address set.

I already noticed a lot of NTP servers from pool.ntp.org are non responsive the last few weeks, so that may still take some time, but that's another issue.

* automaticly updated release notes for mega-20180324

* [NTP] Speedup NTP again with async WiFi

Previously it would only start calling "now" when the WiFi was already setup.
And in calling `now()`, a call to an NTP server is being made. When this fails, retry again in a minute.
But now the WiFi initialization is asynchronous, so the first NTP query was already failing and thus the retry is already set to a minute.

This is fixed now and also the pool.ntp.org will pick a random one from 0...3 (.pool.ntp.org).
The DNS queries from this pool change about every minute, so if you want to retry because one of the servers is offline, you should try one from the other `N.pool.ntp.org` or else you have to wait for another minute.

* - fix for #1170 - uservar not setted on encwrite

* automaticly updated release notes for mega-20180326

* [issue #1174] Show degree sign via external writes to LCD

Fix suggested by [elmicha](https://github.com/letscontrolit/ESPEasy/issues/1174#issuecomment-376244766)

* [ESP32] Event driven WiFi for ESP32

Not tested, just got some inspiration by these files:

- https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFi/examples/WiFiClientEvents/WiFiClientEvents.ino
- https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFi/src/WiFiGeneric.cpp
- https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/esp32/esp_event.h

* automaticly updated release notes for mega-20180327

* Fix nesting level check

* [Build] Cleanup/split builds using defines

See PR #1034 and #1040 made by @soif

* [build] Disabled a few PlatformIO profiles for now.

There were way too many.
Just placed them in comments and Travis had already built them all to test first.

* automaticly updated release notes for mega-20180328

* [Arduino IDE] Revert changes in include paths

Were changed to be able to test the PlatformIO feature to compile only files that are actually used.
Apparently the Arduino IDE cannot find the files anymore because that IDE needs the parent directory to be named as the main project file, not "src"

* automaticly updated release notes for mega-20180329
2018-03-29 19:53:54 +02:00
clumsy-stefanandGitHub 21cb6135dd _P015_TSL2561 added Broadband and IR Values
Extended Plugin to also read Broadband and IR values from device.
2018-03-29 09:27:53 +02:00
linuxnico 07948c87aa add ds1822 definition to ds_read_temp function 2018-03-28 14:30:05 +02:00
GrovkillenandGitHub 5f4685337e Added value number as discussed. 2018-03-26 14:59:47 +02:00
GrovkillenandGitHub 08c158aa9c Moved to correct folder 2018-03-26 10:33:22 +02:00
GrovkillenandGitHub e9d71a8f35 Delete WebServer.ino
Same mistake as before, wrong folder upload
2018-03-26 10:32:58 +02:00
GrovkillenandGitHub 3e3173cbb0 Updated JSON path for sensor values and names
+file type filter on upload (not OTA since that is not part of ESP Easy core)
2018-03-26 10:31:27 +02:00
GHolliandGitHub 4543a10739 Change comma to semicolon
Same functionality, but more common.
2018-03-22 20:12:28 +01:00
GHolliandGitHub daecf2017e Update _P049_MHZ19.ino 2018-03-13 21:41:17 +01:00
Holli 37122bc619 It seems the offsets [3]..[4] for the detection range setting (command byte 0x99) are wrong in the latest online data sheet: http://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf
According to the MH-Z19B data sheet version 1.2, valid from: 2017.03.22 (received 2018-03-07), the offset should be [6]..[7] instead.
Fixing the implementation accordingly.
2018-03-13 20:22:45 +01:00
134 changed files with 7874 additions and 2097 deletions
+35 -9
View File
@@ -1,18 +1,44 @@
**NOTE: This is not a support forum! For questions and support go here: https://www.letscontrolit.com/forum/viewforum.php?f=1**
<!--- 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 --->
<!--- Remove topics that are not applicable to your feature request of issue --->
<!--- Remember to have a "to the point" TITLE --->
### Steps to reproduce
How can we trigger this problem?
Does the problem persists after powering off and on? (just resetting isn't enough sometimes)
### Summarize of the problem/feature request
<!--- Describe the problem or feature request --->
YOUR TEXT GOES HERE
### Expected behavior
Tell us what should happen?
<!--- Tell us what should happen? --->
YOUR TEXT GOES HERE
### Actual behavior
Tell us what happens instead?
<!--- Tell us what happens instead? --->
YOUR TEXT GOES HERE
### Steps to reproduce
<!--- How can we trigger this problem? --->
1.
2.
3.
<!--- Does the problem persists after powering off and on? (just resetting isn't enough sometimes) --->
<!--- Please document if you have restarted the unit and if the problem is then gone etc. etc. --->
### System configuration
<!--- Please add as much information and screenshots as possible --->
Hardware:
Software or git version:
<!--- You should also provide links to hardware pages etc where we can find more info --->
<!--- If you self compile, please state this and PLEASE try to ONLY REPORT ISSUES WITH OFFICIAL BUILDS! --->
ESP Easy version:
<!--- In order to have a better readablity of your issue then you should place screenshots here --->
<!--- Simply drag and drop them onto this template, move the text string below the "ESP Easy settings/screenshots" topic --->
ESP Easy settings/screenshots:
### Rules or log data
<!--- place your code/rules between the two ``` rows --->
<!--- remove if not applicable! --->
```
```
+1
View File
@@ -16,3 +16,4 @@
## Project #####################
lib/readme.txt
src/Custom.h
test/output_export.cpp
+3 -1
View File
@@ -27,11 +27,13 @@ install:
script:
# - cppcheck --enable=warning src/*.ino -q --force -I src --include=src/ESPEasy.ino --error-exitcode=1
# - ./memanalyzer.py ~/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-objdump
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run
# patch platformio core libs for PUYA bug (https://github.com/letscontrolit/ESPEasy/issues/650)
- cd patches; ./check_puya_patch; cd ..
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -s --environment dev_ESP8266PUYA_1024
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -s --environment dev_ESP8266PUYA_1024
before_deploy:
+6 -3
View File
@@ -18,13 +18,16 @@ for ENV in \
dev_ESP8266_4096\
dev_ESP8285_1024\
dev_ESP8266PUYA_1024\
dev_ESP8266PUYA_1024_VCC;\
dev_ESP8266PUYA_1024_VCC\
hard_SONOFF_POW\
esp32dev;\
do
echo
echo "### Deploying environment $ENV for version $VERSION"
BIN=.pioenvs/$ENV/firmware.bin
BIN=.pioenvs/${ENV}/ESP_Easy_${VERSION}_${ENV}.bin
cp .pioenvs/${ENV}/firmware.bin $BIN
python2 crc2.py $BIN
cp $BIN dist/"ESP_Easy_$VERSION""_$ENV.bin"
mv $BIN "dist/ESP_Easy_${VERSION}_${ENV}.bin"
done
+17 -17
View File
@@ -5,10 +5,10 @@ import struct
import md5
import os
MD5DUMMY = "MD5_MD5_MD5_MD5_BoundariesOfTheSegmentsGoHere..." #48 chars
FILENAMEDUMMY = "ThisIsTheDummyPlaceHolderForTheBinaryFilename..." #48 chars
FILENAMEDUMMY = "ThisIsTheDummyPlaceHolderForTheBinaryFilename64ByteLongFilenames" #64 chars
MemorySegmentStart,MemorySegmentEnd,MemoryContent=[],[],[]
##################################################################
# this subroutine shows the segments of a part
##################################################################
@@ -18,7 +18,7 @@ def showSegments (fileContent,offset):
herestr =""
herestr2 =""
MemorySegmentStart.append(struct.pack("I",header[0]))
MemorySegmentEnd.append(struct.pack("I",header[0]+header[1]))
MemorySegmentEnd.append(struct.pack("I",header[0]+header[1]))
MemoryContent.append(fileContent[offset+8:offset+8+header[1]])
if fileContent.find( MD5DUMMY, offset+8, offset+8+header[1]) >0 :
herestr= " <-- CRC is here."
@@ -42,7 +42,7 @@ def showParts(fileContent, offset):
return nextSegmentOffset
##################################################################
# MAIN
# MAIN
##################################################################
#if len(sys.argv) !=2 :
@@ -71,21 +71,21 @@ includeStr = "hash includes segments:"
# 4: RAM
for i in (1,2 ): # use only stable segments, must be 4 in total. We use 2.
startArray =startArray + MemorySegmentStart[i]
endArray = endArray + MemorySegmentEnd[i]
startArray =startArray + MemorySegmentStart[i]
endArray = endArray + MemorySegmentEnd[i]
hashString =hashString + MemoryContent[i]
with open(FileName+str(i), mode='wb') as file: # b is important -> binary
file.write(MemoryContent[i])
includeStr = includeStr +" "+ str(i)
print (includeStr)
# IMPORTANT: pad array with zeros if you use only 3 segments (see above)
while len(startArray) < 16 :
startArray =startArray + struct.pack("I",0)
endArray = endArray + struct.pack("I",0)
# debug print (binascii.hexlify(startArray))
# IMPORTANT: pad array with zeros if you use only 3 segments (see above)
while len(startArray) < 16 :
startArray =startArray + struct.pack("I",0)
endArray = endArray + struct.pack("I",0)
# debug print (binascii.hexlify(startArray))
# debug print (binascii.hexlify(endArray))
if (len(endArray) + len (startArray)) != 32 :
print("ERROR: please make sure you add / remove padding if you change the semgents.")
print("ERROR: please make sure you add / remove padding if you change the semgents.")
BinaryFileName = "";
if fileContent.find( FILENAMEDUMMY) < 0:
@@ -95,22 +95,22 @@ else:
if len(BinaryFileName) >48: # check that filename is <48 chars
BinaryFileName=BinaryFileName[0:48] # truncate if necessary. 49th char in ESP is zero already
else:
BinaryFileName= BinaryFileName.ljust(48,'\0'); # pad with zeros.
BinaryFileName= BinaryFileName.ljust(48,'\0'); # pad with zeros.
if fileContent.find( MD5DUMMY) < 0:
print("ERROR: MD5 dummy not found in binary")
else:
hashString=hashString.replace (MD5DUMMY,"",1)
hashString=hashString.replace (MD5DUMMY,"",1)
m = md5.new()
m.update (hashString) #use segment 1
md5hash = m.digest()
print("MD5 hash: "+ m.hexdigest())
print("\nwriting output file:\n" + FileName)
fileContent=fileContent.replace(MD5DUMMY,md5hash+startArray+endArray)
fileContent=fileContent.replace(FILENAMEDUMMY,BinaryFileName)
with open(FileName, mode='wb') as file: # b is important -> binary
file.write(fileContent)
#k=input("press close to exit")
#k=input("press close to exit")
+641
View File
@@ -1,3 +1,644 @@
-------------------------------------------------
Changes in release mega-20180514 (since mega-20180513)
-------------------------------------------------
Release date: Mon May 14 04:00:09 CEST 2018
Plebs (1):
Added more #formats transformations
TD-er (5):
[#1411] Add SensorTypeNone to indicate no sensor values for Domoticz
[memory] use "-DNDEBUG" to disable ASSERT macros
[issue #1380] Prevent memory leaks in WiFiClient
[memory corruption] LWIP data corrupts log buffer
[ESP32] ESP.getResetReason() is unknown to ESP32
ZericE (6):
[#1404] Fix email notification for RFC2821, fix so msg body included.
undo unnecessary changes in email body
remove debug lines in email notify
updated comment
remove unneeded use of bMesg to free up mem.
use reference to free up mem.
flexiti (4):
Improvement in the file platformio.ini
OTA check box
ESP32 OTA port is set to 3232
ESP32 OTA port setting
-------------------------------------------------
Changes in release mega-20180513 (since mega-20180512)
-------------------------------------------------
Release date: Sun May 13 04:00:08 CEST 2018
Gijs Noorlander (2):
Fix debug code (commented) in _P045_MPU6050.ino
[PR #1304] Rename file before running crc2.py
-------------------------------------------------
Changes in release mega-20180512 (since mega-20180511)
-------------------------------------------------
Release date: Sat May 12 04:00:06 CEST 2018
Grovkillen (15):
Fixed the timers for log + devices
Fixed format (I like tabs, Platformio like spaces)
Preparation for fixed decimals...
Removed a timer reset...
Fixed some small syntax missing
Added check to stop flooding
Fixed scrolling issue when fetch <450mSec
Fix for decimals on auto update device page
Added ";"
[web log] fixed overflow when set to "debug dev"
[web log] fixed wait on requests
[device page] added max request here too
[web log] also taking care of disconnects
[device page] added dynamic length to loop
[web log] safety net not needed anymore
TD-er (2):
[JSON] Add number of decimals to the JSON output
[build] Do builds twice on the nightly builds
-------------------------------------------------
Changes in release mega-20180511 (since mega-20180510)
-------------------------------------------------
Release date: Fri May 11 04:00:08 CEST 2018
TD-er (3):
[cleanup] Simplify formatting user variables and allow checking
[log JSON] Add log level legend to the logjson output
[Web] Improve serving large blobs directly from flash
-------------------------------------------------
Changes in release mega-20180510 (since mega-20180507)
-------------------------------------------------
Release date: Thu May 10 04:00:13 CEST 2018
Grovkillen (7):
First draft of auto update of task/device values
Values are updated (1-4 values per task)
Wrap up for the PR
Added div to web log (color scheme)
Removed auto update of values... wrong branch
Fixed the log level colors
Fixed copy to clipboard (handle HTML tags)
Saverio Cisternino (1):
Fix plugin_id visualization on devices view that afflict Development build
TD-er (2):
[build] Special build config for Ventus W266
[Ventus W266] Fix signed/unsigned warning
ZericE (1):
[#1368] Remove call to Plugin_041_update causing a hard crash.
-------------------------------------------------
Changes in release mega-20180507 (since mega-20180506)
-------------------------------------------------
Release date: Mon May 7 04:00:08 CEST 2018
Grovkillen (1):
[issue template] extra reminder to self compilers
-------------------------------------------------
Changes in release mega-20180506 (since mega-20180505)
-------------------------------------------------
Release date: Sun May 6 04:00:08 CEST 2018
Grovkillen (10):
Added javascript to handle the log entries
Added div to not copy "Fetching log entries...."
Web log now inside a textarea
If error make log show this more clear
Added break...
BR should be \n, now fixed
Forgot extra \ for escape in code
Added some "-"
Updated to compile with TD-er's update on JSON
Forgot the auto-scroll function... now added
Plebs (2):
fix for #960
new command logentry
TD-er (5):
[JSON] Use streaming webserver for serving JSON page
[JSON] Make proper log JSON output for log viewer
[JSON] Sanitize JSON value strings
[JSON] Add TTL, task interval and task enabled
[JSON] Fix for single task view of json output.
ZericE (1):
[#1356] Remove redundant call to MQTTCheck
-------------------------------------------------
Changes in release mega-20180505 (since mega-20180505_TD-er)
-------------------------------------------------
Release date: Sat May 5 04:00:07 CEST 2018
TD-er (2):
[#1337] Include hidden SSID in wifi scans
[#1337] WiFi.isHidden() is unknown to ESP32
-------------------------------------------------
Changes in release mega-20180504 (since mega-20180503)
-------------------------------------------------
Release date: Fri May 4 04:00:10 CEST 2018
Grovkillen (3):
Added dropdown for phones
[#1363] fixed overlapping checkboxes
Added a break under the hamburger
TD-er (3):
[rules timer] revert treating the rules timer as periodical timer
[Settings] Add checks to investigate issues with overlap in settings
[LWIP2] Change LWIP1.4 => LWIP2 Low Memory
-------------------------------------------------
Changes in release mega-20180503 (since mega-20180502)
-------------------------------------------------
Release date: Thu May 3 04:00:12 CEST 2018
Grovkillen (1):
Spelling correction
TD-er (3):
[rules] Make rules start working again.
[timers] Make rules timers more constant and MQTT reconnect less aggressive
[#1353] Remove Domoticz HTTP as default controller
-------------------------------------------------
Changes in release mega-20180502 (since mega-20180501)
-------------------------------------------------
Release date: Wed May 2 04:00:16 CEST 2018
Grovkillen (1):
Added log JSON
Plebs (4):
fix for #1170
fix for #1142
deleted comments
Added 2 system variables
Saverio Cisternino (1):
Optimize setSystemTimer; Removed the second "for" cycle for checking the availability of timers
TD-er (5):
[LWIP 1.4.0] Change to LWIP 1.4.0, to allow large http POST messages
[LWIP] fix ESP32 build
[timers] Make timers more accurate
[wifi] Make retry intervals to connect increase at each attempt.
[web log] Read all items from the log buffer
-------------------------------------------------
Changes in release mega-20180501 (since mega-20180430)
-------------------------------------------------
Release date: Tue May 1 04:00:17 CEST 2018
mvdbro (1):
Fix broken Mini Dashboard feature
-------------------------------------------------
Changes in release mega-20180430 (since mega-20180429)
-------------------------------------------------
Release date: Mon Apr 30 04:00:08 CEST 2018
TD-er (4):
[wifi] Do not rely on WiFi.status() and better log of status
[wifi] Use internal ESPeasy state to check connected status
[rules] Add log indicating POST request for update rules
[MQTT] Set default timeout to 10 sec, equal to default Mosquito timeout
mvdbro (1):
Changed plugin call debug timers
-------------------------------------------------
Changes in release mega-20180429 (since mega-20180428)
-------------------------------------------------
Release date: Sun Apr 29 04:00:07 CEST 2018
TD-er (7):
[wifi] Setup static IP config after connecting to wifi.
[wifi] Set static IP config before and after connect
[wifi] Show number of reconnects in the sysinfo
[wifi] Add wifi status log (Debug More) and DHCP/Static config to info page
[wifi] ESP32 does not know wifi_station_get_connect_status()
[wifi] Added connectionCheckHandler() to force reconnect when needed
[wifi] Force wifi reconnect at lots of MQTT failed connects.
-------------------------------------------------
Changes in release mega-20180428 (since mega-20180426)
-------------------------------------------------
Release date: Sat Apr 28 04:00:15 CEST 2018
TD-er (4):
[wifi] Attempt to make event based wifi simpler
[PlatformIO] Updated core to 2.4.1
[wifi] Just disconnect when DNS lookup is not possible
[Wifi] Avoid doing network communications when not connected.
-------------------------------------------------
Changes in release mega-20180426 (since mega-20180425)
-------------------------------------------------
Release date: Thu Apr 26 04:00:14 CEST 2018
Gijs Noorlander (1):
Change use of core 2_4_0 to 2_3_0
-------------------------------------------------
Changes in release mega-20180425 (since mega-20180424)
-------------------------------------------------
Release date: Wed Apr 25 04:00:08 CEST 2018
Grovkillen (4):
Added a void addCopyButton
Made copy to clipboard JavaScript based instead
Added copy to clipboard on log page
Added new lines if BR + delimiter if wanted
Plebs (3):
Fix for #1300
Adding 3 new http commands: taskrun, taskvalueset and rules
Fix another bug in LCD plugin
TD-er (2):
[Modbus] PR #1128 made by @s0170071
[wifi] More active reconnect to wifi when disconnected
-------------------------------------------------
Changes in release mega-20180424 (since mega-20180423)
-------------------------------------------------
Release date: Tue Apr 24 04:00:13 CEST 2018
Grovkillen (1):
Added note to self compilers
-------------------------------------------------
Changes in release mega-20180423 (since mega-20180422)
-------------------------------------------------
Release date: Mon Apr 23 04:00:10 CEST 2018
Plebs (1):
Fixing #1289 for backwards compatibility
TD-er (1):
[wifi] Add delay between connection attempts
-------------------------------------------------
Changes in release mega-20180422 (since mega-20180421)
-------------------------------------------------
Release date: Sun Apr 22 04:00:09 CEST 2018
Plebs (2):
Syntax: [task#value#transformation#justification]
Code changed as per TD-er suggestions
TD-er (1):
[issue #1292] Remove CRC from settings, init settings and wifi fixes
-------------------------------------------------
Changes in release mega-20180421 (since mega-20180420)
-------------------------------------------------
Release date: Sat Apr 21 04:00:08 CEST 2018
Grovkillen (1):
Removed fade in of body added toast message!
Saverio Cisternino (4):
Add Commands timerpause and timerresume
Add Trigger Rules#TimerPause= and Rules#TimerResume=
Add support at elseif statment
Add debug info
TD-er (7):
[WiFi] Init static IP before connect to wifi
[Toast message] Change "Settings saved" to "Submitted"
[info] Add more build related info to the log and wifi info link to wiki
[Sonoff Pow] Add support for HLW8012
[Sonoff Pow] Add support for HLW8012
[Sonoff POW] Change Plugin ID to 76
[Sonoff POW] Set some proper defaults for the Sonoff POW
Unknown (2):
Merge remote-tracking branch 'papperone/mega' into merge/papperone
Merge remote-tracking branch 'papperone/mega' into merge/papperone
-------------------------------------------------
Changes in release mega-20180420 (since mega-20180419)
-------------------------------------------------
Release date: Fri Apr 20 04:00:09 CEST 2018
Grovkillen (3):
Added small fade in (0.5s)
"bodymenu" was accidentally copied to all body
Added extra breaks below "back to setup" button
TD-er (4):
[Static IP] Make sure static mode is set correct always
[wifi] Restart webserver when connection changes.
[log] Make web log 30 lines for ESP32
[wifi] Create event 'gotIP' after processing 'connected' event
-------------------------------------------------
Changes in release mega-20180419 (since mega-20180417)
-------------------------------------------------
Release date: Thu Apr 19 04:00:17 CEST 2018
Grovkillen (3):
Updated the input, select, textareas with CSS
Added CSS radio buttons to WiFi setup wizard
Removed unused row on hardware settings page
Hans-Rune Bue (1):
Implemented syslog facilities and levels
TD-er (3):
[Static IP] Work-around for set _use_static_ip
[PR #1257] Make it compile again
[ESP32] Add Generic info plugin
sentinel073 (2):
Issue #1211: Plugin template file and hints on writing new plugins
Issue #1211: Plugin template file and hints on writing new plugins Added review comments
stefan (1):
Changes for use of plugin sets
-------------------------------------------------
Changes in release mega-20180417 (since mega-20180416)
-------------------------------------------------
Release date: Tue Apr 17 04:00:09 CEST 2018
Grovkillen (11):
Put borders around checkboxes
Re-arranged Rules page
Moved help button for sleep
Moved help button on hardware page
Made controller symbols a bit bigger (1)(2)(3)
Change enable "off" to a nicer X
Made input type password part of "wide"
Added number input to CSS (width 100px)
Made IDX column wider (device list)
Added max widths for inputs
"Ctr (IDX)" was accidentally removed, now added
TD-er (5):
[wifi] Fix wifi reconnects with static IP
[NTP] Add more information in the log when connecting to NTP server fail
[issue #1260] parentheses error on the json page
[P075] Nextion plugin (testing)
[wifi] Fix build error for ESP32
Unknown (1):
[Nextion] Initial support for Nextion displays
-------------------------------------------------
Changes in release mega-20180416 (since mega-20180415)
-------------------------------------------------
Release date: Mon Apr 16 04:00:09 CEST 2018
TD-er (4):
[wifi] Prevent starting AP+STA mode with correct settings
[Wifi] force STA mode at boot
[wifi] Proper log of static IP configuration
[info] Added FW information to help diagnose issues
-------------------------------------------------
Changes in release mega-20180415 (since mega-20180414)
-------------------------------------------------
Release date: Sun Apr 15 04:00:08 CEST 2018
Gijs Noorlander (1):
Added C013
Grovkillen (6):
Made checkmarks CSS
Fixed missed update.
Added column width for separator...
Updated some more stuff
Made addFormSeparator function a lot cleaner
Bumped delay timer for MQTT pub 10mSec
Nuno Sousa (1):
Replace ultrasonic plugin with NewPing lib
Susis Strolch (4):
add missing USES_XXX to _C*.ino, _N*.ino
system variables %sysheap%, %syssec_d
ignore power-on reset value (85.0 °C)
DS_readTemp: handle power-on reset value
TD-er (4):
[WebServer] Cleanup of all functions appending to a big string
[PR #1247 ] Merged PR into the refactoring of Webserver
[PR #1248] Fixed textarea sizes
[Merge] Easier to merge, rebased on Mega branch.
-------------------------------------------------
Changes in release mega-20180414 (since mega-20180413)
-------------------------------------------------
Release date: Sat Apr 14 04:00:08 CEST 2018
GHolli (3):
Update _P049_MHZ19.ino
Change comma to semicolon
Downstream updates (#1)
Gerald (1):
Update _P049_MHZ19.ino
Grovkillen (4):
Added RSSI, BSSID, Channel to WifiScan/Setup
Removed the serial print "done."
Added better(?) format for tables
Fixed main page!
Holli (2):
It seems the offsets [3]..[4] for the detection range setting (command byte 0x99) are wrong in the latest online data sheet: http://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf According to the MH-Z19B data sheet version 1.2, valid from: 2017.03.22 (received 2018-03-07), the offset should be [6]..[7] instead. Fixing the implementation accordingly.
Disable detection range commands by default.
Plebs (5):
Fixes for #1208 and partial #1196
modified float() call
new #formats
added more formats
Added #I
TD-er (1):
[issue #1239] %bssid% and %wi_ch% added as variables
clumsy-stefan (1):
_P015_TSL2561 added Broadband and IR Values
linuxnico (1):
add ds1822 definition to ds_read_temp function
-------------------------------------------------
Changes in release mega-20180413 (since mega-20180412)
-------------------------------------------------
Release date: Fri Apr 13 04:00:09 CEST 2018
TD-er (1):
[wifi] Event based wifi, fix set AP and crash on start
-------------------------------------------------
Changes in release mega-20180412 (since mega-20180410)
-------------------------------------------------
Release date: Thu Apr 12 04:00:14 CEST 2018
Gijs Noorlander (1):
[MQTT] Process MQTT loop on publish
TD-er (7):
[issue #1215] Cannot login to accesspoint on new install
[issue #1215] Cannot login to accesspoint on new install
[Wifi] Use statemachine to move between Wifi states
[WiFi] Event based wifi, now AP mode works
[wifi] Make it work for ESP32 again
[wifi] Fix wifi AP setup mode for ESP32.
[wifi] Event based wifi, improve scan information.
flexiti (1):
ESP CPU speed and ID
mvdbro (1):
Reboot/Reset pin, build 20101 patch
-------------------------------------------------
Changes in release mega-20180410 (since mega-20180409)
-------------------------------------------------
Release date: Tue Apr 10 04:00:21 CEST 2018
Grovkillen (5):
Added comments that will not show up on issues
Update issue_template.md
Update issue_template.md
Update issue_template.md
Update issue_template.md
-------------------------------------------------
Changes in release mega-20180409 (since mega-20180407)
-------------------------------------------------
Release date: Mon Apr 9 04:00:13 CEST 2018
mvdbro (2):
Factory Reset (not enabled yet)
Both reset/factoryreset option
-------------------------------------------------
Changes in release mega-20180407 (since mega-20180405)
-------------------------------------------------
Release date: Sat Apr 7 04:00:12 CEST 2018
Grovkillen (1):
Fixed clickable link www.letscontrolit.com (#1192)
-------------------------------------------------
Changes in release mega-20180405 (since mega-20180403)
-------------------------------------------------
Release date: Thu Apr 5 04:00:10 CEST 2018
Grovkillen (4):
Updated JSON path for sensor values and names
Delete WebServer.ino
Moved to correct folder
Added value number as discussed.
moi (3):
Show CPU Load in JSON page
Adds CPU Load LC in JSON page
unwanted lib_ignore now properly commented
mvdbro (2):
ESP32 RTOS config setting
ESP32 RTOS 10 per second
-------------------------------------------------
Changes in release mega-20180403 (since mega-20180402)
-------------------------------------------------
Release date: Tue Apr 3 04:00:14 CEST 2018
Grovkillen (2):
Update _P038_NeoPixel.ino
Update _P029_Output.ino
mvdbro (1):
ESP32 prep for RTOS multitasking
-------------------------------------------------
Changes in release mega-20180402 (since mega-20180401)
-------------------------------------------------
+8
View File
@@ -0,0 +1,8 @@
# Precompiled Headers
*.gch
*.pch
# PlatformIO folders
.pioenvs
.piolibdeps
pio
+39
View File
@@ -0,0 +1,39 @@
{
"name": "HLW8012",
"license": "GPL-3.0",
"platforms": [
"atmelavr",
"espressif8266"
],
"repository": {
"url": "https://bitbucket.org/xoseperez/hlw8012.git",
"type": "git"
},
"frameworks": [
"arduino"
],
"version": "1.0.0",
"export": {
"exclude": "tests"
},
"examples": [
"examples/*/*.ino"
],
"dependencies": [],
"authors": [
{
"maintainer": true,
"name": "Xose Perez",
"url": "http://tinkerman.cat",
"email": "xose.perez@gmail.com"
}
],
"keywords": [
"current",
"hlw8012",
"power",
"voltage"
],
"id": 1281,
"description": "HLW8012 library for Arduino and ESP8266"
}
+15
View File
@@ -0,0 +1,15 @@
# HLW8012 change log
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.0.0] 2017-01-13
### Added
- Added reactive power calculation
- Added reset calibration values
### Fixed
- Using volatile for variable inside callbacks
## [0.1.0] 2016-11-08
- Initial working version
+675
View File
@@ -0,0 +1,675 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+62
View File
@@ -0,0 +1,62 @@
# HLW8012
HLW8012 library for Arduino and ESP8266 using the [Arduino Core for ESP8266][1].
![HLW8012 Pinoout](/docs/HLW8012_pinout.png)
This is the IC present in some chinese products like [Itead's Sonoff POW][2].
The HLW8012 is a current, voltage and power monitor IC that outputs a pulse of a frequency inversely proportional to the value to be read.
This IC provides two PWM outputs, the first one for power and the second one for current or voltage, depending on the SEL pin. The output values are always RMS. Power measurements are very consistent but current or voltage measurements require a minimum time lapse after changing the SEL pin value to become stable. This fact reduces sampling frequency.
Higher values (of power, current or voltage) mean shorter pulses.
Typical values are:
* A 1Hz pulse on CF pin means around 12W RMS
* A 1Hz pulse on CF1 pin means 15mA or 0.5V RMS depending on the value in SEL pin
These ratios are per datasheet typical application, but the actual circuitry might be different.
Even if the circuit matches that on the datasheet the IC tolerances are quite loosy (+-15% for clock frequency, for instance).
## Features
The main features of the HLW8012 library are:
* Two available modes: interrupt-driven or non-interrupt-driven.
* Default calibration based on product datasheet (3.1 Typical Applications).
* You can specify the resistor values for your circuit.
* Optional manual calibration based on expected values.
## Usage
Check the examples for indications on how to use the library.
### Interrupt driven mode
When using interrupts, values are monitored in the background. When calling the get***() methods the last sampled value is returned, this value might be up to a few seconds old if they are very low values. This is specially obvious when switching off the load. The new value of 0W or 0mA is ideally represented by infinite-length pulses. That means that the interrupt is not triggered, the value does not get updated and it will only timeout after 2 seconds (configurable through the pulse_timeout parameter in the begin() method). During that time lapse the library will still return the last non-zero value.
### Non interrupt mode
On the other hand, when not using interrupts, you have to let some time for the pulses in CF1 to stabilize before reading the value. So after calling setMode or toggleMode leave 2 seconds minimum before calling the get methods. The get method for the current mode will measure the pulse width and return the corresponding value, the other one will return the cached value (or 0 if none).
Use non-interrupt approach and a low pulse_timeout (200ms) only if you are deploying a battery powered device and you care more about your device power consumption than about precission. But then you should know the HLW8012 takes about 15mW...
### Notes
I've put together this library after doing a lot of tests with a Sonoff POW[2]. The HLW8012 datasheet (in the "docs" folder) gives some information but I couldn't find any about this issue in the CF1 line that requires some time for the pulse length to stabilize (apparently). Any help about that will be very welcome.
## Manual calibration
Use a pure resistive load with a well-known power consumption or use a multimeter to monitor it. A bulb is usually a good idea, although a toaster would be better since it's power consumption is higher.
Then use the expected*() methods and feed the values. For instance, for a 60W bulb in a 230 line that would be:
```
hlw8012.expectedActivePower(60.0);
hlw8012.expectedVoltage(230.0);
hlw8012.expectedCurrent(60.0 / 230.0);
```
[1]:https://github.com/esp8266/Arduino
[2]:https://www.itead.cc/sonoff-pow.html?acc=70efdf2ec9b086079795c442636b55fb
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

@@ -0,0 +1,120 @@
#include <Arduino.h>
#include "HLW8012.h"
#define SERIAL_BAUDRATE 115200
// GPIOs
#define RELAY_PIN 12
#define SEL_PIN 5
#define CF1_PIN 13
#define CF_PIN 14
// Check values every 2 seconds
#define UPDATE_TIME 2000
// Set SEL_PIN to HIGH to sample current
// This is the case for Itead's Sonoff POW, where a
// the SEL_PIN drives a transistor that pulls down
// the SEL pin in the HLW8012 when closed
#define CURRENT_MODE HIGH
// These are the nominal values for the resistors in the circuit
#define CURRENT_RESISTOR 0.001
#define VOLTAGE_RESISTOR_UPSTREAM ( 5 * 470000 ) // Real: 2280k
#define VOLTAGE_RESISTOR_DOWNSTREAM ( 1000 ) // Real 1.009k
HLW8012 hlw8012;
void unblockingDelay(unsigned long mseconds) {
unsigned long timeout = millis();
while ((millis() - timeout) < mseconds) delay(1);
}
void calibrate() {
// Let's first read power, current and voltage
// with an interval in between to allow the signal to stabilise:
hlw8012.getActivePower();
hlw8012.setMode(MODE_CURRENT);
unblockingDelay(2000);
hlw8012.getCurrent();
hlw8012.setMode(MODE_VOLTAGE);
unblockingDelay(2000);
hlw8012.getVoltage();
// Calibrate using a 60W bulb (pure resistive) on a 230V line
hlw8012.expectedActivePower(60.0);
hlw8012.expectedVoltage(230.0);
hlw8012.expectedCurrent(60.0 / 230.0);
// Show corrected factors
Serial.print("[HLW] New current multiplier : "); Serial.println(hlw8012.getCurrentMultiplier());
Serial.print("[HLW] New voltage multiplier : "); Serial.println(hlw8012.getVoltageMultiplier());
Serial.print("[HLW] New power multiplier : "); Serial.println(hlw8012.getPowerMultiplier());
Serial.println();
}
void setup() {
// Init serial port and clean garbage
Serial.begin(SERIAL_BAUDRATE);
Serial.println();
Serial.println();
// Close the relay to switch on the load
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, HIGH);
// Initialize HLW8012
// void begin(unsigned char cf_pin, unsigned char cf1_pin, unsigned char sel_pin, unsigned char currentWhen = HIGH, bool use_interrupts = false, unsigned long pulse_timeout = PULSE_TIMEOUT);
// * cf_pin, cf1_pin and sel_pin are GPIOs to the HLW8012 IC
// * currentWhen is the value in sel_pin to select current sampling
// * set use_interrupts to false, we will have to call handle() in the main loop to do the sampling
// * set pulse_timeout to 500ms for a fast response but losing precision (that's ~24W precision :( )
hlw8012.begin(CF_PIN, CF1_PIN, SEL_PIN, CURRENT_MODE, false, 500000);
// These values are used to calculate current, voltage and power factors as per datasheet formula
// These are the nominal values for the Sonoff POW resistors:
// * The CURRENT_RESISTOR is the 1milliOhm copper-manganese resistor in series with the main line
// * The VOLTAGE_RESISTOR_UPSTREAM are the 5 470kOhm resistors in the voltage divider that feeds the V2P pin in the HLW8012
// * The VOLTAGE_RESISTOR_DOWNSTREAM is the 1kOhm resistor in the voltage divider that feeds the V2P pin in the HLW8012
hlw8012.setResistors(CURRENT_RESISTOR, VOLTAGE_RESISTOR_UPSTREAM, VOLTAGE_RESISTOR_DOWNSTREAM);
// Show default (as per datasheet) multipliers
Serial.print("[HLW] Default current multiplier : "); Serial.println(hlw8012.getCurrentMultiplier());
Serial.print("[HLW] Default voltage multiplier : "); Serial.println(hlw8012.getVoltageMultiplier());
Serial.print("[HLW] Default power multiplier : "); Serial.println(hlw8012.getPowerMultiplier());
Serial.println();
calibrate();
}
void loop() {
static unsigned long last = millis();
// This UPDATE_TIME should be at least twice the minimum time for the current or voltage
// signals to stabilize. Experimentally that's about 1 second.
if ((millis() - last) > UPDATE_TIME) {
last = millis();
Serial.print("[HLW] Active Power (W) : "); Serial.println(hlw8012.getActivePower());
Serial.print("[HLW] Voltage (V) : "); Serial.println(hlw8012.getVoltage());
Serial.print("[HLW] Current (A) : "); Serial.println(hlw8012.getCurrent());
Serial.print("[HLW] Apparent Power (VA) : "); Serial.println(hlw8012.getApparentPower());
Serial.print("[HLW] Power Factor (%) : "); Serial.println((int) (100 * hlw8012.getPowerFactor()));
Serial.println();
// When not using interrupts we have to manually switch to current or voltage monitor
// This means that every time we get into the conditional we only update one of them
// while the other will return the cached value.
hlw8012.toggleMode();
}
}
@@ -0,0 +1,46 @@
#include <Arduino.h>
#include <LowPower.h>
#include "HLW8012.h"
#define SERIAL_BAUDRATE 115200
// GPIOs
#define SEL_PIN 5
#define CF1_PIN 13
#define CF_PIN 14
// Set SEL_PIN to HIGH to sample current
// This is the case for Itead's Sonoff POW, where a
// the SEL_PIN drives a transistor that pulls down
// the SEL pin in the HLW8012 when closed
#define CURRENT_MODE HIGH
// Maximum pulse width, a 2Hz pulse means a precission of ~24W
#define MAX_PULSE_WIDTH 500000
HLW8012 hlw8012;
void setup() {
// Init serial port and clean garbage
Serial.begin(SERIAL_BAUDRATE);
Serial.println();
Serial.println();
// Initialize HLW8012
hlw8012.begin(CF_PIN, CF1_PIN, SEL_PIN, CURRENT_MODE, false, MAX_PULSE_WIDTH);
}
void loop() {
// Sleep for 20 seconds
for (unsigned short i = 0; i < 5; i++ ) {
LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);
}
unsigned long start = millis();
Serial.print("[HLW] Active Power (W) : "); Serial.println(hlw8012.getActivePower());
Serial.print("[HLW] Awake for (ms) : "); Serial.println(millis() - start);
}
@@ -0,0 +1,118 @@
#include <Arduino.h>
#include "HLW8012.h"
#define SERIAL_BAUDRATE 115200
// GPIOs
#define RELAY_PIN 12
#define SEL_PIN 5
#define CF1_PIN 13
#define CF_PIN 14
// Check values every 10 seconds
#define UPDATE_TIME 10000
// Set SEL_PIN to HIGH to sample current
// This is the case for Itead's Sonoff POW, where a
// the SEL_PIN drives a transistor that pulls down
// the SEL pin in the HLW8012 when closed
#define CURRENT_MODE HIGH
// These are the nominal values for the resistors in the circuit
#define CURRENT_RESISTOR 0.001
#define VOLTAGE_RESISTOR_UPSTREAM ( 5 * 470000 ) // Real: 2280k
#define VOLTAGE_RESISTOR_DOWNSTREAM ( 1000 ) // Real 1.009k
HLW8012 hlw8012;
// When using interrupts we have to call the library entry point
// whenever an interrupt is triggered
void hlw8012_cf1_interrupt() {
hlw8012.cf1_interrupt();
}
void hlw8012_cf_interrupt() {
hlw8012.cf_interrupt();
}
// Library expects an interrupt on both edges
void setInterrupts() {
attachInterrupt(CF1_PIN, hlw8012_cf1_interrupt, CHANGE);
attachInterrupt(CF_PIN, hlw8012_cf_interrupt, CHANGE);
}
void calibrate() {
// Let some time to register values
unsigned long timeout = millis();
while ((millis() - timeout) < 10000) {
delay(1);
}
// Calibrate using a 60W bulb (pure resistive) on a 230V line
hlw8012.expectedActivePower(60.0);
hlw8012.expectedVoltage(230.0);
hlw8012.expectedCurrent(60.0 / 230.0);
// Show corrected factors
Serial.print("[HLW] New current multiplier : "); Serial.println(hlw8012.getCurrentMultiplier());
Serial.print("[HLW] New voltage multiplier : "); Serial.println(hlw8012.getVoltageMultiplier());
Serial.print("[HLW] New power multiplier : "); Serial.println(hlw8012.getPowerMultiplier());
Serial.println();
}
void setup() {
// Init serial port and clean garbage
Serial.begin(SERIAL_BAUDRATE);
Serial.println();
Serial.println();
// Close the relay to switch on the load
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, HIGH);
// Initialize HLW8012
// void begin(unsigned char cf_pin, unsigned char cf1_pin, unsigned char sel_pin, unsigned char currentWhen = HIGH, bool use_interrupts = false, unsigned long pulse_timeout = PULSE_TIMEOUT);
// * cf_pin, cf1_pin and sel_pin are GPIOs to the HLW8012 IC
// * currentWhen is the value in sel_pin to select current sampling
// * set use_interrupts to true to use interrupts to monitor pulse widths
// * leave pulse_timeout to the default value, recommended when using interrupts
hlw8012.begin(CF_PIN, CF1_PIN, SEL_PIN, CURRENT_MODE, true);
// These values are used to calculate current, voltage and power factors as per datasheet formula
// These are the nominal values for the Sonoff POW resistors:
// * The CURRENT_RESISTOR is the 1milliOhm copper-manganese resistor in series with the main line
// * The VOLTAGE_RESISTOR_UPSTREAM are the 5 470kOhm resistors in the voltage divider that feeds the V2P pin in the HLW8012
// * The VOLTAGE_RESISTOR_DOWNSTREAM is the 1kOhm resistor in the voltage divider that feeds the V2P pin in the HLW8012
hlw8012.setResistors(CURRENT_RESISTOR, VOLTAGE_RESISTOR_UPSTREAM, VOLTAGE_RESISTOR_DOWNSTREAM);
// Show default (as per datasheet) multipliers
Serial.print("[HLW] Default current multiplier : "); Serial.println(hlw8012.getCurrentMultiplier());
Serial.print("[HLW] Default voltage multiplier : "); Serial.println(hlw8012.getVoltageMultiplier());
Serial.print("[HLW] Default power multiplier : "); Serial.println(hlw8012.getPowerMultiplier());
Serial.println();
setInterrupts();
calibrate();
}
void loop() {
static unsigned long last = millis();
// This UPDATE_TIME should be at least twice the interrupt timeout (2 second by default)
if ((millis() - last) > UPDATE_TIME) {
last = millis();
Serial.print("[HLW] Active Power (W) : "); Serial.println(hlw8012.getActivePower());
Serial.print("[HLW] Voltage (V) : "); Serial.println(hlw8012.getVoltage());
Serial.print("[HLW] Current (A) : "); Serial.println(hlw8012.getCurrent());
Serial.print("[HLW] Apparent Power (VA) : "); Serial.println(hlw8012.getApparentPower());
Serial.print("[HLW] Power Factor (%) : "); Serial.println((int) (100 * hlw8012.getPowerFactor()));
Serial.println();
}
}
+25
View File
@@ -0,0 +1,25 @@
{
"name": "HLW8012",
"keywords": "hlw8012,power,current,voltage",
"description": "HLW8012 library for Arduino and ESP8266",
"repository": {
"type": "git",
"url": "https://bitbucket.org/xoseperez/hlw8012.git"
},
"version": "1.0.0",
"license": "GPL-3.0",
"exclude": "tests",
"frameworks": "arduino",
"platforms": ["atmelavr", "espressif8266"],
"dependencies": [
],
"authors": {
"name": "Xose Perez",
"email": "xose.perez@gmail.com",
"url": "http://tinkerman.cat",
"maintainer": true
},
"examples": [
"examples/*/*.ino"
]
}
@@ -0,0 +1,9 @@
name=HLW8012
version=1.0.0
author=Xose Pérez <xose.perez@gmail.com>
maintainer=Xose Perez <xose.perez@gmail.com>
sentence=HLW8012 for Arduino / ESP8216
paragraph=HLW8012 power/current/voltage monitor IC library for Arduino and ESP8266. Use 2.x.x for ESP and 1.3 for AVR.
category=Sensors
url=https://bitbucket.org/xoseperez/hlw8012
architectures=*
+220
View File
@@ -0,0 +1,220 @@
/*
HLW8012 1.0.0
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#include "HLW8012.h"
void HLW8012::begin(
unsigned char cf_pin,
unsigned char cf1_pin,
unsigned char sel_pin,
unsigned char currentWhen,
bool use_interrupts,
unsigned long pulse_timeout
) {
_cf_pin = cf_pin;
_cf1_pin = cf1_pin;
_sel_pin = sel_pin;
_current_mode = currentWhen;
_use_interrupts = use_interrupts;
_pulse_timeout = pulse_timeout;
pinMode(_cf_pin, INPUT_PULLUP);
pinMode(_cf1_pin, INPUT_PULLUP);
pinMode(_sel_pin, OUTPUT);
_calculateDefaultMultipliers();
_mode = _current_mode;
digitalWrite(_sel_pin, _mode);
}
void HLW8012::setMode(hlw8012_mode_t mode) {
_mode = (mode == MODE_CURRENT) ? _current_mode : 1 - _current_mode;
digitalWrite(_sel_pin, _mode);
if (_use_interrupts) {
_last_cf1_interrupt = _first_cf1_interrupt = micros();
}
}
hlw8012_mode_t HLW8012::getMode() {
return (_mode == _current_mode) ? MODE_CURRENT : MODE_VOLTAGE;
}
hlw8012_mode_t HLW8012::toggleMode() {
hlw8012_mode_t new_mode = getMode() == MODE_CURRENT ? MODE_VOLTAGE : MODE_CURRENT;
setMode(new_mode);
return new_mode;
}
double HLW8012::getCurrent() {
// Power measurements are more sensitive to switch offs,
// so we first check if power is 0 to set _current to 0 too
if (_power == 0) {
_current_pulse_width = 0;
} else if (_use_interrupts) {
_checkCF1Signal();
} else if (_mode == _current_mode) {
_current_pulse_width = pulseIn(_cf1_pin, HIGH, _pulse_timeout);
}
_current = (_current_pulse_width > 0) ? _current_multiplier / _current_pulse_width / 2 : 0;
return _current;
}
unsigned int HLW8012::getVoltage() {
if (_use_interrupts) {
_checkCF1Signal();
} else if (_mode != _current_mode) {
_voltage_pulse_width = pulseIn(_cf1_pin, HIGH, _pulse_timeout);
}
_voltage = (_voltage_pulse_width > 0) ? _voltage_multiplier / _voltage_pulse_width / 2 : 0;
return _voltage;
}
unsigned int HLW8012::getActivePower() {
if (_use_interrupts) {
_checkCFSignal();
} else {
_power_pulse_width = pulseIn(_cf_pin, HIGH, _pulse_timeout);
}
_power = (_power_pulse_width > 0) ? _power_multiplier / _power_pulse_width / 2 : 0;
return _power;
}
unsigned int HLW8012::getApparentPower() {
double current = getCurrent();
unsigned int voltage = getVoltage();
return voltage * current;
}
unsigned int HLW8012::getReactivePower() {
unsigned int active = getActivePower();
unsigned int apparent = getApparentPower();
if (apparent > active) {
return sqrt(apparent * apparent - active * active);
} else {
return 0;
}
}
double HLW8012::getPowerFactor() {
unsigned int active = getActivePower();
unsigned int apparent = getApparentPower();
if (active > apparent) return 1;
if (apparent == 0) return 0;
return (double) active / apparent;
}
void HLW8012::expectedCurrent(double value) {
if (_current == 0) getCurrent();
if (_current > 0) _current_multiplier *= (value / _current);
}
void HLW8012::expectedVoltage(unsigned int value) {
if (_voltage == 0) getVoltage();
if (_voltage > 0) _voltage_multiplier *= ((double) value / _voltage);
}
void HLW8012::expectedActivePower(unsigned int value) {
if (_power == 0) getActivePower();
if (_power > 0) _power_multiplier *= ((double) value / _power);
}
void HLW8012::resetMultipliers() {
_calculateDefaultMultipliers();
}
void HLW8012::setResistors(double current, double voltage_upstream, double voltage_downstream) {
if (voltage_downstream > 0) {
_current_resistor = current;
_voltage_resistor = (voltage_upstream + voltage_downstream) / voltage_downstream;
_calculateDefaultMultipliers();
}
}
void HLW8012::cf_interrupt() {
unsigned long now = micros();
_power_pulse_width = now - _last_cf_interrupt;
_last_cf_interrupt = now;
}
void HLW8012::cf1_interrupt() {
unsigned long now = micros();
unsigned long pulse_width;
if ((now - _first_cf1_interrupt) > _pulse_timeout) {
if (_last_cf1_interrupt == _first_cf1_interrupt) {
pulse_width = 0;
} else {
pulse_width = now - _last_cf1_interrupt;
}
if (_mode == _current_mode) {
_current_pulse_width = pulse_width;
} else {
_voltage_pulse_width = pulse_width;
}
_mode = 1 - _mode;
digitalWrite(_sel_pin, _mode);
_first_cf1_interrupt = now;
}
_last_cf1_interrupt = now;
}
void HLW8012::_checkCFSignal() {
if ((micros() - _last_cf_interrupt) > _pulse_timeout) _power_pulse_width = 0;
}
void HLW8012::_checkCF1Signal() {
if ((micros() - _last_cf1_interrupt) > _pulse_timeout) {
if (_mode == _current_mode) {
_current_pulse_width = 0;
} else {
_voltage_pulse_width = 0;
}
toggleMode();
}
}
// These are the multipliers for current, voltage and power as per datasheet
// These values divided by output period (in useconds) give the actual value
// For power a frequency of 1Hz means around 12W
// For current a frequency of 1Hz means around 15mA
// For voltage a frequency of 1Hz means around 0.5V
void HLW8012::_calculateDefaultMultipliers() {
_current_multiplier = ( 1000000.0 * 512 * V_REF / _current_resistor / 24.0 / F_OSC );
_voltage_multiplier = ( 1000000.0 * 512 * V_REF * _voltage_resistor / 2.0 / F_OSC );
_power_multiplier = ( 1000000.0 * 128 * V_REF * V_REF * _voltage_resistor / _current_resistor / 48.0 / F_OSC );
}
+138
View File
@@ -0,0 +1,138 @@
/*
HLW8012 1.0.0
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HLW8012_h
#define HLW8012_h
#include <Arduino.h>
// Internal voltage reference value
#define V_REF 2.43
// The factor of a 1mOhm resistor
// as per recomended circuit in datasheet
// A 1mOhm resistor allows a ~30A max measurement
#define R_CURRENT 0.001
// This is the factor of a voltage divider of 6x 470K upstream and 1k downstream
// as per recomended circuit in datasheet
#define R_VOLTAGE 2821
// Frequency of the HLW8012 internal clock
#define F_OSC 3579000
// Minimum delay between selecting a mode and reading a sample
#define READING_INTERVAL 3000
// Maximum pulse with in microseconds
// If longer than this pulse width is reset to 0
// This value is purely experimental.
// Higher values allow for a better precission but reduce sampling rate
// and response speed to change
// Lower values increase sampling rate but reduce precission
// Values below 0.5s are not recommended since current and voltage output
// will have no time to stabilise
#define PULSE_TIMEOUT 2000000
// CF1 mode
typedef enum {
MODE_CURRENT,
MODE_VOLTAGE
} hlw8012_mode_t;
class HLW8012 {
public:
void cf_interrupt();
void cf1_interrupt();
void begin(
unsigned char cf_pin,
unsigned char cf1_pin,
unsigned char sel_pin,
unsigned char currentWhen = HIGH,
bool use_interrupts = true,
unsigned long pulse_timeout = PULSE_TIMEOUT);
void setMode(hlw8012_mode_t mode);
hlw8012_mode_t getMode();
hlw8012_mode_t toggleMode();
double getCurrent();
unsigned int getVoltage();
unsigned int getActivePower();
unsigned int getApparentPower();
double getPowerFactor();
unsigned int getReactivePower();
void setResistors(double current, double voltage_upstream, double voltage_downstream);
void expectedCurrent(double current);
void expectedVoltage(unsigned int current);
void expectedActivePower(unsigned int power);
double getCurrentMultiplier() { return _current_multiplier; };
double getVoltageMultiplier() { return _voltage_multiplier; };
double getPowerMultiplier() { return _power_multiplier; };
void setCurrentMultiplier(double current_multiplier) { _current_multiplier = current_multiplier; };
void setVoltageMultiplier(double voltage_multiplier) { _voltage_multiplier = voltage_multiplier; };
void setPowerMultiplier(double power_multiplier) { _power_multiplier = power_multiplier; };
void resetMultipliers();
private:
unsigned char _cf_pin;
unsigned char _cf1_pin;
unsigned char _sel_pin;
double _current_resistor = R_CURRENT;
double _voltage_resistor = R_VOLTAGE;
double _current_multiplier;
double _voltage_multiplier;
double _power_multiplier;
unsigned long _pulse_timeout = PULSE_TIMEOUT;
volatile unsigned long _voltage_pulse_width = 0;
volatile unsigned long _current_pulse_width = 0;
volatile unsigned long _power_pulse_width = 0;
double _current = 0;
unsigned int _voltage = 0;
unsigned int _power = 0;
unsigned char _current_mode = HIGH;
volatile unsigned char _mode;
bool _use_interrupts = true;
volatile unsigned long _last_cf_interrupt = 0;
volatile unsigned long _last_cf1_interrupt = 0;
volatile unsigned long _first_cf1_interrupt = 0;
void _checkCFSignal();
void _checkCF1Signal();
void _calculateDefaultMultipliers();
};
#endif
+1 -1
View File
@@ -151,7 +151,7 @@ void QEIx4::begin(int16_t pinA, int16_t pinB, int16_t pinI, uint8_t mode)
_pinI = pinI;
_counter = 0;
_bHasChanged = true;
_bHasChanged = false;
if (mode == 1)
_eventMask = QEIx4_1x_MASK;
+362
View File
@@ -0,0 +1,362 @@
// ---------------------------------------------------------------------------
// Created by Tim Eckel - teckel@leethost.com
// Copyright 2016 License: GNU GPL v3 http://www.gnu.org/licenses/gpl.html
//
// See "NewPing.h" for purpose, syntax, version history, links, and more.
// ---------------------------------------------------------------------------
#include "NewPing.h"
// ---------------------------------------------------------------------------
// NewPing constructor
// ---------------------------------------------------------------------------
NewPing::NewPing(uint8_t trigger_pin, uint8_t echo_pin, unsigned int max_cm_distance) {
#if DO_BITWISE == true
_triggerBit = digitalPinToBitMask(trigger_pin); // Get the port register bitmask for the trigger pin.
_echoBit = digitalPinToBitMask(echo_pin); // Get the port register bitmask for the echo pin.
_triggerOutput = portOutputRegister(digitalPinToPort(trigger_pin)); // Get the output port register for the trigger pin.
_echoInput = portInputRegister(digitalPinToPort(echo_pin)); // Get the input port register for the echo pin.
_triggerMode = (uint8_t *) portModeRegister(digitalPinToPort(trigger_pin)); // Get the port mode register for the trigger pin.
#else
_triggerPin = trigger_pin;
_echoPin = echo_pin;
#endif
set_max_distance(max_cm_distance); // Call function to set the max sensor distance.
#if (defined (__arm__) && defined (TEENSYDUINO)) || DO_BITWISE != true
pinMode(echo_pin, INPUT); // Set echo pin to input (on Teensy 3.x (ARM), pins default to disabled, at least one pinMode() is needed for GPIO mode).
pinMode(trigger_pin, OUTPUT); // Set trigger pin to output (on Teensy 3.x (ARM), pins default to disabled, at least one pinMode() is needed for GPIO mode).
#endif
#if defined (ARDUINO_AVR_YUN)
pinMode(echo_pin, INPUT); // Set echo pin to input for the Arduino Yun, not sure why it doesn't default this way.
#endif
#if ONE_PIN_ENABLED != true && DO_BITWISE == true
*_triggerMode |= _triggerBit; // Set trigger pin to output.
#endif
}
// ---------------------------------------------------------------------------
// Standard ping methods
// ---------------------------------------------------------------------------
unsigned int NewPing::ping(unsigned int max_cm_distance) {
if (max_cm_distance > 0) set_max_distance(max_cm_distance); // Call function to set a new max sensor distance.
if (!ping_trigger()) return NO_ECHO; // Trigger a ping, if it returns false, return NO_ECHO to the calling function.
#if URM37_ENABLED == true
#if DO_BITWISE == true
while (!(*_echoInput & _echoBit)) // Wait for the ping echo.
#else
while (!digitalRead(_echoPin)) // Wait for the ping echo.
#endif
if (micros() > _max_time) return NO_ECHO; // Stop the loop and return NO_ECHO (false) if we're beyond the set maximum distance.
#else
#if DO_BITWISE == true
while (*_echoInput & _echoBit) // Wait for the ping echo.
#else
while (digitalRead(_echoPin)) // Wait for the ping echo.
#endif
if (micros() > _max_time) return NO_ECHO; // Stop the loop and return NO_ECHO (false) if we're beyond the set maximum distance.
#endif
return (micros() - (_max_time - _maxEchoTime) - PING_OVERHEAD); // Calculate ping time, include overhead.
}
unsigned long NewPing::ping_cm(unsigned int max_cm_distance) {
unsigned long echoTime = NewPing::ping(max_cm_distance); // Calls the ping method and returns with the ping echo distance in uS.
#if ROUNDING_ENABLED == false
return (echoTime / US_ROUNDTRIP_CM); // Call the ping method and returns the distance in centimeters (no rounding).
#else
return NewPingConvert(echoTime, US_ROUNDTRIP_CM); // Convert uS to centimeters.
#endif
}
unsigned long NewPing::ping_in(unsigned int max_cm_distance) {
unsigned long echoTime = NewPing::ping(max_cm_distance); // Calls the ping method and returns with the ping echo distance in uS.
#if ROUNDING_ENABLED == false
return (echoTime / US_ROUNDTRIP_IN); // Call the ping method and returns the distance in inches (no rounding).
#else
return NewPingConvert(echoTime, US_ROUNDTRIP_IN); // Convert uS to inches.
#endif
}
unsigned long NewPing::ping_median(uint8_t it, unsigned int max_cm_distance) {
unsigned int uS[it], last;
uint8_t j, i = 0;
unsigned long t;
uS[0] = NO_ECHO;
while (i < it) {
t = micros(); // Start ping timestamp.
last = ping(max_cm_distance); // Send ping.
if (last != NO_ECHO) { // Ping in range, include as part of median.
if (i > 0) { // Don't start sort till second ping.
for (j = i; j > 0 && uS[j - 1] < last; j--) // Insertion sort loop.
uS[j] = uS[j - 1]; // Shift ping array to correct position for sort insertion.
} else j = 0; // First ping is sort starting point.
uS[j] = last; // Add last ping to array in sorted position.
i++; // Move to next ping.
} else it--; // Ping out of range, skip and don't include as part of median.
if (i < it && micros() - t < PING_MEDIAN_DELAY)
delay((PING_MEDIAN_DELAY + t - micros()) / 1000); // Millisecond delay between pings.
}
return (uS[it >> 1]); // Return the ping distance median.
}
// ---------------------------------------------------------------------------
// Standard and timer interrupt ping method support functions (not called directly)
// ---------------------------------------------------------------------------
boolean NewPing::ping_trigger() {
#if DO_BITWISE == true
#if ONE_PIN_ENABLED == true
*_triggerMode |= _triggerBit; // Set trigger pin to output.
#endif
*_triggerOutput &= ~_triggerBit; // Set the trigger pin low, should already be low, but this will make sure it is.
delayMicroseconds(4); // Wait for pin to go low.
*_triggerOutput |= _triggerBit; // Set trigger pin high, this tells the sensor to send out a ping.
delayMicroseconds(10); // Wait long enough for the sensor to realize the trigger pin is high. Sensor specs say to wait 10uS.
*_triggerOutput &= ~_triggerBit; // Set trigger pin back to low.
#if ONE_PIN_ENABLED == true
*_triggerMode &= ~_triggerBit; // Set trigger pin to input (when using one Arduino pin, this is technically setting the echo pin to input as both are tied to the same Arduino pin).
#endif
#if URM37_ENABLED == true
if (!(*_echoInput & _echoBit)) return false; // Previous ping hasn't finished, abort.
_max_time = micros() + _maxEchoTime + MAX_SENSOR_DELAY; // Maximum time we'll wait for ping to start (most sensors are <450uS, the SRF06 can take up to 34,300uS!)
while (*_echoInput & _echoBit) // Wait for ping to start.
if (micros() > _max_time) return false; // Took too long to start, abort.
#else
if (*_echoInput & _echoBit) return false; // Previous ping hasn't finished, abort.
_max_time = micros() + _maxEchoTime + MAX_SENSOR_DELAY; // Maximum time we'll wait for ping to start (most sensors are <450uS, the SRF06 can take up to 34,300uS!)
while (!(*_echoInput & _echoBit)) // Wait for ping to start.
if (micros() > _max_time) return false; // Took too long to start, abort.
#endif
#else
#if ONE_PIN_ENABLED == true
pinMode(_triggerPin, OUTPUT); // Set trigger pin to output.
#endif
digitalWrite(_triggerPin, LOW); // Set the trigger pin low, should already be low, but this will make sure it is.
delayMicroseconds(4); // Wait for pin to go low.
digitalWrite(_triggerPin, HIGH); // Set trigger pin high, this tells the sensor to send out a ping.
delayMicroseconds(10); // Wait long enough for the sensor to realize the trigger pin is high. Sensor specs say to wait 10uS.
digitalWrite(_triggerPin, LOW); // Set trigger pin back to low.
#if ONE_PIN_ENABLED == true
pinMode(_triggerPin, INPUT); // Set trigger pin to input (when using one Arduino pin, this is technically setting the echo pin to input as both are tied to the same Arduino pin).
#endif
#if URM37_ENABLED == true
if (!digitalRead(_echoPin)) return false; // Previous ping hasn't finished, abort.
_max_time = micros() + _maxEchoTime + MAX_SENSOR_DELAY; // Maximum time we'll wait for ping to start (most sensors are <450uS, the SRF06 can take up to 34,300uS!)
while (digitalRead(_echoPin)) // Wait for ping to start.
if (micros() > _max_time) return false; // Took too long to start, abort.
#else
if (digitalRead(_echoPin)) return false; // Previous ping hasn't finished, abort.
_max_time = micros() + _maxEchoTime + MAX_SENSOR_DELAY; // Maximum time we'll wait for ping to start (most sensors are <450uS, the SRF06 can take up to 34,300uS!)
while (!digitalRead(_echoPin)) // Wait for ping to start.
if (micros() > _max_time) return false; // Took too long to start, abort.
#endif
#endif
_max_time = micros() + _maxEchoTime; // Ping started, set the time-out.
return true; // Ping started successfully.
}
void NewPing::set_max_distance(unsigned int max_cm_distance) {
#if ROUNDING_ENABLED == false
_maxEchoTime = min(max_cm_distance + 1, (unsigned int) MAX_SENSOR_DISTANCE + 1) * US_ROUNDTRIP_CM; // Calculate the maximum distance in uS (no rounding).
#else
_maxEchoTime = min(max_cm_distance, (unsigned int) MAX_SENSOR_DISTANCE) * US_ROUNDTRIP_CM + (US_ROUNDTRIP_CM / 2); // Calculate the maximum distance in uS.
#endif
}
#if TIMER_ENABLED == true && DO_BITWISE == true
// ---------------------------------------------------------------------------
// Timer interrupt ping methods (won't work with non-AVR, ATmega128 and all ATtiny microcontrollers)
// ---------------------------------------------------------------------------
void NewPing::ping_timer(void (*userFunc)(void), unsigned int max_cm_distance) {
if (max_cm_distance > 0) set_max_distance(max_cm_distance); // Call function to set a new max sensor distance.
if (!ping_trigger()) return; // Trigger a ping, if it returns false, return without starting the echo timer.
timer_us(ECHO_TIMER_FREQ, userFunc); // Set ping echo timer check every ECHO_TIMER_FREQ uS.
}
boolean NewPing::check_timer() {
if (micros() > _max_time) { // Outside the time-out limit.
timer_stop(); // Disable timer interrupt
return false; // Cancel ping timer.
}
#if URM37_ENABLED == false
if (!(*_echoInput & _echoBit)) { // Ping echo received.
#else
if (*_echoInput & _echoBit) { // Ping echo received.
#endif
timer_stop(); // Disable timer interrupt
ping_result = (micros() - (_max_time - _maxEchoTime) - PING_TIMER_OVERHEAD); // Calculate ping time including overhead.
return true; // Return ping echo true.
}
return false; // Return false because there's no ping echo yet.
}
// ---------------------------------------------------------------------------
// Timer2/Timer4 interrupt methods (can be used for non-ultrasonic needs)
// ---------------------------------------------------------------------------
// Variables used for timer functions
void (*intFunc)();
void (*intFunc2)();
unsigned long _ms_cnt_reset;
volatile unsigned long _ms_cnt;
#if defined(__arm__) && defined(TEENSYDUINO)
IntervalTimer itimer;
#endif
void NewPing::timer_us(unsigned int frequency, void (*userFunc)(void)) {
intFunc = userFunc; // User's function to call when there's a timer event.
timer_setup(); // Configure the timer interrupt.
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
OCR4C = min((frequency>>2) - 1, 255); // Every count is 4uS, so divide by 4 (bitwise shift right 2) subtract one, then make sure we don't go over 255 limit.
TIMSK4 = (1<<TOIE4); // Enable Timer4 interrupt.
#elif defined (__arm__) && defined (TEENSYDUINO) // Timer for Teensy 3.x
itimer.begin(userFunc, frequency); // Really simple on the Teensy 3.x, calls userFunc every 'frequency' uS.
#else
OCR2A = min((frequency>>2) - 1, 255); // Every count is 4uS, so divide by 4 (bitwise shift right 2) subtract one, then make sure we don't go over 255 limit.
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 interrupt.
#endif
}
void NewPing::timer_ms(unsigned long frequency, void (*userFunc)(void)) {
intFunc = NewPing::timer_ms_cntdwn; // Timer events are sent here once every ms till user's frequency is reached.
intFunc2 = userFunc; // User's function to call when user's frequency is reached.
_ms_cnt = _ms_cnt_reset = frequency; // Current ms counter and reset value.
timer_setup(); // Configure the timer interrupt.
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
OCR4C = 249; // Every count is 4uS, so 1ms = 250 counts - 1.
TIMSK4 = (1<<TOIE4); // Enable Timer4 interrupt.
#elif defined (__arm__) && defined (TEENSYDUINO) // Timer for Teensy 3.x
itimer.begin(NewPing::timer_ms_cntdwn, 1000); // Set timer to 1ms (1000 uS).
#else
OCR2A = 249; // Every count is 4uS, so 1ms = 250 counts - 1.
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 interrupt.
#endif
}
void NewPing::timer_stop() { // Disable timer interrupt.
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
TIMSK4 = 0;
#elif defined (__arm__) && defined (TEENSYDUINO) // Timer for Teensy 3.x
itimer.end();
#else
TIMSK2 &= ~(1<<OCIE2A);
#endif
}
// ---------------------------------------------------------------------------
// Timer2/Timer4 interrupt method support functions (not called directly)
// ---------------------------------------------------------------------------
void NewPing::timer_setup() {
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
timer_stop(); // Disable Timer4 interrupt.
TCCR4A = TCCR4C = TCCR4D = TCCR4E = 0;
TCCR4B = (1<<CS42) | (1<<CS41) | (1<<CS40) | (1<<PSR4); // Set Timer4 prescaler to 64 (4uS/count, 4uS-1020uS range).
TIFR4 = (1<<TOV4);
TCNT4 = 0; // Reset Timer4 counter.
#elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__) || defined (__AVR_ATmega8535__) // Alternate timer commands for certain microcontrollers.
timer_stop(); // Disable Timer2 interrupt.
ASSR &= ~(1<<AS2); // Set clock, not pin.
TCCR2 = (1<<WGM21 | 1<<CS22); // Set Timer2 to CTC mode, prescaler to 64 (4uS/count, 4uS-1020uS range).
TCNT2 = 0; // Reset Timer2 counter.
#elif defined (__arm__) && defined (TEENSYDUINO)
timer_stop(); // Stop the timer.
#else
timer_stop(); // Disable Timer2 interrupt.
ASSR &= ~(1<<AS2); // Set clock, not pin.
TCCR2A = (1<<WGM21); // Set Timer2 to CTC mode.
TCCR2B = (1<<CS22); // Set Timer2 prescaler to 64 (4uS/count, 4uS-1020uS range).
TCNT2 = 0; // Reset Timer2 counter.
#endif
}
void NewPing::timer_ms_cntdwn() {
if (!_ms_cnt--) { // Count down till we reach zero.
intFunc2(); // Scheduled time reached, run the main timer event function.
_ms_cnt = _ms_cnt_reset; // Reset the ms timer.
}
}
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
ISR(TIMER4_OVF_vect) {
intFunc(); // Call wrapped function.
}
#elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__) || defined (__AVR_ATmega8535__) // Alternate timer commands for certain microcontrollers.
ISR(TIMER2_COMP_vect) {
intFunc(); // Call wrapped function.
}
#elif defined (__arm__)
// Do nothing...
#else
ISR(TIMER2_COMPA_vect) {
intFunc(); // Call wrapped function.
}
#endif
#endif
// ---------------------------------------------------------------------------
// Conversion methods (rounds result to nearest cm or inch).
// ---------------------------------------------------------------------------
unsigned int NewPing::convert_cm(unsigned int echoTime) {
#if ROUNDING_ENABLED == false
return (echoTime / US_ROUNDTRIP_CM); // Convert uS to centimeters (no rounding).
#else
return NewPingConvert(echoTime, US_ROUNDTRIP_CM); // Convert uS to centimeters.
#endif
}
unsigned int NewPing::convert_in(unsigned int echoTime) {
#if ROUNDING_ENABLED == false
return (echoTime / US_ROUNDTRIP_IN); // Convert uS to inches (no rounding).
#else
return NewPingConvert(echoTime, US_ROUNDTRIP_IN); // Convert uS to inches.
#endif
}
+245
View File
@@ -0,0 +1,245 @@
// ---------------------------------------------------------------------------
// NewPing Library - v1.8 - 07/30/2016
//
// AUTHOR/LICENSE:
// Created by Tim Eckel - teckel@leethost.com
// Copyright 2016 License: GNU GPL v3 http://www.gnu.org/licenses/gpl.html
//
// LINKS:
// Project home: https://bitbucket.org/teckel12/arduino-new-ping/wiki/Home
// Blog: http://arduino.cc/forum/index.php/topic,106043.0.html
//
// DISCLAIMER:
// This software is furnished "as is", without technical support, and with no
// warranty, express or implied, as to its usefulness for any purpose.
//
// BACKGROUND:
// When I first received an ultrasonic sensor I was not happy with how poorly
// it worked. Quickly I realized the problem wasn't the sensor, it was the
// available ping and ultrasonic libraries causing the problem. The NewPing
// library totally fixes these problems, adds many new features, and breaths
// new life into these very affordable distance sensors.
//
// FEATURES:
// * Works with many different ultrasonic sensors: SR04, SRF05, SRF06, DYP-ME007, URM37 & Parallax PING))).
// * Compatible with the entire Arduino line-up (and clones), Teensy family (including $19 96Mhz 32 bit Teensy 3.2) and non-AVR microcontrollers.
// * Interface with all but the SRF06 sensor using only one Arduino pin.
// * Doesn't lag for a full second if no ping/echo is received.
// * Ping sensors consistently and reliably at up to 30 times per second.
// * Timer interrupt method for event-driven sketches.
// * Built-in digital filter method ping_median() for easy error correction.
// * Uses port registers for a faster pin interface and smaller code size.
// * Allows you to set a maximum distance where pings beyond that distance are read as no ping "clear".
// * Ease of using multiple sensors (example sketch with 15 sensors).
// * More accurate distance calculation (cm, inches & uS).
// * Doesn't use pulseIn, which is slow and gives incorrect results with some ultrasonic sensor models.
// * Actively developed with features being added and bugs/issues addressed.
//
// CONSTRUCTOR:
// NewPing sonar(trigger_pin, echo_pin [, max_cm_distance])
// trigger_pin & echo_pin - Arduino pins connected to sensor trigger and echo.
// NOTE: To use the same Arduino pin for trigger and echo, specify the same pin for both values.
// max_cm_distance - [Optional] Maximum distance you wish to sense. Default=500cm.
//
// METHODS:
// sonar.ping([max_cm_distance]) - Send a ping and get the echo time (in microseconds) as a result. [max_cm_distance] allows you to optionally set a new max distance.
// sonar.ping_in([max_cm_distance]) - Send a ping and get the distance in whole inches. [max_cm_distance] allows you to optionally set a new max distance.
// sonar.ping_cm([max_cm_distance]) - Send a ping and get the distance in whole centimeters. [max_cm_distance] allows you to optionally set a new max distance.
// sonar.ping_median(iterations [, max_cm_distance]) - Do multiple pings (default=5), discard out of range pings and return median in microseconds. [max_cm_distance] allows you to optionally set a new max distance.
// NewPing::convert_in(echoTime) - Convert echoTime from microseconds to inches (rounds to nearest inch).
// NewPing::convert_cm(echoTime) - Convert echoTime from microseconds to centimeters (rounds to nearest cm).
// sonar.ping_timer(function [, max_cm_distance]) - Send a ping and call function to test if ping is complete. [max_cm_distance] allows you to optionally set a new max distance.
// sonar.check_timer() - Check if ping has returned within the set distance limit.
// NewPing::timer_us(frequency, function) - Call function every frequency microseconds.
// NewPing::timer_ms(frequency, function) - Call function every frequency milliseconds.
// NewPing::timer_stop() - Stop the timer.
//
// HISTORY:
// 07/30/2016 v1.8 - Added support for non-AVR microcontrollers. For non-AVR
// microcontrollers, advanced ping_timer() timer methods are disabled due to
// inconsistencies or no support at all between platforms. However, standard
// ping methods are all supported. Added new optional variable to ping(),
// ping_in(), ping_cm(), ping_median(), and ping_timer() methods which allows
// you to set a new maximum distance for each ping. Added support for the
// ATmega16, ATmega32 and ATmega8535 microcontrollers. Changed convert_cm()
// and convert_in() methods to static members. You can now call them without
// an object. For example: cm = NewPing::convert_cm(distance);
//
// 09/29/2015 v1.7 - Removed support for the Arduino Due and Zero because
// they're both 3.3 volt boards and are not 5 volt tolerant while the HC-SR04
// is a 5 volt sensor. Also, the Due and Zero don't support pin manipulation
// compatibility via port registers which can be done (see the Teensy 3.2).
//
// 06/17/2014 v1.6 - Corrected delay between pings when using ping_median()
// method. Added support for the URM37 sensor (must change URM37_ENABLED from
// false to true). Added support for Arduino microcontrollers like the $20
// 32 bit ARM Cortex-M4 based Teensy 3.2. Added automatic support for the
// Atmel ATtiny family of microcontrollers. Added timer support for the
// ATmega8 microcontroller. Rounding disabled by default, reduces compiled
// code size (can be turned on with ROUNDING_ENABLED switch). Added
// TIMER_ENABLED switch to get around compile-time "__vector_7" errors when
// using the Tone library, or you can use the toneAC, NewTone or
// TimerFreeTone libraries: https://bitbucket.org/teckel12/arduino-toneac/
// Other speed and compiled size optimizations.
//
// 08/15/2012 v1.5 - Added ping_median() method which does a user specified
// number of pings (default=5) and returns the median ping in microseconds
// (out of range pings ignored). This is a very effective digital filter.
// Optimized for smaller compiled size (even smaller than sketches that
// don't use a library).
//
// 07/14/2012 v1.4 - Added support for the Parallax PING))) sensor. Interface
// with all but the SRF06 sensor using only one Arduino pin. You can also
// interface with the SRF06 using one pin if you install a 0.1uf capacitor
// on the trigger and echo pins of the sensor then tie the trigger pin to
// the Arduino pin (doesn't work with Teensy). To use the same Arduino pin
// for trigger and echo, specify the same pin for both values. Various bug
// fixes.
//
// 06/08/2012 v1.3 - Big feature addition, event-driven ping! Uses Timer2
// interrupt, so be mindful of PWM or timing conflicts messing with Timer2
// may cause (namely PWM on pins 3 & 11 on Arduino, PWM on pins 9 and 10 on
// Mega, and Tone library). Simple to use timer interrupt functions you can
// use in your sketches totally unrelated to ultrasonic sensors (don't use if
// you're also using NewPing's ping_timer because both use Timer2 interrupts).
// Loop counting ping method deleted in favor of timing ping method after
// inconsistent results kept surfacing with the loop timing ping method.
// Conversion to cm and inches now rounds to the nearest cm or inch. Code
// optimized to save program space and fixed a couple minor bugs here and
// there. Many new comments added as well as line spacing to group code
// sections for better source readability.
//
// 05/25/2012 v1.2 - Lots of code clean-up thanks to Arduino Forum members.
// Rebuilt the ping timing code from scratch, ditched the pulseIn code as it
// doesn't give correct results (at least with ping sensors). The NewPing
// library is now VERY accurate and the code was simplified as a bonus.
// Smaller and faster code as well. Fixed some issues with very close ping
// results when converting to inches. All functions now return 0 only when
// there's no ping echo (out of range) and a positive value for a successful
// ping. This can effectively be used to detect if something is out of range
// or in-range and at what distance. Now compatible with Arduino 0023.
//
// 05/16/2012 v1.1 - Changed all I/O functions to use low-level port registers
// for ultra-fast and lean code (saves from 174 to 394 bytes). Tested on both
// the Arduino Uno and Teensy 2.0 but should work on all Arduino-based
// platforms because it calls standard functions to retrieve port registers
// and bit masks. Also made a couple minor fixes to defines.
//
// 05/15/2012 v1.0 - Initial release.
// ---------------------------------------------------------------------------
#ifndef NewPing_h
#define NewPing_h
#if defined (ARDUINO) && ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#include <pins_arduino.h>
#endif
#if defined (__AVR__)
#include <avr/io.h>
#include <avr/interrupt.h>
#endif
// Shouldn't need to change these values unless you have a specific need to do so.
#define MAX_SENSOR_DISTANCE 500 // Maximum sensor distance can be as high as 500cm, no reason to wait for ping longer than sound takes to travel this distance and back. Default=500
#define US_ROUNDTRIP_CM 57 // Microseconds (uS) it takes sound to travel round-trip 1cm (2cm total), uses integer to save compiled code space. Default=57
#define US_ROUNDTRIP_IN 146 // Microseconds (uS) it takes sound to travel round-trip 1 inch (2 inches total), uses integer to save compiled code space. Defalult=146
#define ONE_PIN_ENABLED true // Set to "false" to disable one pin mode which saves around 14-26 bytes of binary size. Default=true
#define ROUNDING_ENABLED false // Set to "true" to enable distance rounding which also adds 64 bytes to binary size. Default=false
#define URM37_ENABLED false // Set to "true" to enable support for the URM37 sensor in PWM mode. Default=false
#define TIMER_ENABLED true // Set to "false" to disable the timer ISR (if getting "__vector_7" compile errors set this to false). Default=true
// Probably shouldn't change these values unless you really know what you're doing.
#define NO_ECHO 0 // Value returned if there's no ping echo within the specified MAX_SENSOR_DISTANCE or max_cm_distance. Default=0
#define MAX_SENSOR_DELAY 5800 // Maximum uS it takes for sensor to start the ping. Default=5800
#define ECHO_TIMER_FREQ 24 // Frequency to check for a ping echo (every 24uS is about 0.4cm accuracy). Default=24
#define PING_MEDIAN_DELAY 29000 // Microsecond delay between pings in the ping_median method. Default=29000
#define PING_OVERHEAD 5 // Ping overhead in microseconds (uS). Default=5
#define PING_TIMER_OVERHEAD 13 // Ping timer overhead in microseconds (uS). Default=13
#if URM37_ENABLED == true
#undef US_ROUNDTRIP_CM
#undef US_ROUNDTRIP_IN
#define US_ROUNDTRIP_CM 50 // Every 50uS PWM signal is low indicates 1cm distance. Default=50
#define US_ROUNDTRIP_IN 127 // If 50uS is 1cm, 1 inch would be 127uS (50 x 2.54 = 127). Default=127
#endif
// Conversion from uS to distance (round result to nearest cm or inch).
#define NewPingConvert(echoTime, conversionFactor) (max(((unsigned int)echoTime + conversionFactor / 2) / conversionFactor, (echoTime ? 1 : 0)))
// Detect non-AVR microcontrollers (Teensy 3.x, Arduino DUE, etc.) and don't use port registers or timer interrupts as required.
#if (defined (__arm__) && defined (TEENSYDUINO))
#undef PING_OVERHEAD
#define PING_OVERHEAD 1
#undef PING_TIMER_OVERHEAD
#define PING_TIMER_OVERHEAD 1
#define DO_BITWISE true
#elif !defined (__AVR__)
#undef PING_OVERHEAD
#define PING_OVERHEAD 1
#undef PING_TIMER_OVERHEAD
#define PING_TIMER_OVERHEAD 1
#undef TIMER_ENABLED
#define TIMER_ENABLED false
#define DO_BITWISE false
#else
#define DO_BITWISE true
#endif
// Disable the timer interrupts when using ATmega128 and all ATtiny microcontrollers.
#if defined (__AVR_ATmega128__) || defined (__AVR_ATtiny24__) || defined (__AVR_ATtiny44__) || defined (__AVR_ATtiny84__) || defined (__AVR_ATtiny25__) || defined (__AVR_ATtiny45__) || defined (__AVR_ATtiny85__) || defined (__AVR_ATtiny261__) || defined (__AVR_ATtiny461__) || defined (__AVR_ATtiny861__) || defined (__AVR_ATtiny43U__)
#undef TIMER_ENABLED
#define TIMER_ENABLED false
#endif
// Define timers when using ATmega8, ATmega16, ATmega32 and ATmega8535 microcontrollers.
#if defined (__AVR_ATmega8__) || defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__) || defined (__AVR_ATmega8535__)
#define OCR2A OCR2
#define TIMSK2 TIMSK
#define OCIE2A OCIE2
#endif
class NewPing {
public:
NewPing(uint8_t trigger_pin, uint8_t echo_pin, unsigned int max_cm_distance = MAX_SENSOR_DISTANCE);
unsigned int ping(unsigned int max_cm_distance = 0);
unsigned long ping_cm(unsigned int max_cm_distance = 0);
unsigned long ping_in(unsigned int max_cm_distance = 0);
unsigned long ping_median(uint8_t it = 5, unsigned int max_cm_distance = 0);
static unsigned int convert_cm(unsigned int echoTime);
static unsigned int convert_in(unsigned int echoTime);
#if TIMER_ENABLED == true
void ping_timer(void (*userFunc)(void), unsigned int max_cm_distance = 0);
boolean check_timer();
unsigned long ping_result;
static void timer_us(unsigned int frequency, void (*userFunc)(void));
static void timer_ms(unsigned long frequency, void (*userFunc)(void));
static void timer_stop();
#endif
private:
boolean ping_trigger();
void set_max_distance(unsigned int max_cm_distance);
#if TIMER_ENABLED == true
boolean ping_trigger_timer(unsigned int trigger_delay);
boolean ping_wait_timer();
static void timer_setup();
static void timer_ms_cntdwn();
#endif
#if DO_BITWISE == true
uint8_t _triggerBit;
uint8_t _echoBit;
volatile uint8_t *_triggerOutput;
volatile uint8_t *_echoInput;
volatile uint8_t *_triggerMode;
#else
uint8_t _triggerPin;
uint8_t _echoPin;
#endif
unsigned int _maxEchoTime;
unsigned long _max_time;
};
#endif
+75
View File
@@ -0,0 +1,75 @@
// ---------------------------------------------------------------------------
// This example code was used to successfully communicate with 15 ultrasonic sensors. You can adjust
// the number of sensors in your project by changing SONAR_NUM and the number of NewPing objects in the
// "sonar" array. You also need to change the pins for each sensor for the NewPing objects. Each sensor
// is pinged at 33ms intervals. So, one cycle of all sensors takes 495ms (33 * 15 = 495ms). The results
// are sent to the "oneSensorCycle" function which currently just displays the distance data. Your project
// would normally process the sensor results in this function (for example, decide if a robot needs to
// turn and call the turn function). Keep in mind this example is event-driven. Your complete sketch needs
// to be written so there's no "delay" commands and the loop() cycles at faster than a 33ms rate. If other
// processes take longer than 33ms, you'll need to increase PING_INTERVAL so it doesn't get behind.
// ---------------------------------------------------------------------------
#include <NewPing.h>
#define SONAR_NUM 15 // Number of sensors.
#define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.
#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).
unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor.
unsigned int cm[SONAR_NUM]; // Where the ping distances are stored.
uint8_t currentSensor = 0; // Keeps track of which sensor is active.
NewPing sonar[SONAR_NUM] = { // Sensor object array.
NewPing(41, 42, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
NewPing(43, 44, MAX_DISTANCE),
NewPing(45, 20, MAX_DISTANCE),
NewPing(21, 22, MAX_DISTANCE),
NewPing(23, 24, MAX_DISTANCE),
NewPing(25, 26, MAX_DISTANCE),
NewPing(27, 28, MAX_DISTANCE),
NewPing(29, 30, MAX_DISTANCE),
NewPing(31, 32, MAX_DISTANCE),
NewPing(34, 33, MAX_DISTANCE),
NewPing(35, 36, MAX_DISTANCE),
NewPing(37, 38, MAX_DISTANCE),
NewPing(39, 40, MAX_DISTANCE),
NewPing(50, 51, MAX_DISTANCE),
NewPing(52, 53, MAX_DISTANCE)
};
void setup() {
Serial.begin(115200);
pingTimer[0] = millis() + 75; // First ping starts at 75ms, gives time for the Arduino to chill before starting.
for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor.
pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}
void loop() {
for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors.
if (millis() >= pingTimer[i]) { // Is it this sensor's time to ping?
pingTimer[i] += PING_INTERVAL * SONAR_NUM; // Set next time this sensor will be pinged.
if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
sonar[currentSensor].timer_stop(); // Make sure previous timer is canceled before starting a new ping (insurance).
currentSensor = i; // Sensor being accessed.
cm[currentSensor] = 0; // Make distance zero in case there's no ping echo for this sensor.
sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).
}
}
// Other code that *DOESN'T* analyze ping results can go here.
}
void echoCheck() { // If ping received, set the sensor distance to array.
if (sonar[currentSensor].check_timer())
cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
}
void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.
// The following code would be replaced with your code that does something with the ping results.
for (uint8_t i = 0; i < SONAR_NUM; i++) {
Serial.print(i);
Serial.print("=");
Serial.print(cm[i]);
Serial.print("cm ");
}
Serial.println();
}
@@ -0,0 +1,46 @@
// ---------------------------------------------------------------------------
// This example shows how to use NewPing's ping_timer method which uses the Timer2 interrupt to get the
// ping time. The advantage of using this method over the standard ping method is that it permits a more
// event-driven sketch which allows you to appear to do two things at once. An example would be to ping
// an ultrasonic sensor for a possible collision while at the same time navigating. This allows a
// properly developed sketch to multitask. Be aware that because the ping_timer method uses Timer2,
// other features or libraries that also use Timer2 would be effected. For example, the PWM function on
// pins 3 & 11 on Arduino Uno (pins 9 and 11 on Arduino Mega) and the Tone library. Note, only the PWM
// functionality of the pins is lost (as they use Timer2 to do PWM), the pins are still available to use.
// NOTE: For Teensy/Leonardo (ATmega32U4) the library uses Timer4 instead of Timer2.
// ---------------------------------------------------------------------------
#include <NewPing.h>
#define TRIGGER_PIN 12 // Arduino pin tied to trigger pin on ping sensor.
#define ECHO_PIN 11 // Arduino pin tied to echo pin on ping sensor.
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
unsigned int pingSpeed = 50; // How frequently are we going to send out a ping (in milliseconds). 50ms would be 20 times a second.
unsigned long pingTimer; // Holds the next ping time.
void setup() {
Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
pingTimer = millis(); // Start now.
}
void loop() {
// Notice how there's no delays in this sketch to allow you to do other processing in-line while doing distance pings.
if (millis() >= pingTimer) { // pingSpeed milliseconds since last ping, do another ping.
pingTimer += pingSpeed; // Set the next ping time.
sonar.ping_timer(echoCheck); // Send out the ping, calls "echoCheck" function every 24uS where you can check the ping status.
}
// Do other stuff here, really. Think of it as multi-tasking.
}
void echoCheck() { // Timer2 interrupt calls this function every 24uS where you can check the ping status.
// Don't do anything here!
if (sonar.check_timer()) { // This is how you check to see if the ping was received.
// Here's where you can add code.
Serial.print("Ping: ");
Serial.print(sonar.ping_result / US_ROUNDTRIP_CM); // Ping returned, uS result in ping_result, convert to cm with US_ROUNDTRIP_CM.
Serial.println("cm");
}
// Don't do anything here!
}
+22
View File
@@ -0,0 +1,22 @@
// ---------------------------------------------------------------------------
// Example NewPing library sketch that does a ping about 20 times per second.
// ---------------------------------------------------------------------------
#include <NewPing.h>
#define TRIGGER_PIN 12 // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN 11 // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
void setup() {
Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
}
void loop() {
delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
Serial.print("Ping: ");
Serial.print(sonar.ping_cm()); // Send ping, get distance in cm and print result (0 = outside set distance range)
Serial.println("cm");
}
+25
View File
@@ -0,0 +1,25 @@
// ---------------------------------------------------------------------------
// While the NewPing library's primary goal is to interface with ultrasonic sensors, interfacing with
// the Timer2 interrupt was a result of creating an interrupt-based ping method. Since these Timer2
// interrupt methods were built, the library may as well provide the functionality to use these methods
// in your sketches. This shows how simple it is (no ultrasonic sensor required). Keep in mind that
// these methods use Timer2, as does NewPing's ping_timer method for using ultrasonic sensors. You
// can't use ping_timer at the same time you're using timer_ms or timer_us as all use the same timer.
// ---------------------------------------------------------------------------
#include <NewPing.h>
#define LED_PIN 13 // Pin with LED attached.
void setup() {
pinMode(LED_PIN, OUTPUT);
NewPing::timer_ms(500, toggleLED); // Create a Timer2 interrupt that calls toggleLED in your sketch once every 500 milliseconds.
}
void loop() {
// Do anything here, the Timer2 interrupt will take care of the flashing LED without your intervention.
}
void toggleLED() {
digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Toggle the LED.
}
+29
View File
@@ -0,0 +1,29 @@
###################################
# Syntax Coloring Map For NewPing
###################################
###################################
# Datatypes (KEYWORD1)
###################################
NewPing KEYWORD1
###################################
# Methods and Functions (KEYWORD2)
###################################
ping KEYWORD2
ping_in KEYWORD2
ping_cm KEYWORD2
ping_median KEYWORD2
ping_timer KEYWORD2
check_timer KEYWORD2
timer_us KEYWORD2
timer_ms KEYWORD2
timer_stop KEYWORD2
convert_in KEYWORD2
convert_cm KEYWORD2
###################################
# Constants (LITERAL1)
###################################
+2 -1
View File
@@ -27,8 +27,9 @@
#endif
// MQTT_KEEPALIVE : keepAlive interval in Seconds
// Keepalive timeout for default MQTT Broker is 10s
#ifndef MQTT_KEEPALIVE
#define MQTT_KEEPALIVE 15
#define MQTT_KEEPALIVE 10
#endif
// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
+118 -41
View File
@@ -5,6 +5,20 @@
# http://docs.platformio.org/en/stable/projectconf.html
#
###########################################################################################
# You can uncomment or add here Your favorite environment you want to work on at the moment
# (uncomment only one !)
###########################################################################################
[platformio]
#env_default = esp32dev
#env_default = dev_ESP8266_4096
#env_default = normal_ESP8266_1024
#env_default = normal_ESP8266_4096
# ..etc
#minimal version for esps with 512K or less flash (only has minimal plugin set)
; [env:mini_512]
; platform = ${common.platform}
@@ -39,9 +53,15 @@ platform = espressif8266@1.5.0
[core_2_4_0]
platform = espressif8266@1.6.0
[core_2_4_1]
platform = espressif8266@1.7.0
[core_staged]
platform = https://github.com/platformio/platform-espressif8266.git#feature/stage
[core_esp32]
#platform = espressif32@0.12.0
platform = https://github.com/platformio/platform-espressif32.git#feature/stage
platform = espressif32@0.12.0
#platform = https://github.com/platformio/platform-espressif32.git#feature/stage
build_flags = -D BUILD_GIT='"${env.TRAVIS_TAG}"'
lib_ignore = ESPeasySoftwareSerial, EspESPeasySoftwareSerial, AS_BH1750, ESP8266WiFi, ESP8266Ping, ESP8266WebServer, ESP8266HTTPUpdateServer, ESP8266mDNS, IRremoteESP8266, ESPEasy_ESP8266Ping, SerialSensors
lib_deps = ESP32WebServer
@@ -49,13 +69,24 @@ lib_deps = ESP32WebServer
[common]
build_flags = -D BUILD_GIT='"${env.TRAVIS_TAG}"' ; ${compiler_warnings.build_flags}
-D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
-D NDEBUG
lib_deps = ""
lib_ignore = ESP32_ping, ESP32WebServer
lib_ldf_mode = chain
upload_speed = 460800
framework = arduino
board = esp12e
platform = ${core_2_3_0.platform}
platform = ${core_2_4_1.platform}
[normal]
platform = ${common.platform}
[testing]
platform = ${core_2_4_1.platform}
[dev]
platform = ${core_2_4_1.platform}
[esp8266_1M]
@@ -71,6 +102,13 @@ build_flags = ${esp8266_1M.build_flags} -DESP8285
board = esp01_1m
board_flash_mode = ${esp8266_1M.board_flash_mode}
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld
platform = ${core_2_4_1.platform}
[Sonoff_8285]
board_flash_mode = ${esp8285_1M.board_flash_mode}
board = ${esp8285_1M.board}
build_flags = ${esp8285_1M.build_flags}
platform = ${core_2_4_1.platform}
[espWroom2M]
board_flash_mode = dout
@@ -95,6 +133,8 @@ lib_ignore = ${core_esp32.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
framework = ${common.framework}
upload_speed = ${common.upload_speed}
#upload_port = 192.168.0.100 # uncoment and change IP to own to use OTA
# directly from Platformio, Atom ..
### NORMAL (STABLE) ######################################################################
# normal version with stable plugins #
@@ -156,7 +196,7 @@ build_flags = ${esp8266_4M.build_flags}
# TEST: 1024k version ----------------------------
[env:test_ESP8266_1024]
platform = ${common.platform}
platform = ${testing.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
@@ -168,7 +208,7 @@ build_flags = ${esp8266_1M.build_flags} -D PLUGIN_BUILD_TESTING
# TEST: 1024k for esp8285 ------------------------
[env:test_ESP8285_1024]
platform = ${common.platform}
platform = ${testing.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
@@ -180,7 +220,7 @@ build_flags = ${esp8285_1M.build_flags} -D PLUGIN_BUILD_TESTING
# TEST: 2048k version ----------------------------
[env:test_WROOM02_2048]
platform = ${common.platform}
platform = ${testing.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
@@ -192,7 +232,7 @@ build_flags = ${espWroom2M.build_flags} -D PLUGIN_BUILD_TESTING
# TEST: 4096k version ----------------------------
[env:test_ESP8266_4096]
platform = ${common.platform}
platform = ${testing.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
@@ -204,7 +244,7 @@ build_flags = ${esp8266_4M.build_flags} -D PLUGIN_BUILD_TESTING
# TEST: 4096k version + FEATURE_ADC_VCC ----------
[env:test_ESP8266_4096_VCC]
platform = ${common.platform}
platform = ${testing.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
@@ -222,7 +262,7 @@ build_flags = ${esp8266_4M.build_flags} -D PLUGIN_BUILD_TESTING -D FEATURE_
# DEV : 1024k version ----------------------------
[env:dev_ESP8266_1024]
platform = ${common.platform}
platform = ${dev.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
@@ -234,7 +274,7 @@ build_flags = ${esp8266_1M.build_flags} -D PLUGIN_BUILD_DEV
# DEV: 1024k for esp8285 -------------------------
[env:dev_ESP8285_1024]
platform = ${common.platform}
platform = ${dev.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
@@ -246,7 +286,7 @@ build_flags = ${esp8285_1M.build_flags} -D PLUGIN_BUILD_DEV
# DEV: 2048k version -----------------------------
[env:dev_WROOM02_2048]
platform = ${common.platform}
platform = ${dev.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
@@ -258,7 +298,7 @@ build_flags = ${espWroom2M.build_flags} -D PLUGIN_BUILD_DEV
# DEV : 4096k version ----------------------------
[env:dev_ESP8266_4096]
platform = ${common.platform}
platform = ${dev.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
@@ -276,7 +316,7 @@ build_flags = ${esp8266_4M.build_flags} -D PLUGIN_BUILD_DEV
# DEV+PUYA : 1024k version -----------------------
[env:dev_ESP8266PUYA_1024]
platform = ${common.platform}
platform = ${dev.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
@@ -288,7 +328,7 @@ build_flags = ${esp8266_1M.build_flags} -D PLUGIN_BUILD_DEV -D FLASH_QUIRK_
# DEV+PUYA : 1024k version + FEATURE_ADC_VCC -----
[env:dev_ESP8266PUYA_1024_VCC]
platform = ${common.platform}
platform = ${dev.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
@@ -311,9 +351,9 @@ build_flags = ${esp8266_1M.build_flags} -D PLUGIN_BUILD_DEV -D FLASH_QUIRK_
#[env:hard_SONOFF_BASIC]
#upload_speed = ${common.upload_speed}
#framework = ${common.framework}
#platform = ${common.platform}
#platform = ${Sonoff.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${Sonoff.board_flash_mode}
#board = ${Sonoff.board}
@@ -323,9 +363,9 @@ lib_ignore = ${common.lib_ignore}
#[env:hard_SONOFF_TH10]
#upload_speed = ${common.upload_speed}
#framework = ${common.framework}
#platform = ${common.platform}
#platform = ${Sonoff.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${Sonoff.board_flash_mode}
#board = ${Sonoff.board}
@@ -335,33 +375,57 @@ lib_ignore = ${common.lib_ignore}
#[env:hard_SONOFF_TH16]
#upload_speed = ${common.upload_speed}
#framework = ${common.framework}
#platform = ${common.platform}
#platform = ${Sonoff.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${Sonoff.board_flash_mode}
#board = ${Sonoff.board}
#build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_TH16
# ITEAD / SONOFF POW version --------------------
#[env:hard_SONOFF_POW]
# Sonoff Pow (ESP8266 - HLW8012)
# GPIO00 Button
# GPIO05 HLW8012 Sel output
# GPIO12 Red Led and Relay (0 = Off, 1 = On)
# GPIO13 HLW8012 CF1 voltage / current
# GPIO14 HLW8012 CF power
# GPIO15 Blue Led (0 = On, 1 = Off)
[env:hard_SONOFF_POW]
upload_speed = ${common.upload_speed}
framework = ${common.framework}
platform = ${Sonoff.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
board_flash_mode = ${Sonoff.board_flash_mode}
board = ${Sonoff.board}
build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_POW
# Sonoff Pow R2 (ESP8285 - CSE7766)
# GPIO00 Button
# GPIO01 Serial RXD 4800 baud 8E1 CSE7766 energy sensor
# GPIO03 Serial TXD
# GPIO12 Red Led and Relay (0 = Off, 1 = On)
# GPIO13 Blue Led (0 = On, 1 = Off)
#[env:hard_SONOFF_POW_R2]
#upload_speed = ${common.upload_speed}
#framework = ${common.framework}
#platform = ${common.platform}
#platform = ${Sonoff.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${Sonoff.board_flash_mode}
#board = ${Sonoff.board}
#build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_POW
#board_flash_mode = ${Sonoff_8285.board_flash_mode}
#board = ${Sonoff_8285.board}
#build_flags = ${Sonoff_8285.build_flags} -D PLUGIN_SET_SONOFF_POW_R2
# ITEAD / SONOFF S20 version --------------------
#[env:hard_SONOFF_S20]
#upload_speed = ${common.upload_speed}
#framework = ${common.framework}
#platform = ${common.platform}
#platform = ${Sonoff.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${Sonoff.board_flash_mode}
#board = ${Sonoff.board}
@@ -371,9 +435,9 @@ lib_ignore = ${common.lib_ignore}
#[env:hard_SONOFF_4CH]
#upload_speed = ${common.upload_speed}
#framework = ${common.framework}
#platform = ${common.platform}
#platform = ${Sonoff.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${Sonoff.board_flash_mode}
#board = ${Sonoff.board}
@@ -383,9 +447,9 @@ lib_ignore = ${common.lib_ignore}
#[env:hard_SONOFF_TOUCH]
#upload_speed = ${common.upload_speed}
#framework = ${common.framework}
#platform = ${common.platform}
#platform = ${Sonoff.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${Sonoff.board_flash_mode}
#board = ${Sonoff.board}
@@ -401,7 +465,7 @@ lib_ignore = ${common.lib_ignore}
#framework = ${common.framework}
#platform = ${common.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${esp8266_1M.board_flash_mode}
#board = esp01_1m
@@ -414,7 +478,7 @@ lib_ignore = ${common.lib_ignore}
#framework = ${common.framework}
#platform = ${common.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${esp8266_1M.board_flash_mode}
#board = esp01_1m
@@ -426,7 +490,7 @@ lib_ignore = ${common.lib_ignore}
#framework = ${common.framework}
#platform = ${common.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${esp8266_1M.board_flash_mode}
#board = esp01_1m
@@ -445,7 +509,7 @@ lib_ignore = ${common.lib_ignore}
#framework = ${common.framework}
#platform = ${common.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${esp8266_1M.board_flash_mode}
#board = esp01_1m
@@ -458,7 +522,7 @@ lib_ignore = ${common.lib_ignore}
#framework = ${common.framework}
#platform = ${common.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${esp8266_1M.board_flash_mode}
#board = esp01_1m
@@ -473,7 +537,7 @@ lib_ignore = ${common.lib_ignore}
#framework = ${common.framework}
#platform = ${common.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${esp8266_1M.board_flash_mode}
#board = esp01_1m
@@ -485,7 +549,7 @@ lib_ignore = ${common.lib_ignore}
#framework = ${common.framework}
#platform = ${common.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${esp8266_1M.board_flash_mode}
#board = esp01_1m
@@ -497,7 +561,7 @@ lib_ignore = ${common.lib_ignore}
#framework = ${common.framework}
#platform = ${common.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${esp8266_1M.board_flash_mode}
#board = esp01_1m
@@ -509,8 +573,21 @@ lib_ignore = ${common.lib_ignore}
#framework = ${common.framework}
#platform = ${common.platform}
#lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
#lib_ignore = ${common.lib_ignore}
#lib_ldf_mode = ${common.lib_ldf_mode}
#board_flash_mode = ${esp8266_1M.board_flash_mode}
#board = esp01_1m
#build_flags = ${esp8266_1M.build_flags} -D PLUGIN_SET_GENERIC_1M
# Ventus W266 weather station
# https://www.letscontrolit.com/wiki/index.php/VentusW266
[env:hard_Ventus_W266]
platform = ${normal.platform}
lib_deps = ${common.lib_deps}
lib_ignore = ${common.lib_ignore}
lib_ldf_mode = ${common.lib_ldf_mode}
framework = ${common.framework}
upload_speed = ${common.upload_speed}
board_flash_mode = ${esp8266_1M.board_flash_mode}
board = ${common.board}
build_flags = ${esp8266_1M.build_flags} -D PLUGIN_SET_VENTUS_W266
+1 -1
View File
@@ -29,7 +29,7 @@ cat "$NOTES" >> "$NOTES.new"
mv "$NOTES.new" "$NOTES"
git add "$NOTES"
git commit -m "automaticly updated release notes for $NEW"
git commit -m "automatically updated release notes for $NEW"
################ tag and add tag message
+101 -4
View File
@@ -43,6 +43,9 @@ Command commandStringToEnum(const char * cmd) {
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]) {
@@ -81,6 +84,7 @@ Command commandStringToEnum(const char * cmd) {
}
case 'l': {
if (strcmp_P(cmd_lc, PSTR("load") ) == 0) return cmd_Load;
else if (strcmp_P(cmd_lc, PSTR("logentry") ) == 0) return cmd_logentry;
else if (strcmp_P(cmd_lc, PSTR("lowmem") ) == 0) return cmd_lowmem;
break;
}
@@ -125,7 +129,10 @@ Command commandStringToEnum(const char * cmd) {
else if (strcmp_P(cmd_lc, PSTR("taskclearall") ) == 0) return cmd_TaskClearAll;
else if (strcmp_P(cmd_lc, PSTR("taskrun") ) == 0) return cmd_TaskRun;
else if (strcmp_P(cmd_lc, PSTR("taskvalueset") ) == 0) return cmd_TaskValueSet;
else if (strcmp_P(cmd_lc, PSTR("taskvaluesetandrun") ) == 0) return cmd_TaskValueSetAndRun;
else if (strcmp_P(cmd_lc, PSTR("timerset") ) == 0) return cmd_TimerSet;
else if (strcmp_P(cmd_lc, PSTR("timerpause") ) == 0) return cmd_TimerPause;
else if (strcmp_P(cmd_lc, PSTR("timerresume") ) == 0) return cmd_TimerResume;
break;
}
case 'u': {
@@ -147,8 +154,10 @@ Command commandStringToEnum(const char * cmd) {
break;
}
default:
addLog(LOG_LEVEL_INFO, F("Command unknown"));
return cmd_Unknown;
}
addLog(LOG_LEVEL_INFO, F("Command unknown"));
return cmd_Unknown;
}
@@ -452,6 +461,29 @@ void ExecuteCommand(byte source, const char *Line)
break;
}
case cmd_TaskValueSetAndRun:
{
success = true;
if (GetArgv(Line, TmpStr1, 4))
{
float result = 0;
Calculate(TmpStr1, &result);
UserVar[(VARS_PER_TASK * (Par1 - 1)) + Par2 - 1] = result;
SensorSendTask(Par1 - 1);
}
break;
}
// it does nothing, just print on the log (INFO) the content of the line in the rule:
// log example of command: logentry,S=[task#value] T=[task1#value]:
// ACT : logentry,S=24 T=23.1
// Command: logentry
case cmd_logentry:
{
success = true;
break;
}
case cmd_TaskRun:
{
success = true;
@@ -465,11 +497,76 @@ void ExecuteCommand(byte source, const char *Line)
{
success = true;
if (Par2)
{
//start new timer
RulesTimer[Par1 - 1] = millis() + (1000 * Par2);
RulesTimer[Par1 - 1].interval = Par2*1000;
RulesTimer[Par1 - 1].paused = false;
RulesTimer[Par1 - 1].timestamp = millis() + (1000 * Par2);
}
else
{
//disable existing timer
RulesTimer[Par1 - 1] = 0L;
RulesTimer[Par1 - 1].interval = 0;
RulesTimer[Par1 - 1].paused = false;
RulesTimer[Par1 - 1].timestamp = 0L;
}
}
else
{
addLog(LOG_LEVEL_ERROR, F("TIMER: invalid timer number"));
}
break;
}
case cmd_TimerPause:
{
if (Par1>=1 && Par1<=RULES_TIMER_MAX)
{
success = true;
if (RulesTimer[Par1 - 1].paused == false)
{
long delta = timePassedSince(RulesTimer[Par1 - 1].timestamp);
if(RulesTimer[Par1 - 1].timestamp != 0L && delta < 0)
{
String event = F("Rules#TimerPause=");
event += Par1;
rulesProcessing(event);
RulesTimer[Par1 - 1].paused = true;
RulesTimer[Par1 - 1].interval = -delta; // set remaind time
}
}
else
{
addLog(LOG_LEVEL_INFO, F("TIMER: already paused"));
}
}
else
{
addLog(LOG_LEVEL_ERROR, F("TIMER: invalid timer number"));
}
break;
}
case cmd_TimerResume:
{
if (Par1>=1 && Par1<=RULES_TIMER_MAX)
{
success = true;
if (RulesTimer[Par1 - 1].paused == true)
{
if(RulesTimer[Par1 - 1].interval > 0 && RulesTimer[Par1 - 1].timestamp != 0L)
{
String event = F("Rules#TimerResume=");
event += Par1;
rulesProcessing(event);
RulesTimer[Par1 - 1].timestamp = millis() + (RulesTimer[Par1 - 1].interval);
RulesTimer[Par1 - 1].paused = false;
}
}
else
{
addLog(LOG_LEVEL_INFO, F("TIMER: already resumed"));
}
}
else
{
@@ -694,7 +791,7 @@ void ExecuteCommand(byte source, const char *Line)
case cmd_WifiAPMode:
{
WifiAPMode(true);
setAP(true);
success = true;
break;
}
@@ -746,7 +843,7 @@ void ExecuteCommand(byte source, const char *Line)
{
success = true;
WiFi.persistent(true); // use SDK storage of SSID/WPA parameters
WiFi.disconnect(); // this will store empty ssid/wpa into sdk storage
WifiDisconnect(); // this will store empty ssid/wpa into sdk storage
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
break;
}
+10 -3
View File
@@ -89,14 +89,16 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
strncpy(c_payload,(char*)b_payload,length);
c_payload[length] = 0;
/*
String log;
log=F("MQTT : Topic: ");
log+=c_topic;
addLog(LOG_LEVEL_DEBUG, log);
addLog(LOG_LEVEL_DEBUG_MORE, log);
log=F("MQTT : Payload: ");
log+=c_payload;
addLog(LOG_LEVEL_DEBUG, log);
addLog(LOG_LEVEL_DEBUG_MORE, log);
*/
// sprintf_P(log, PSTR("%s%s"), "MQTT : Topic: ", c_topic);
// addLog(LOG_LEVEL_DEBUG, log);
@@ -116,6 +118,7 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
\*********************************************************************************************/
bool MQTTConnect(int controller_idx)
{
++mqtt_reconnect_count;
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(controller_idx, (byte*)&ControllerSettings, sizeof(ControllerSettings));
if (!ControllerSettings.checkHostReachable(true))
@@ -124,6 +127,7 @@ bool MQTTConnect(int controller_idx)
MQTTclient.disconnect();
updateMQTTclient_connected();
}
mqtt = WiFiClient(); // workaround see: https://github.com/esp8266/Arduino/issues/4497#issuecomment-373023864
if (ControllerSettings.UseDNS) {
MQTTclient.setServer(ControllerSettings.getHost().c_str(), ControllerSettings.Port);
} else {
@@ -170,6 +174,7 @@ bool MQTTConnect(int controller_idx)
if (MQTTclient.publish(LWTTopic.c_str(), "Connected", 1)) {
updateMQTTclient_connected();
statusLED(true);
mqtt_reconnect_count = 0;
return true; // end loop if succesfull
}
return false;
@@ -227,8 +232,10 @@ 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))
if (MQTTclient.publish(topic, payload, retained)) {
timermqtt = millis() + 10; // Make sure the MQTT is being processed as soon as possible.
return true;
}
addLog(LOG_LEVEL_DEBUG, F("MQTT : publish failed"));
return false;
}
+150 -23
View File
@@ -1,3 +1,5 @@
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#ifndef ESPEASY_GLOBALS_H_
#define ESPEASY_GLOBALS_H_
@@ -16,7 +18,8 @@
#define DEFAULT_DELAY 60 // Sleep Delay in seconds
// --- Wifi AP Mode (when your Wifi Network is not reachable) ----------------------------------------
#define DEFAULT_AP_IP 192,168,4,1 // Enter IP address (comma separated) for AP (config) mode
#define DEFAULT_AP_IP 192,168,4,1 // Enter IP address (comma separated) for AP (config) mode
#define DEFAULT_AP_SUBNET 255,255,255,0 // Enter IP address (comma separated) for AP (config) mode
#define DEFAULT_AP_KEY "configesp" // Enter network WPA key for AP (config) mode
// --- Wifi Client Mode -----------------------------------------------------------------------------
@@ -42,7 +45,8 @@
#define DEFAULT_SERVER "192.168.0.8" // Enter your Server IP address
#define DEFAULT_PORT 8080 // Enter your Server port value
#define DEFAULT_PROTOCOL 1 // Protocol used for controller communications
#define DEFAULT_PROTOCOL 0 // Protocol used for controller communications
// 0 = Stand-alone (no controller set)
// 1 = Domoticz HTTP
// 2 = Domoticz MQTT
// 3 = Nodo Telnet
@@ -53,8 +57,19 @@
// 8 = Generic HTTP
// 9 = FHEM HTTP
#define DEFAULT_PIN_I2C_SDA 4
#define DEFAULT_PIN_I2C_SCL 5
#define DEFAULT_PIN_STATUS_LED -1
#define DEFAULT_PIN_STATUS_LED_INVERSED true
// --- Advanced Settings ---------------------------------------------------------------------------------
#if defined(ESP32)
#define USE_RTOS_MULTITASKING
#endif
#define DEFAULT_USE_RULES false // (true|false) Enable Rules?
#define DEFAULT_MQTT_RETAIN false // (true|false) Retain MQTT messages?
@@ -69,16 +84,18 @@
#define LOG_TO_SYSLOG 2
#define LOG_TO_WEBLOG 3
#define LOG_TO_SDCARD 4
#define DEFAULT_SYSLOG_IP "" // Syslog IP Address
#define DEFAULT_SYSLOG_IP "" // Syslog IP Address
#define DEFAULT_SYSLOG_LEVEL 0 // Syslog Log Level
#define DEFAULT_SERIAL_LOG_LEVEL LOG_LEVEL_INFO // Serial Log Level
#define DEFAULT_WEB_LOG_LEVEL LOG_LEVEL_INFO // Web Log Level
#define DEFAULT_SERIAL_LOG_LEVEL 0 // Serial Log Level
#define DEFAULT_WEB_LOG_LEVEL LOG_LEVEL_INFO // Web Log Level
#define DEFAULT_SD_LOG_LEVEL 0 // SD Card Log Level
#define DEFAULT_USE_SD_LOG false // (true|false) Enable Logging to the SD card
#define DEFAULT_USE_SERIAL true // (true|false) Enable Logging to the Serial Port
#define DEFAULT_SERIAL_BAUD 115200 // Serial Port Baud Rate
#define DEFAULT_SYSLOG_FACILITY 0 // kern
/*
// --- Experimental Advanced Settings (NOT ACTIVES at this time) ------------------------------------
@@ -149,7 +166,7 @@
#define VERSION 3 // Change in config.dat mapping needs a full reset
#endif
#define BUILD 20100 // git version 2.1.0
#define BUILD 20102 // git version 2.1.02
#if defined(ESP8266)
#define BUILD_NOTES " - Mega"
#endif
@@ -230,14 +247,15 @@
#define LOG_LEVEL_DEBUG 3
#define LOG_LEVEL_DEBUG_MORE 4
#define LOG_LEVEL_DEBUG_DEV 9 // use for testing/debugging only, not for regular use
#define LOG_LEVEL_NRELEMENTS 5 // Update this and getLogLevelDisplayString() when new log levels are added
#define CMD_REBOOT 89
#define CMD_WIFI_DISCONNECT 135
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
#define DEVICES_MAX 72
#define DEVICES_MAX 75
#else
#define DEVICES_MAX 64
#define DEVICES_MAX 50
#endif
#if defined(ESP8266)
@@ -283,6 +301,7 @@
#define DEVICE_TYPE_I2C 20 // connected through I2C
#define DEVICE_TYPE_DUMMY 99 // Dummy device, has no physical connection
#define SENSOR_TYPE_NONE 0
#define SENSOR_TYPE_SINGLE 1
#define SENSOR_TYPE_TEMP_HUM 2
#define SENSOR_TYPE_TEMP_BARO 3
@@ -308,6 +327,7 @@
#define DAT_TASKS_SIZE 2048
#define DAT_TASKS_CUSTOM_OFFSET 1024
#define DAT_TASKS_CUSTOM_SIZE 1024
#define DAT_CUSTOM_CONTROLLER_SIZE 1024
#define DAT_CONTROLLER_SIZE 1024
#define DAT_NOTIFICATION_SIZE 1024
@@ -335,7 +355,7 @@
#include "Custom.h"
#endif
#include "WebStaticData.h"
#include "ESPEasyTimeTypes.h"
#define FS_NO_GLOBALS
#if defined(ESP8266)
@@ -445,12 +465,15 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info);
WiFiEventHandler stationConnectedHandler;
WiFiEventHandler stationDisconnectedHandler;
WiFiEventHandler stationGotIpHandler;
WiFiEventHandler APModeStationConnectedHandler;
WiFiEventHandler APModeStationDisconnectedHandler;
#endif
// Setup DNS, only used if the ESP has no valid WiFi config
const byte DNS_PORT = 53;
IPAddress apIP(DEFAULT_AP_IP);
DNSServer dnsServer;
bool dnsServerActive = false;
#ifdef FEATURE_MDNS
MDNSResponder mdns;
#endif
@@ -460,13 +483,14 @@ WiFiClient mqtt;
PubSubClient MQTTclient(mqtt);
bool MQTTclient_should_reconnect = true;
bool MQTTclient_connected = false;
int mqtt_reconnect_count = 0;
// udp protocol stuff (syslog, global sync, node info list, ntp time)
WiFiUDP portUDP;
struct CRCStruct{
char compileTimeMD5[16+32+1]= "MD5_MD5_MD5_MD5_BoundariesOfTheSegmentsGoHere...";
char binaryFilename[16+32+1]= "ThisIsTheDummyPlaceHolderForTheBinaryFilename...";
char binaryFilename[32+32+1]= "ThisIsTheDummyPlaceHolderForTheBinaryFilename64ByteLongFilenames";
char compileTime[16]= __TIME__;
char compileDate[16]= __DATE__;
uint8_t runTimeMD5[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -492,6 +516,7 @@ enum Command {
cmd_i2cscanner,
cmd_IP,
cmd_Load,
cmd_logentry,
cmd_lowmem,
cmd_malloc,
cmd_meminfo,
@@ -518,7 +543,10 @@ enum Command {
cmd_TaskClearAll,
cmd_TaskRun,
cmd_TaskValueSet,
cmd_TaskValueSetAndRun,
cmd_TimerSet,
cmd_TimerPause,
cmd_TimerResume,
cmd_udptest,
cmd_Unit,
cmd_wdconfig,
@@ -537,10 +565,12 @@ enum Command {
// Forward declarations.
Command commandStringToEnum(const char * cmd);
bool WiFiConnected(uint32_t timeout_ms);
bool WiFiConnected();
bool hostReachable(const IPAddress& ip);
bool hostReachable(const String& hostname);
void formatMAC(const uint8_t* mac, char (&strMAC)[20]);
void formatIP(const IPAddress& ip, char (&strIP)[20]);
String to_json_object_value(const String& object, const String& value);
struct SecurityStruct
{
@@ -567,6 +597,7 @@ struct SecurityStruct
byte AllowedIPrangeLow[4]; // TD-er: Use these
byte AllowedIPrangeHigh[4];
byte IPblockLevel;
//its safe to extend this struct, up to 4096 bytes, default values in config are 0. Make sure crc is last
uint8_t ProgmemMd5[16]; // crc of the binary that last saved the struct to file.
uint8_t md5[16];
@@ -584,7 +615,8 @@ struct SettingsStruct
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)
DST_Start(0), DST_End(0), UseRTOSMultitasking(false), Pin_Reset(-1),
SyslogFacility(DEFAULT_SYSLOG_FACILITY), StructSize(0)
{
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
Protocol[i] = 0;
@@ -688,13 +720,20 @@ struct SettingsStruct
boolean ArduinoOTAEnable;
uint16_t DST_Start;
uint16_t DST_End;
boolean UseRTOSMultitasking;
int8_t Pin_Reset;
byte SyslogFacility;
uint32_t StructSize; // Forced to be 32 bit, to make sure alignment is clear.
//its safe to extend this struct, up to several bytes, default values in config are 0
//look in misc.ino how config.dat is used because also other stuff is stored in it at different offsets.
//TODO: document config.dat somewhere here
// FIXME @TD-er: As discussed in #1292, the CRC for the settings is now disabled.
// make sure crc is the last value in the struct
uint8_t ProgmemMd5[16]; // crc of the binary that last saved the struct to file.
uint8_t md5[16];
// Try to extend settings to make the checksum 4-byte aligned.
// uint8_t ProgmemMd5[16]; // crc of the binary that last saved the struct to file.
// uint8_t md5[16];
} Settings;
struct ControllerSettingsStruct
@@ -796,6 +835,7 @@ private:
if (!UseDNS) {
return true;
}
if (!WiFiConnected()) return false;
IPAddress tmpIP;
if (WiFi.hostByName(HostName, tmpIP)) {
for (byte x = 0; x < 4; x++) {
@@ -890,24 +930,40 @@ struct EventStruct
};
#define LOG_STRUCT_MESSAGE_SIZE 128
#define LOG_STRUCT_MESSAGE_LINES 20
#ifdef ESP32
#define LOG_STRUCT_MESSAGE_LINES 30
#else
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
#define LOG_STRUCT_MESSAGE_LINES 10
#else
#define LOG_STRUCT_MESSAGE_LINES 15
#endif
#endif
struct LogStruct {
LogStruct() : write_idx(0), read_idx(0) {
for (int i = 0; i < LOG_STRUCT_MESSAGE_LINES; ++i) {
memset(Message[i], 0, LOG_STRUCT_MESSAGE_SIZE);
Message[i].reserve(LOG_STRUCT_MESSAGE_SIZE);
timeStamp[i] = 0;
log_level[i] = 0;
}
}
void add(const char *line) {
void add(const byte loglevel, const char *line) {
write_idx = (write_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
if (write_idx == read_idx) {
// Buffer full, move read_idx to overwrite oldest entry.
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
}
timeStamp[write_idx] = millis();
strncpy(Message[write_idx], line, LOG_STRUCT_MESSAGE_SIZE-1);
log_level[write_idx] = loglevel;
unsigned linelength = strlen(line);
if (linelength > LOG_STRUCT_MESSAGE_SIZE-1)
linelength = LOG_STRUCT_MESSAGE_SIZE-1;
Message[write_idx] = "";
for (unsigned i = 0; i < linelength; ++i) {
Message[write_idx] += *(line + i);
}
}
// Read the next item and append it to the given string.
@@ -920,6 +976,20 @@ struct LogStruct {
return !isEmpty();
}
String get_logjson_formatted(bool& logLinesAvailable, unsigned long& timestamp) {
logLinesAvailable = false;
if (isEmpty()) {
return "";
}
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
timestamp = timeStamp[read_idx];
String output = logjson_formatLine(read_idx);
if (isEmpty()) return output;
output += ",\n";
logLinesAvailable = true;
return output;
}
bool get(String& output, const String& lineEnd, int line) {
int tmpread((write_idx + 1+line) % LOG_STRUCT_MESSAGE_LINES);
if (timeStamp[tmpread] != 0) {
@@ -955,11 +1025,25 @@ struct LogStruct {
return output;
}
String logjson_formatLine(int index) {
String output;
output.reserve(LOG_STRUCT_MESSAGE_SIZE + 64);
output = "{";
output += to_json_object_value("timestamp", String(timeStamp[index]));
output += ",\n";
output += to_json_object_value("text", Message[index]);
output += ",\n";
output += to_json_object_value("level", String(log_level[index]));
output += "}";
return output;
}
int write_idx;
int read_idx;
unsigned long timeStamp[LOG_STRUCT_MESSAGE_LINES];
char Message[LOG_STRUCT_MESSAGE_LINES][LOG_STRUCT_MESSAGE_SIZE];
byte log_level[LOG_STRUCT_MESSAGE_LINES];
String Message[LOG_STRUCT_MESSAGE_LINES];
} Logging;
@@ -1036,6 +1120,8 @@ struct systemTimerStruct
byte Par3;
} 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) {}
@@ -1080,7 +1166,12 @@ String printWebString = "";
boolean printToWebJSON = false;
float UserVar[VARS_PER_TASK * TASKS_MAX];
unsigned long RulesTimer[RULES_TIMER_MAX];
struct rulesTiemerStatus
{
unsigned long timestamp;
unsigned int interval; //interval in millisencond
boolean paused;
} RulesTimer[RULES_TIMER_MAX];
unsigned long timerSensor[TASKS_MAX];
unsigned long timer100ms;
@@ -1091,8 +1182,6 @@ unsigned long timermqtt;
unsigned long timermqtt_interval;
unsigned long lastSend;
unsigned long lastWeb;
unsigned int NC_Count = 0;
unsigned int C_Count = 0;
byte cmd_within_mainloop = 0;
unsigned long connectionFailures;
unsigned long wdcounter = 0;
@@ -1154,6 +1243,27 @@ enum WiFiDisconnectReason
};
#endif
#ifndef ESP32
// To do some reconnection check.
#include <Ticker.h>
Ticker connectionCheck;
#endif
bool reconnectChecker = false;
void connectionCheckHandler()
{
if (reconnectChecker == false && !WiFiConnected()){
reconnectChecker = true;
WiFi.reconnect();
}
else if (WiFiConnected() && reconnectChecker == true){
reconnectChecker = false;
}
}
bool useStaticIP();
// WiFi related data
boolean wifiSetup = false;
boolean wifiSetupConnect = false;
@@ -1161,6 +1271,7 @@ uint8_t lastBSSID[6] = {0};
uint8_t wifiStatus = ESPEASY_WIFI_DISCONNECTED;
unsigned long last_wifi_connect_attempt_moment = 0;
unsigned int wifi_connect_attempt = 0;
int wifi_reconnects = -1; // First connection attempt is not a reconnect.
uint8_t lastWiFiSettings = 0;
String last_ssid;
bool bssid_changed = false;
@@ -1169,17 +1280,30 @@ WiFiDisconnectReason lastDisconnectReason = WIFI_DISCONNECT_REASON_UNSPECIFIED;
unsigned long lastConnectMoment = 0;
unsigned long lastDisconnectMoment = 0;
unsigned long lastGetIPmoment = 0;
unsigned long lastGetScanMoment = 0;
unsigned long lastConnectedDuration = 0;
bool intent_to_reboot = false;
uint8_t lastMacConnectedAPmode[6] = {0};
uint8_t lastMacDisconnectedAPmode[6] = {0};
//uint32_t scan_done_status = 0;
uint8_t scan_done_number = 0;
//uint8_t scan_done_scan_id = 0;
// Semaphore like booleans for processing data gathered from WiFi events.
bool processedConnect = true;
bool processedDisconnect = true;
bool processedGetIP = true;
bool processedConnectAPmode = true;
bool processedDisconnectAPmode = true;
bool processedScanDone = true;
bool webserver_state = false;
bool webserver_init = false;
unsigned long start = 0;
unsigned long elapsed = 0;
unsigned long elapsed10ps = 0;
unsigned long elapsed10psU = 0;
unsigned long elapsed50ps = 0;
unsigned long loopCounter = 0;
unsigned long loopCounterLast = 0;
unsigned long loopCounterMax = 1;
@@ -1196,6 +1320,9 @@ bool firstLoop=true;
boolean activeRuleSets[RULESETS_MAX];
boolean UseRTOSMultitasking;
void (*MainLoopCall_ptr)(void);
// These wifi event functions must be in a .h-file because otherwise the preprocessor
// may not filter the ifdef checks properly.
+152 -69
View File
@@ -96,7 +96,9 @@ int firstEnabledBlynkController() {
\*********************************************************************************************/
void setup()
{
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
WiFi.setAutoReconnect(false);
setWifiMode(WIFI_OFF);
checkRAM(F("setup"));
#if defined(ESP32)
@@ -110,7 +112,6 @@ void setup()
// Serial.print("\n\n\nBOOOTTT\n\n\n");
initLog();
#if defined(ESP32)
WiFi.onEvent((WiFiEventFullCb)WiFiEvent);
#else
@@ -118,6 +119,8 @@ void setup()
stationConnectedHandler = WiFi.onStationModeConnected(onConnected);
stationDisconnectedHandler = WiFi.onStationModeDisconnected(onDisconnect);
stationGotIpHandler = WiFi.onStationModeGotIP(onGotIP);
APModeStationConnectedHandler = WiFi.onSoftAPModeStationConnected(onConnectedAPmode);
APModeStationDisconnectedHandler = WiFi.onSoftAPModeStationDisconnected(onDisonnectedAPmode);
#endif
if (SpiffsSectors() < 32)
@@ -131,6 +134,9 @@ void setup()
String log = F("\n\n\rINIT : Booting version: ");
log += BUILD_GIT;
log += F(" (");
log += getSystemLibraryString();
log += F(")");
addLog(LOG_LEVEL_INFO, log);
@@ -170,9 +176,9 @@ void setup()
fileSystemCheck();
progMemMD5check();
LoadSettings();
// setWifiMode(WIFI_STA);
checkRuleSets();
if (strcasecmp(SecuritySettings.WifiSSID, "ssid") == 0)
wifiSetup = true;
ExtraTaskSettings.TaskIndex = 255; // make sure this is an unused nr to prevent cache load on boot
@@ -195,6 +201,7 @@ void setup()
//make sure previous serial buffers are flushed before resetting baudrate
Serial.flush();
Serial.begin(Settings.BaudRate);
// Serial.setDebugOutput(true);
}
if (Settings.Build != BUILD)
@@ -228,23 +235,41 @@ void setup()
PluginInit();
CPluginInit();
NPluginInit();
log = F("INFO : Plugins: ");
log += deviceCount + 1;
log += getPluginDescriptionString();
log += F(" (");
log += getSystemLibraryString();
log += F(")");
addLog(LOG_LEVEL_INFO, log);
if (deviceCount + 1 >= PLUGIN_MAX) {
addLog(LOG_LEVEL_ERROR, F("Programming error! - Increase PLUGIN_MAX"));
}
if (Settings.UseRules)
{
String event = F("System#Wake");
rulesProcessing(event);
}
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
WifiAPconfig();
if (!selectValidWiFiSettings()) {
wifiSetup = true;
}
/*
// FIXME TD-er:
// Async scanning for wifi doesn't work yet like it should.
// So no selection of strongest network yet.
if (selectValidWiFiSettings()) {
WifiScanAsync();
}
*/
WiFiConnectRelaxed();
#ifdef FEATURE_REPORTING
ReportStatus();
#endif
WebServerInit();
#ifdef FEATURE_ARDUINO_OTA
ArduinoOTAInit();
#endif
@@ -262,12 +287,6 @@ void setup()
vcc = ESP.getVcc() / 1000.0;
#endif
// Start DNS, only used if the ESP has no valid WiFi config
// It will reply with it's own address on all DNS requests
// (captive portal concept)
if (wifiSetup)
dnsServer.start(DNS_PORT, "*", apIP);
if (Settings.UseRules)
{
String event = F("System#Boot");
@@ -276,8 +295,55 @@ void setup()
writeDefaultCSS();
UseRTOSMultitasking = Settings.UseRTOSMultitasking;
#ifdef USE_RTOS_MULTITASKING
if(UseRTOSMultitasking){
log = F("RTOS : Launching tasks");
addLog(LOG_LEVEL_INFO, log);
xTaskCreatePinnedToCore(RTOS_TaskServers, "RTOS_TaskServers", 8192, NULL, 1, NULL, 1);
xTaskCreatePinnedToCore(RTOS_TaskSerial, "RTOS_TaskSerial", 8192, NULL, 1, NULL, 1);
xTaskCreatePinnedToCore(RTOS_Task10ps, "RTOS_Task10ps", 8192, NULL, 1, NULL, 1);
}
#endif
// #ifndef ESP32
// connectionCheck.attach(30, connectionCheckHandler);
// #endif
timer20ms = millis();
timer100ms = millis();
timer1s = millis();
}
#ifdef USE_RTOS_MULTITASKING
void RTOS_TaskServers( void * parameter )
{
while (true){
delay(100);
WebServer.handleClient();
checkUDP();
}
}
void RTOS_TaskSerial( void * parameter )
{
while (true){
delay(100);
if (Settings.UseSerial)
if (Serial.available())
if (!PluginCall(PLUGIN_SERIAL_IN, 0, dummyString))
serial();
}
}
void RTOS_Task10ps( void * parameter )
{
while (true){
delay(100);
run10TimesPerSecond();
}
}
#endif
int firstEnabledMQTTController() {
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[i]);
@@ -299,7 +365,9 @@ bool getControllerProtocolDisplayName(byte ProtocolIndex, byte parameterIdx, Str
\*********************************************************************************************/
void loop()
{
//checkRAM(F("loop"));
if(MainLoopCall_ptr)
MainLoopCall_ptr();
loopCounter++;
if (wifiSetupConnect)
@@ -312,10 +380,15 @@ void loop()
if (wifiStatus >= ESPEASY_WIFI_CONNECTED) processConnect();
if (wifiStatus >= ESPEASY_WIFI_GOT_IP) processGotIP();
if (wifiStatus == ESPEASY_WIFI_DISCONNECTED) processDisconnect();
} else if (WiFi.status() != WL_CONNECTED) {
} else if (!WiFiConnected()) {
// Somehow the WiFi has entered a limbo state.
resetWiFi();
// FIXME TD-er: This may happen on WiFi config with AP_STA mode active.
// addLog(LOG_LEVEL_ERROR, F("Wifi status out sync"));
// resetWiFi();
}
if (!processedConnectAPmode) processConnectAPmode();
if (!processedDisconnectAPmode) processDisconnectAPmode();
if (!processedScanDone) processScanDone();
bool firstLoopWiFiConnected = wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED && firstLoop;
if (firstLoopWiFiConnected) {
@@ -341,7 +414,8 @@ void loop()
run50TimesPerSecond();
if (timeOutReached(timer100ms))
run10TimesPerSecond();
if(!UseRTOSMultitasking)
run10TimesPerSecond();
if (timeOutReached(timerwd))
runEach30Seconds();
@@ -405,8 +479,9 @@ void updateMQTTclient_connected() {
}
}
if (!MQTTclient_connected) {
if (timermqtt_interval < 2000) {
timermqtt_interval += 250;
// As suggested here: https://github.com/letscontrolit/ESPEasy/issues/1356
if (timermqtt_interval < 30000) {
timermqtt_interval += 5000;
}
} else {
timermqtt_interval = 250;
@@ -420,10 +495,10 @@ void updateMQTTclient_connected() {
void run50TimesPerSecond()
{
timer20ms = millis() + 20;
setNextTimeInterval(timer20ms, 20);
unsigned long start = micros();
PluginCall(PLUGIN_FIFTY_PER_SECOND, 0, dummyString);
// statusLED(false);
elapsed50ps += micros() - start;
}
/*********************************************************************************************\
@@ -431,17 +506,21 @@ void run50TimesPerSecond()
\*********************************************************************************************/
void run10TimesPerSecond()
{
start = micros();
timer100ms = millis() + 100;
setNextTimeInterval(timer100ms, 100);
unsigned long start = micros();
PluginCall(PLUGIN_TEN_PER_SECOND, 0, dummyString);
elapsed10ps += micros() - start;
start = micros();
PluginCall(PLUGIN_UNCONDITIONAL_POLL, 0, dummyString);
elapsed10psU += micros() - start;
if (Settings.UseRules && eventBuffer.length() > 0)
{
rulesProcessing(eventBuffer);
eventBuffer = "";
}
elapsed = micros() - start;
WebServer.handleClient();
#ifndef USE_RTOS_MULTITASKING
WebServer.handleClient();
#endif
}
@@ -450,6 +529,7 @@ void run10TimesPerSecond()
\*********************************************************************************************/
void runOncePerSecond()
{
setNextTimeInterval(timer1s, 1000);
dailyResetCounter++;
if (dailyResetCounter > 86400) // 1 day elapsed... //86400
{
@@ -460,8 +540,6 @@ void runOncePerSecond()
addLog(LOG_LEVEL_INFO, log);
}
timer1s = millis() + 1000;
checkSensors();
if (Settings.ConnectionFailuresThreshold)
@@ -496,15 +574,15 @@ void runOncePerSecond()
if (Settings.UseNTP)
checkTime();
unsigned long timer = micros();
unsigned long start = micros();
PluginCall(PLUGIN_ONCE_A_SECOND, 0, dummyString);
unsigned long elapsed = micros() - start;
checkSystemTimers();
if (Settings.UseRules)
rulesTimers();
timer = micros() - timer;
if (SecuritySettings.Password[0] != 0)
{
@@ -522,19 +600,22 @@ void runOncePerSecond()
Wire.endTransmission();
}
if (Settings.SerialLogLevel == 5)
if (Settings.SerialLogLevel == LOG_LEVEL_DEBUG_DEV)
{
Serial.print(F("10 ps:"));
Serial.print(F("Plugin calls: 50 ps:"));
Serial.print(elapsed50ps);
Serial.print(F(" uS, 10 ps:"));
Serial.print(elapsed10ps);
Serial.print(F(" uS, 10 psU:"));
Serial.print(elapsed10psU);
Serial.print(F(" uS, 1 ps:"));
Serial.print(elapsed);
Serial.print(F(" uS 1 ps:"));
Serial.println(timer);
}
if (timerAPoff != 0 && timeOutReached(timerAPoff))
{
timerAPoff = 0;
WifiAPMode(false);
Serial.println(F(" uS"));
elapsed50ps=0;
elapsed10ps=0;
elapsed10psU=0;
}
checkResetFactoryPin();
}
/*********************************************************************************************\
@@ -558,11 +639,6 @@ void runEach30Seconds()
sendSysInfoUDP(1);
refreshNodeList();
int enabledMqttController = firstEnabledMQTTController();
if (enabledMqttController >= 0) {
MQTTCheck(enabledMqttController);
}
#if defined(ESP8266)
if (Settings.UseSSDP)
SSDP_update();
@@ -597,7 +673,7 @@ void checkSensors()
(isDeepSleep || timeOutReached(timerSensor[x]))
)
{
timerSensor[x] = millis() + Settings.TaskDeviceTimer[x] * 1000;
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);
@@ -680,7 +756,9 @@ void setSystemTimer(unsigned long timer, byte plugin, byte Par1, byte Par2, byte
// 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
boolean reUse = false;
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].Par1 == Par1))
@@ -690,20 +768,25 @@ void setSystemTimer(unsigned long timer, byte plugin, byte Par1, byte Par2, byte
break;
}
}
else if(firstAvailable == SYSTEM_TIMER_MAX)
{
firstAvailable = x;
}
}
if (!reUse)
{
// find a new free timer slot...
for (byte x = 0; x < SYSTEM_TIMER_MAX; x++)
if (systemTimers[x].timer == 0)
{
systemTimers[x].timer = millis() + timer;
systemTimers[x].plugin = plugin;
systemTimers[x].Par1 = Par1;
systemTimers[x].Par2 = Par2;
systemTimers[x].Par3 = Par3;
break;
}
if (firstAvailable == SYSTEM_TIMER_MAX )
{
addLog(LOG_LEVEL_ERROR, F(NOTAVAILABLE_SYSTEM_TIMER_ERROR));
}
else
{
systemTimers[firstAvailable].timer = millis() + timer;
systemTimers[firstAvailable].plugin = plugin;
systemTimers[firstAvailable].Par1 = Par1;
systemTimers[firstAvailable].Par2 = Par2;
systemTimers[firstAvailable].Par3 = Par3;
}
}
}
@@ -780,19 +863,19 @@ void backgroundtasks()
tcpCleanup();
#endif
if (Settings.UseSerial)
if (Serial.available())
if (!PluginCall(PLUGIN_SERIAL_IN, 0, dummyString))
serial();
if(!UseRTOSMultitasking){
if (Settings.UseSerial)
if (Serial.available())
if (!PluginCall(PLUGIN_SERIAL_IN, 0, dummyString))
serial();
WebServer.handleClient();
checkUDP();
}
// process DNS, only used if the ESP has no valid WiFi config
if (wifiSetup)
if (dnsServerActive)
dnsServer.processNextRequest();
WebServer.handleClient();
checkUDP();
#ifdef FEATURE_ARDUINO_OTA
if(Settings.ArduinoOTAEnable)
ArduinoOTA.handle();
+76 -7
View File
@@ -1,3 +1,36 @@
//********************************************************************************
// Work-around for setting _useStaticIP
// See reported issue: https://github.com/esp8266/Arduino/issues/4114
//********************************************************************************
#ifdef ESP32
class WiFi_Access_Static_IP: public WiFiSTAClass {
public:
void set_use_static_ip(bool enabled) {
_useStaticIp = enabled;
}
};
#else
class WiFi_Access_Static_IP: public ESP8266WiFiSTAClass {
public:
void set_use_static_ip(bool enabled) {
_useStaticIp = enabled;
}
};
#endif
void setUseStaticIP(bool enabled) {
WiFi_Access_Static_IP tmp_wifi;
tmp_wifi.set_use_static_ip(enabled);
}
void markGotIP() {
lastGetIPmoment = millis();
wifiStatus = ESPEASY_WIFI_GOT_IP;
processedGetIP = false;
}
//********************************************************************************
// Functions called on events.
// Make sure not to call anything in these functions that result in delay() or yield()
@@ -23,9 +56,26 @@ void WiFiEvent(system_event_id_t event, system_event_info_t info) {
wifiStatus = ESPEASY_WIFI_DISCONNECTED;
break;
case SYSTEM_EVENT_STA_GOT_IP:
lastGetIPmoment = millis();
wifiStatus = ESPEASY_WIFI_GOT_IP;
processedGetIP = false;
markGotIP();
break;
case SYSTEM_EVENT_AP_STACONNECTED:
for (byte i = 0; i < 6; ++i) {
lastMacConnectedAPmode[i] = info.sta_connected.mac[i];
}
processedConnectAPmode = false;
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
for (byte i = 0; i < 6; ++i) {
lastMacConnectedAPmode[i] = info.sta_disconnected.mac[i];
}
processedDisconnectAPmode = false;
break;
case SYSTEM_EVENT_SCAN_DONE:
lastGetScanMoment = millis();
// scan_done_status = info.scan_done.status;
scan_done_number = info.scan_done.number;
// scan_done_scan_id = info.scan_done.scan_id;
processedScanDone = false;
break;
default:
break;
@@ -55,14 +105,33 @@ void onDisconnect(const WiFiEventStationModeDisconnected& event){
lastConnectedDuration = timeDiff(last_wifi_connect_attempt_moment, lastDisconnectMoment);
} else
lastConnectedDuration = timeDiff(lastConnectMoment, lastDisconnectMoment);
processedDisconnect = false;
lastDisconnectReason = event.reason;
wifiStatus = ESPEASY_WIFI_DISCONNECTED;
processedDisconnect = false;
}
void onGotIP(const WiFiEventStationModeGotIP& event){
lastGetIPmoment = millis();
wifiStatus = ESPEASY_WIFI_GOT_IP;
processedGetIP = false;
markGotIP();
}
void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event) {
for (byte i = 0; i < 6; ++i) {
lastMacConnectedAPmode[i] = event.mac[i];
}
processedConnectAPmode = false;
}
void onDisonnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event) {
for (byte i = 0; i < 6; ++i) {
lastMacDisconnectedAPmode[i] = event.mac[i];
}
processedDisconnectAPmode = false;
}
void onScanFinished(int networksFound) {
lastGetScanMoment = millis();
scan_done_number = networksFound;
processedScanDone = false;
}
#endif
+474 -174
View File
@@ -1,4 +1,5 @@
#define WIFI_AP_OFF_TIMER_DURATION 60000 // in milliSeconds
//********************************************************************************
// Functions to process the data gathered from the events.
@@ -6,15 +7,16 @@
//********************************************************************************
void processConnect() {
if (processedConnect) return;
processedConnect = true;
++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;
const long connect_duration = timeDiff(last_wifi_connect_attempt_moment, lastConnectMoment);
if (connect_duration > 0 && connect_duration < 30000) {
// Just log times when they make sense.
log += F(" Duration: ");
@@ -22,17 +24,20 @@ void processConnect() {
log += F(" ms");
}
addLog(LOG_LEVEL_INFO, log);
if (Settings.UseRules && bssid_changed) {
String event = F("WiFi#ChangedAccesspoint");
rulesProcessing(event);
}
wifi_connect_attempt = 0;
processedConnect = true;
if (useStaticIP()) {
setupStaticIPconfig();
markGotIP();
}
logConnectionStatus();
}
void processDisconnect() {
if (processedDisconnect) return;
processedDisconnect = true;
if (Settings.UseRules) {
String event = F("WiFi#Disconnected");
rulesProcessing(event);
@@ -45,25 +50,18 @@ void processDisconnect() {
log += format_msec_duration(lastConnectedDuration);
}
addLog(LOG_LEVEL_INFO, log);
processedDisconnect = true;
if (Settings.deepSleep && Settings.deepSleepOnFail) {
//only one attempt in deepsleep, to conserve battery
addLog(LOG_LEVEL_ERROR, F("SLEEP: Connection failed, going back to sleep."));
deepSleep(Settings.Delay);
}
if (!intent_to_reboot)
WiFiConnectRelaxed();
logConnectionStatus();
}
void processGotIP() {
if (processedGetIP)
return;
if (wifiStatus < ESPEASY_WIFI_GOT_IP)
return;
IPAddress ip = WiFi.localIP();
if (!useStaticIP())
if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0)
return;
processedGetIP = true;
const IPAddress gw = WiFi.gatewayIP();
const IPAddress subnet = WiFi.subnetMask();
String log = F("WIFI : ");
@@ -118,6 +116,7 @@ void processGotIP() {
if (Settings.UseNTP) {
initTime();
}
mqtt_reconnect_count = 0;
timermqtt_interval = 100;
timermqtt = millis() + timermqtt_interval;
if (Settings.UseRules)
@@ -126,19 +125,264 @@ void processGotIP() {
rulesProcessing(event);
}
statusLED(true);
// WiFi.scanDelete();
wifiStatus = ESPEASY_WIFI_SERVICES_INITIALIZED;
processedGetIP = true;
setWebserverRunning(true);
wifi_connect_attempt = 0;
if (wifiSetup) {
// Wifi setup was active, Apparently these settings work.
wifiSetup = false;
SaveSettings();
}
logConnectionStatus();
}
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);
timerAPoff = 0; // Disable timer to switch AP off
setWebserverRunning(true);
// Start DNS, only used if the ESP has no valid WiFi config
// It will reply with it's own address on all DNS requests
// (captive portal concept)
if (!dnsServerActive) {
dnsServerActive = true;
dnsServer.start(DNS_PORT, "*", apIP);
}
}
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 (nrStationsConnected == 0) {
timerAPoff = millis() + WIFI_AP_OFF_TIMER_DURATION;
}
}
void processDisableAPmode() {
if (timerAPoff == 0) return;
if (WifiIsAP(WiFi.getMode())) {
// disable AP after timeout.
if (timeOutReached(timerAPoff)) {
setAP(false);
}
}
}
void processScanDone() {
if (processedScanDone) return;
processedScanDone = true;
String log = F("WIFI : Scan finished, found: ");
log += scan_done_number;
addLog(LOG_LEVEL_INFO, log);
int bestScanID = -1;
int32_t bestRssi = -1000;
uint8_t bestWiFiSettings = lastWiFiSettings;
if (selectValidWiFiSettings()) {
bool done = false;
String lastWiFiSettingsSSID = getLastWiFiSettingsSSID();
for (int settingNr = 0; !done && settingNr < 2; ++settingNr) {
for (int i = 0; i < scan_done_number; ++i) {
if (WiFi.SSID(i) == lastWiFiSettingsSSID) {
int32_t rssi = WiFi.RSSI(i);
if (bestRssi < rssi) {
bestRssi = rssi;
bestScanID = i;
bestWiFiSettings = lastWiFiSettings;
}
}
}
if (!selectNextWiFiSettings()) done = true;
}
if (bestScanID >= 0) {
log = F("WIFI : Selected: ");
log += formatScanResult(bestScanID, " ");
addLog(LOG_LEVEL_INFO, log);
lastWiFiSettings = bestWiFiSettings;
uint8_t * scanbssid = WiFi.BSSID(bestScanID);
if (scanbssid) {
for (int i = 0; i < 6 ; ++i) {
lastBSSID[i] = *(scanbssid + i);
}
}
}
}
}
void resetWiFi() {
WiFiMode_t currentMode = WiFi.getMode();
WiFi.mode(WIFI_OFF);
WiFi.mode(currentMode);
addLog(LOG_LEVEL_INFO, F("Reset WiFi."));
setWifiMode(WIFI_OFF);
setWifiMode(WIFI_STA);
lastDisconnectMoment = millis();
processedDisconnect = false;
wifiStatus = ESPEASY_WIFI_DISCONNECTED;
}
void WifiScanAsync() {
addLog(LOG_LEVEL_INFO, F("WIFI : Start network scan"));
#ifdef ESP32
bool async = true;
bool show_hidden = false;
bool passive = false;
uint32_t max_ms_per_chan = 300;
WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan);
#else
// 2.4.x only and it doesn't work like expected.
// WiFi.scanNetworksAsync(onScanFinished);
#endif
}
//********************************************************************************
// WiFi state
//********************************************************************************
// 0 Wifi off
// 1 Start => STA
// 2 Try connect => STA => successful, goto 7
// 3 Connection fails => AP => no client in N seconds, goto 1
// 4 Client connects => AP
// 5 Credentials changed => STA_AP => goto 2
// 6 Connect successful (AP on) => STA_AP => disable AP after N seconds, goto 8
// 7 Connect successful => STA
// 8 Disable AP after N seconds => STA
//********************************************************************************
bool WifiIsAP(WiFiMode_t wifimode)
{
#if defined(ESP32)
return (wifimode == WIFI_MODE_AP) || (wifimode == WIFI_MODE_APSTA);
#else
return (wifimode == WIFI_AP) || (wifimode == WIFI_AP_STA);
#endif
}
bool WifiIsSTA(WiFiMode_t wifimode)
{
#if defined(ESP32)
return ((wifimode & WIFI_MODE_STA) != 0);
#else
return ((wifimode & WIFI_STA) != 0);
#endif
}
//********************************************************************************
// Set Wifi Mode
//********************************************************************************
void setSTA(bool enable) {
switch(WiFi.getMode()) {
case WIFI_OFF:
if (enable) setWifiMode(WIFI_STA);
break;
case WIFI_STA:
if (!enable) setWifiMode(WIFI_OFF);
break;
case WIFI_AP:
if (enable) setWifiMode(WIFI_AP_STA);
break;
case WIFI_AP_STA:
if (!enable) setWifiMode(WIFI_AP);
break;
default:
break;
}
}
void setAP(bool enable) {
switch(WiFi.getMode()) {
case WIFI_OFF:
if (enable) setWifiMode(WIFI_AP);
break;
case WIFI_STA:
if (enable) setWifiMode(WIFI_AP_STA);
break;
case WIFI_AP:
if (!enable) setWifiMode(WIFI_OFF);
break;
case WIFI_AP_STA:
if (!enable) setWifiMode(WIFI_STA);
break;
default:
break;
}
if (enable) {
timerAPoff = millis() + WIFI_AP_OFF_TIMER_DURATION;
// create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password!
// setup ssid for AP Mode when needed
String softAPSSID=WifiGetAPssid();
String pwd = SecuritySettings.WifiAPKey;
IPAddress subnet(DEFAULT_AP_SUBNET);
if (!WiFi.softAPConfig(apIP, apIP, subnet)) {
addLog(LOG_LEVEL_ERROR, "WIFI : [AP] softAPConfig failed!");
}
if (WiFi.softAP(softAPSSID.c_str(),pwd.c_str())) {
String log("WIFI : AP Mode ssid will be ");
log += softAPSSID;
log += F(" with address ");
log += WiFi.softAPIP().toString();
addLog(LOG_LEVEL_INFO, log);
} else {
String log("WIFI : Error while starting AP Mode with SSID: ");
log += softAPSSID;
log += F(" IP: ");
log += apIP.toString();
addLog(LOG_LEVEL_ERROR, log);
}
#ifdef ESP32
#else
if(wifi_softap_dhcps_status() != DHCP_STARTED) {
if(!wifi_softap_dhcps_start()) {
addLog(LOG_LEVEL_ERROR, "WIFI : [AP] wifi_softap_dhcps_start failed!");
}
}
#endif
} else {
timerAPoff = 0; // Disable timer to switch AP off
if (dnsServerActive) {
dnsServerActive = false;
dnsServer.stop();
}
}
}
void setWifiMode(WiFiMode_t wifimode) {
if (WiFi.getMode() == wifimode) {
return;
}
switch (wifimode) {
case WIFI_OFF:
addLog(LOG_LEVEL_INFO, F("WIFI : Switch off WiFi"));
break;
case WIFI_STA:
addLog(LOG_LEVEL_INFO, F("WIFI : Set WiFi to STA"));
break;
case WIFI_AP:
addLog(LOG_LEVEL_INFO, F("WIFI : Set WiFi to AP"));
break;
case WIFI_AP_STA:
addLog(LOG_LEVEL_INFO, F("WIFI : Set WiFi to AP+STA"));
break;
default:
break;
}
setUseStaticIP(useStaticIP());
WiFi.mode(wifimode);
delay(30); // Must allow for some time to init.
}
//********************************************************************************
// Determine Wifi AP name to set. (also used for mDNS)
@@ -146,7 +390,7 @@ void resetWiFi() {
String WifiGetAPssid()
{
String ssid(Settings.Name);
ssid+=F("-");
ssid+=F("_");
ssid+=Settings.Unit;
return (ssid);
}
@@ -163,76 +407,38 @@ String WifiGetHostname()
}
//********************************************************************************
// Set Wifi AP Mode config
//********************************************************************************
void WifiAPconfig()
{
// create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password!
// setup ssid for AP Mode when needed
String softAPSSID=WifiGetAPssid();
String pwd = SecuritySettings.WifiAPKey;
WiFi.softAP(softAPSSID.c_str(),pwd.c_str());
// We start in STA mode
WifiAPMode(false);
String log("WIFI : AP Mode ssid will be ");
log=log+WifiGetAPssid();
log=log+F(" with address ");
log=log+apIP.toString();
addLog(LOG_LEVEL_INFO, log);
}
bool WifiIsAP()
{
#if defined(ESP8266)
byte wifimode = wifi_get_opmode();
#endif
#if defined(ESP32)
byte wifimode = WiFi.getMode();
#endif
return(wifimode == 2 || wifimode == 3); //apmode is enabled
}
//********************************************************************************
// Set Wifi AP Mode
//********************************************************************************
void WifiAPMode(boolean state)
{
if (WifiIsAP())
{
//want to disable?
if (!state)
{
WiFi.mode(WIFI_STA);
addLog(LOG_LEVEL_INFO, F("WIFI : AP Mode disabled"));
}
}
else
{
//want to enable?
if (state)
{
WiFi.mode(WIFI_AP_STA);
addLog(LOG_LEVEL_INFO, F("WIFI : AP Mode enabled"));
}
}
}
bool useStaticIP() {
return (Settings.IP[0] != 0 && Settings.IP[0] != 255);
}
bool WiFiConnected() {
// For ESP82xx, do not rely on WiFi.status() with event based wifi.
return wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED;
}
void WiFiConnectRelaxed() {
if (WiFiConnected())
return; //already connected, need to disconnect first
if (prepareWiFi()) {
if (selectValidWiFiSettings()) {
tryConnectWiFi();
return;
}
}
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP!"));
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
setAP(true);
}
//********************************************************************************
// Set Wifi config
//********************************************************************************
bool prepareWiFi() {
if (!selectValidWiFiSettings())
if (!selectValidWiFiSettings()) {
addLog(LOG_LEVEL_ERROR, F("WIFI : No valid wifi settings"));
return false;
}
setSTA(true);
String log = "";
char hostname[40];
strncpy(hostname, WifiGetHostname().c_str(), sizeof(hostname));
@@ -242,35 +448,9 @@ bool prepareWiFi() {
#if defined(ESP32)
WiFi.setHostname(hostname);
#endif
//use static ip?
if (useStaticIP())
{
const IPAddress ip = Settings.IP;
log = F("IP : Static IP :");
log += ip;
addLog(LOG_LEVEL_INFO, log);
const IPAddress gw = Settings.Gateway;
const IPAddress subnet = Settings.Subnet;
const IPAddress dns = Settings.DNS;
WiFi.config(ip, gw, subnet, dns);
}
return true;
}
//********************************************************************************
// Start connect to WiFi and check later to see if connected.
//********************************************************************************
void WiFiConnectRelaxed() {
if (prepareWiFi()) {
tryConnectWiFi();
return;
}
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP! (relaxed connect mode)"));
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
WifiAPMode(true);
}
//********************************************************************************
// Manage WiFi credentials
@@ -304,7 +484,7 @@ bool wifiSettingsValid(const char* ssid, const char* pass) {
if (ssid[0] == 0 || (strcasecmp(ssid, "ssid") == 0)) {
return false;
}
if (pass[0] == 0) return false;
// if (pass[0] == 0) return false; // Allow for empty pass
if (strlen(ssid) > 32) return false;
if (strlen(pass) > 64) return false;
return true;
@@ -316,7 +496,7 @@ bool wifiConnectTimeoutReached() {
// Connection attempt was already ended.
return true;
}
if (wifiSetupConnect) {
if (WifiIsAP(WiFi.getMode())) {
// Initial setup of WiFi, may take much longer since accesspoint is still active.
return timeOutReached(last_wifi_connect_attempt_moment + 20000);
}
@@ -331,29 +511,50 @@ bool wifiConnectTimeoutReached() {
return timeOutReached(last_wifi_connect_attempt_moment + DEFAULT_WIFI_CONNECTION_TIMEOUT + randomOffset_in_sec);
}
void setupStaticIPconfig() {
setUseStaticIP(useStaticIP());
if (!useStaticIP()) return;
const IPAddress ip = Settings.IP;
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);
WiFi.config(ip, gw, subnet, dns);
}
//********************************************************************************
// Simply start the WiFi connection sequence
//********************************************************************************
bool tryConnectWiFi() {
if (wifiSetup && !wifiSetupConnect)
return false;
if (wifiStatus != ESPEASY_WIFI_DISCONNECTED)
return(true); //already connected, need to disconnect first
if (wifiSetupConnect) {
lastWiFiSettings = 0; // Force to load the first settings.
wifi_connect_attempt = 0;
}
if (wifiStatus != ESPEASY_WIFI_DISCONNECTED) {
if (!WifiIsAP(WiFi.getMode())) {
// Only when not in AP mode.
return(true); //already connected, need to disconnect first
}
}
if (!wifiConnectTimeoutReached())
return true; // timeout not reached yet, thus no need to retry again.
if (!selectValidWiFiSettings()) {
addLog(LOG_LEVEL_ERROR, F("WIFI : No valid WiFi settings!"));
return false;
}
if (wifi_connect_attempt != 0 && ((wifi_connect_attempt % 3) == 0)) {
// Change to other wifi settings.
if (selectNextWiFiSettings())
WiFi.disconnect();
if (wifi_connect_attempt != 0 && (wifi_connect_attempt % 2) == 0) {
selectNextWiFiSettings();
}
if (wifi_connect_attempt > 6) {
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
WifiAPMode(true);
if (wifi_connect_attempt > 5) {
setAP(true);
}
const char* ssid = getLastWiFiSettingsSSID();
const char* passphrase = getLastWiFiSettingsPassphrase();
@@ -362,7 +563,7 @@ bool tryConnectWiFi() {
log += F(" attempt #");
log += wifi_connect_attempt;
addLog(LOG_LEVEL_INFO, log);
setupStaticIPconfig();
last_wifi_connect_attempt_moment = millis();
switch (wifi_connect_attempt) {
case 0:
@@ -375,6 +576,7 @@ bool tryConnectWiFi() {
WiFi.begin(ssid, passphrase);
}
++wifi_connect_attempt;
logConnectionStatus();
switch (WiFi.status()) {
case WL_NO_SSID_AVAIL: {
log = F("WIFI : No SSID found matching: ");
@@ -399,7 +601,13 @@ bool tryConnectWiFi() {
//********************************************************************************
void WifiDisconnect()
{
WiFi.disconnect();
#if defined(ESP32)
WiFi.disconnect();
#else
ETS_UART_INTR_DISABLE();
wifi_station_disconnect();
ETS_UART_INTR_ENABLE();
#endif
}
@@ -410,7 +618,7 @@ void WifiScan()
{
// Direct Serial is allowed here, since this function will only be called from serial input.
Serial.println(F("WIFI : SSID Scan start"));
int n = WiFi.scanNetworks();
int n = WiFi.scanNetworks(false, true);
if (n == 0)
Serial.println(F("WIFI : No networks found"));
else
@@ -424,17 +632,110 @@ void WifiScan()
Serial.print(F("WIFI : "));
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(")");
Serial.println("");
Serial.println(formatScanResult(i, " "));
delay(10);
}
}
Serial.println("");
}
String formatScanResult(int i, const String& separator) {
String result = WiFi.SSID(i);
#ifndef ESP32
if (WiFi.isHidden(i)) {
result += F("#Hidden#");
}
#endif
result += separator;
result += WiFi.BSSIDstr(i);
result += separator;
result += F("Ch:");
result += WiFi.channel(i);
result += F(" (");
result += WiFi.RSSI(i);
result += F("dBm) ");
switch (WiFi.encryptionType(i)) {
#ifdef ESP32
case WIFI_AUTH_OPEN: result += F("open"); break;
case WIFI_AUTH_WEP: result += F("WEP"); break;
case WIFI_AUTH_WPA_PSK: result += F("WPA/PSK"); break;
case WIFI_AUTH_WPA2_PSK: result += F("WPA2/PSK"); break;
case WIFI_AUTH_WPA_WPA2_PSK: result += F("WPA/WPA2/PSK"); break;
case WIFI_AUTH_WPA2_ENTERPRISE: result += F("WPA2 Enterprise"); break;
#else
case ENC_TYPE_WEP: result += F("WEP"); break;
case ENC_TYPE_TKIP: result += F("WPA/PSK"); break;
case ENC_TYPE_CCMP: result += F("WPA2/PSK"); break;
case ENC_TYPE_NONE: result += F("open"); break;
case ENC_TYPE_AUTO: result += F("WPA/WPA2/PSK"); break;
#endif
default:
break;
}
return result;
}
#ifndef ESP32
String SDKwifiStatusToString(uint8_t sdk_wifistatus) {
switch (sdk_wifistatus) {
case STATION_IDLE: return F("STATION_IDLE");
case STATION_CONNECTING: return F("STATION_CONNECTING");
case STATION_WRONG_PASSWORD: return F("STATION_WRONG_PASSWORD");
case STATION_NO_AP_FOUND: return F("STATION_NO_AP_FOUND");
case STATION_CONNECT_FAIL: return F("STATION_CONNECT_FAIL");
case STATION_GOT_IP: return F("STATION_GOT_IP");
}
return F("Unknown");
}
#endif
String ArduinoWifiStatusToString(uint8_t arduino_corelib_wifistatus) {
String log;
switch (arduino_corelib_wifistatus) {
case WL_IDLE_STATUS: log += F("WL_IDLE_STATUS"); break;
case WL_NO_SSID_AVAIL: log += F("WL_NO_SSID_AVAIL"); break;
case WL_SCAN_COMPLETED: log += F("WL_SCAN_COMPLETED"); break;
case WL_CONNECTED: log += F("WL_CONNECTED"); break;
case WL_CONNECT_FAILED: log += F("WL_CONNECT_FAILED"); break;
case WL_CONNECTION_LOST: log += F("WL_CONNECTION_LOST"); break;
case WL_DISCONNECTED: log += F("WL_DISCONNECTED"); break;
default: log += arduino_corelib_wifistatus; break;
}
return log;
}
String ESPeasyWifiStatusToString() {
String log;
switch (wifiStatus) {
case ESPEASY_WIFI_DISCONNECTED: log += F("ESPEASY_WIFI_DISCONNECTED"); break;
case ESPEASY_WIFI_CONNECTED: log += F("ESPEASY_WIFI_CONNECTED"); break;
case ESPEASY_WIFI_GOT_IP: log += F("ESPEASY_WIFI_GOT_IP"); break;
case ESPEASY_WIFI_SERVICES_INITIALIZED: log += F("ESPEASY_WIFI_SERVICES_INITIALIZED"); break;
default: log += wifiStatus;
}
return log;
}
void logConnectionStatus() {
const uint8_t arduino_corelib_wifistatus = WiFi.status();
String log;
#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);
}
#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);
}
//********************************************************************************
// Check if we are still connected to a Wifi AP
@@ -444,21 +745,15 @@ void WifiCheck()
if(wifiSetup)
return;
if (wifiStatus == ESPEASY_WIFI_DISCONNECTED)
{
NC_Count++;
WiFiConnectRelaxed();
}
//connected
else
{
C_Count++;
NC_Count = 0;
if (C_Count > 2) // disable AP after timeout if a Wifi connection is established...
{
WifiAPMode(false);
processDisableAPmode();
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) {
if (timeOutReached(last_wifi_connect_attempt_moment + (1000 + wifi_connect_attempt * 200))) {
WiFiConnectRelaxed();
}
}
if (mqtt_reconnect_count > 10) {
connectionCheckHandler();
}
}
//********************************************************************************
@@ -466,7 +761,7 @@ void WifiCheck()
//********************************************************************************
bool getSubnetRange(IPAddress& low, IPAddress& high)
{
if (WifiIsAP()) {
if (WifiIsAP(WiFi.getMode())) {
// WiFi is active as accesspoint, do not check.
return false;
}
@@ -487,36 +782,41 @@ bool getSubnetRange(IPAddress& low, IPAddress& high)
return true;
}
String getLastDisconnectReason() {
String reason = F("(");
reason += lastDisconnectReason;
reason += F(") ");
switch (lastDisconnectReason) {
case WIFI_DISCONNECT_REASON_UNSPECIFIED: return F("Unspecified");
case WIFI_DISCONNECT_REASON_AUTH_EXPIRE: return F("Auth expire");
case WIFI_DISCONNECT_REASON_AUTH_LEAVE: return F("Auth leave");
case WIFI_DISCONNECT_REASON_ASSOC_EXPIRE: return F("Assoc expire");
case WIFI_DISCONNECT_REASON_ASSOC_TOOMANY: return F("Assoc toomany");
case WIFI_DISCONNECT_REASON_NOT_AUTHED: return F("Not authed");
case WIFI_DISCONNECT_REASON_NOT_ASSOCED: return F("Not assoced");
case WIFI_DISCONNECT_REASON_ASSOC_LEAVE: return F("Assoc leave");
case WIFI_DISCONNECT_REASON_ASSOC_NOT_AUTHED: return F("Assoc not authed");
case WIFI_DISCONNECT_REASON_DISASSOC_PWRCAP_BAD: return F("Disassoc pwrcap bad");
case WIFI_DISCONNECT_REASON_DISASSOC_SUPCHAN_BAD: return F("Disassoc supchan bad");
case WIFI_DISCONNECT_REASON_IE_INVALID: return F("IE invalid");
case WIFI_DISCONNECT_REASON_MIC_FAILURE: return F("Mic failure");
case WIFI_DISCONNECT_REASON_4WAY_HANDSHAKE_TIMEOUT: return F("4way handshake timeout");
case WIFI_DISCONNECT_REASON_GROUP_KEY_UPDATE_TIMEOUT: return F("Group key update timeout");
case WIFI_DISCONNECT_REASON_IE_IN_4WAY_DIFFERS: return F("IE in 4way differs");
case WIFI_DISCONNECT_REASON_GROUP_CIPHER_INVALID: return F("Group cipher invalid");
case WIFI_DISCONNECT_REASON_PAIRWISE_CIPHER_INVALID: return F("Pairwise cipher invalid");
case WIFI_DISCONNECT_REASON_AKMP_INVALID: return F("AKMP invalid");
case WIFI_DISCONNECT_REASON_UNSUPP_RSN_IE_VERSION: return F("Unsupp RSN IE version");
case WIFI_DISCONNECT_REASON_INVALID_RSN_IE_CAP: return F("Invalid RSN IE cap");
case WIFI_DISCONNECT_REASON_802_1X_AUTH_FAILED: return F("802 1X auth failed");
case WIFI_DISCONNECT_REASON_CIPHER_SUITE_REJECTED: return F("Cipher suite rejected");
case WIFI_DISCONNECT_REASON_BEACON_TIMEOUT: return F("Beacon timeout");
case WIFI_DISCONNECT_REASON_NO_AP_FOUND: return F("No AP found");
case WIFI_DISCONNECT_REASON_AUTH_FAIL: return F("Auth fail");
case WIFI_DISCONNECT_REASON_ASSOC_FAIL: return F("Assoc fail");
case WIFI_DISCONNECT_REASON_HANDSHAKE_TIMEOUT: return F("Handshake timeout");
case WIFI_DISCONNECT_REASON_UNSPECIFIED: reason += F("Unspecified"); break;
case WIFI_DISCONNECT_REASON_AUTH_EXPIRE: reason += F("Auth expire"); break;
case WIFI_DISCONNECT_REASON_AUTH_LEAVE: reason += F("Auth leave"); break;
case WIFI_DISCONNECT_REASON_ASSOC_EXPIRE: reason += F("Assoc expire"); break;
case WIFI_DISCONNECT_REASON_ASSOC_TOOMANY: reason += F("Assoc toomany"); break;
case WIFI_DISCONNECT_REASON_NOT_AUTHED: reason += F("Not authed"); break;
case WIFI_DISCONNECT_REASON_NOT_ASSOCED: reason += F("Not assoced"); break;
case WIFI_DISCONNECT_REASON_ASSOC_LEAVE: reason += F("Assoc leave"); break;
case WIFI_DISCONNECT_REASON_ASSOC_NOT_AUTHED: reason += F("Assoc not authed"); break;
case WIFI_DISCONNECT_REASON_DISASSOC_PWRCAP_BAD: reason += F("Disassoc pwrcap bad"); break;
case WIFI_DISCONNECT_REASON_DISASSOC_SUPCHAN_BAD: reason += F("Disassoc supchan bad"); break;
case WIFI_DISCONNECT_REASON_IE_INVALID: reason += F("IE invalid"); break;
case WIFI_DISCONNECT_REASON_MIC_FAILURE: reason += F("Mic failure"); break;
case WIFI_DISCONNECT_REASON_4WAY_HANDSHAKE_TIMEOUT: reason += F("4way handshake timeout"); break;
case WIFI_DISCONNECT_REASON_GROUP_KEY_UPDATE_TIMEOUT: reason += F("Group key update timeout"); break;
case WIFI_DISCONNECT_REASON_IE_IN_4WAY_DIFFERS: reason += F("IE in 4way differs"); break;
case WIFI_DISCONNECT_REASON_GROUP_CIPHER_INVALID: reason += F("Group cipher invalid"); break;
case WIFI_DISCONNECT_REASON_PAIRWISE_CIPHER_INVALID: reason += F("Pairwise cipher invalid"); break;
case WIFI_DISCONNECT_REASON_AKMP_INVALID: reason += F("AKMP invalid"); break;
case WIFI_DISCONNECT_REASON_UNSUPP_RSN_IE_VERSION: reason += F("Unsupp RSN IE version"); break;
case WIFI_DISCONNECT_REASON_INVALID_RSN_IE_CAP: reason += F("Invalid RSN IE cap"); break;
case WIFI_DISCONNECT_REASON_802_1X_AUTH_FAILED: reason += F("802 1X auth failed"); break;
case WIFI_DISCONNECT_REASON_CIPHER_SUITE_REJECTED: reason += F("Cipher suite rejected"); break;
case WIFI_DISCONNECT_REASON_BEACON_TIMEOUT: reason += F("Beacon timeout"); break;
case WIFI_DISCONNECT_REASON_NO_AP_FOUND: reason += F("No AP found"); break;
case WIFI_DISCONNECT_REASON_AUTH_FAIL: reason += F("Auth fail"); break;
case WIFI_DISCONNECT_REASON_ASSOC_FAIL: reason += F("Assoc fail"); break;
case WIFI_DISCONNECT_REASON_HANDSHAKE_TIMEOUT: reason += F("Handshake timeout"); break;
default: reason += F("Unknown"); break;
}
return F("Unknown");
return reason;
}
+27
View File
@@ -26,6 +26,9 @@ void hardwareInit()
break;
}
if (Settings.Pin_Reset != -1)
pinMode(Settings.Pin_Reset,INPUT_PULLUP);
// configure hardware pins according to eeprom settings.
if (Settings.Pin_i2c_sda != -1)
{
@@ -97,3 +100,27 @@ void hardwareInit()
}
void checkResetFactoryPin(){
static byte factoryResetCounter=0;
if (Settings.Pin_Reset == -1)
return;
if (digitalRead(Settings.Pin_Reset) == 0){ // active low reset pin
factoryResetCounter++; // just count every second
}
else
{ // reset pin released
if (factoryResetCounter > 9) // factory reset and reboot
ResetFactory();
if (factoryResetCounter > 3) // normal reboot
#if defined(ESP8266)
ESP.reset();
#endif
#if defined(ESP32)
ESP.restart();
#endif
factoryResetCounter = 0; // count was < 3, reset counter
}
}
+459 -71
View File
@@ -332,7 +332,7 @@ void statusLED(boolean traffic)
}
}
//AP mode is active
else if (WifiIsAP())
else if (WifiIsAP(WiFi.getMode()))
{
nStatusValue = ((millis()>>1) & PWMRANGE) - (PWMRANGE>>2); //ramp up for 2 sec, 3/4 luminosity
}
@@ -482,6 +482,22 @@ String BuildFixes()
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.StructSize = sizeof(Settings);
}
Settings.Build = BUILD;
return(SaveSettings());
}
@@ -694,25 +710,42 @@ 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(Settings.md5);
String err;
err=SaveToFile((char*)FILE_CONFIG, 0, (byte*)&Settings, sizeof(struct SettingsStruct));
if (err.length())
return(err);
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(SecuritySettings.md5);
err=SaveToFile((char*)FILE_SECURITY, 0, (byte*)&SecuritySettings, sizeof(struct SecurityStruct));
return (err);
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);
}
/********************************************************************************************\
@@ -729,10 +762,14 @@ String LoadSettings()
if (err.length())
return(err);
md5.begin();
md5.add((uint8_t *)&Settings, sizeof(Settings)-16);
md5.calculate();
md5.getBytes(calculatedMd5);
// 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)
@@ -741,7 +778,7 @@ String LoadSettings()
else{
addLog(LOG_LEVEL_ERROR, F("CRC : Settings CRC ...FAIL"));
}
*/
err=LoadFromFile((char*)FILE_SECURITY, 0, (byte*)&SecuritySettings, sizeof( SecurityStruct));
md5.begin();
@@ -756,6 +793,7 @@ String LoadSettings()
else{
addLog(LOG_LEVEL_ERROR, F("CRC : SecuritySettings CRC ...FAIL"));
}
setUseStaticIP(useStaticIP());
return(err);
}
@@ -766,6 +804,11 @@ String LoadSettings()
String SaveTaskSettings(byte TaskIndex)
{
checkRAM(F("SaveTaskSettings"));
if (DAT_TASKS_SIZE < sizeof(struct ExtraTaskSettingsStruct))
return F("SaveTaskSettings too big");
if (TaskIndex >= TASKS_MAX)
return F("SaveTaskSettings TaskIndex too big");
ExtraTaskSettings.TaskIndex = TaskIndex;
return(SaveToFile((char*)FILE_CONFIG, DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE), (byte*)&ExtraTaskSettings, sizeof(struct ExtraTaskSettingsStruct)));
}
@@ -780,6 +823,8 @@ String LoadTaskSettings(byte TaskIndex)
//already loaded
if (ExtraTaskSettings.TaskIndex == TaskIndex)
return(String());
if (TaskIndex >= TASKS_MAX)
return F("LoadTaskSettings TaskIndex too big");
String result = "";
result = LoadFromFile((char*)FILE_CONFIG, DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE), (byte*)&ExtraTaskSettings, sizeof(struct ExtraTaskSettingsStruct));
@@ -796,6 +841,9 @@ String SaveCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
checkRAM(F("SaveCustomTaskSettings"));
if (datasize > DAT_TASKS_SIZE)
return F("SaveCustomTaskSettings too big");
if (TaskIndex >= TASKS_MAX)
return F("SaveCustomTaskSettings TaskIndex too big");
return(SaveToFile((char*)FILE_CONFIG, DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE) + DAT_TASKS_CUSTOM_OFFSET, memAddress, datasize));
}
@@ -806,7 +854,9 @@ String SaveCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
String ClearCustomTaskSettings(int TaskIndex)
{
// addLog(LOG_LEVEL_DEBUG, F("Clearing custom task settings"));
return(ClearInFile((char*)FILE_CONFIG, DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE) + DAT_TASKS_CUSTOM_OFFSET, DAT_TASKS_SIZE));
if (TaskIndex >= TASKS_MAX)
return F("ClearCustomTaskSettings TaskIndex too big");
return(ClearInFile((char*)FILE_CONFIG, DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE) + DAT_TASKS_CUSTOM_OFFSET, DAT_TASKS_CUSTOM_SIZE));
}
/********************************************************************************************\
@@ -817,6 +867,9 @@ String LoadCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
checkRAM(F("LoadCustomTaskSettings"));
if (datasize > DAT_TASKS_SIZE)
return (String(F("LoadCustomTaskSettings too big")));
if (TaskIndex >= TASKS_MAX)
return F("LoadCustomTaskSettings TaskIndex too big");
return(LoadFromFile((char*)FILE_CONFIG, DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE) + DAT_TASKS_CUSTOM_OFFSET, memAddress, datasize));
}
@@ -933,6 +986,13 @@ String SaveToFile(char* fname, int index, byte* memAddress, int datasize)
{
checkRAM(F("SaveToFile"));
FLASH_GUARD();
String log = F("SaveToFile: ");
log += fname;
log += F(" index: ");
log += index;
log += F(" datasize: ");
log += datasize;
addLog(LOG_LEVEL_DEBUG, log);
fs::File f = SPIFFS.open(fname, "r+");
SPIFFS_CHECK(f, fname);
@@ -945,7 +1005,7 @@ String SaveToFile(char* fname, int index, byte* memAddress, int datasize)
pointerToByteToSave++;
}
f.close();
String log = F("FILE : Saved ");
log = F("FILE : Saved ");
log=log+fname;
addLog(LOG_LEVEL_INFO, log);
@@ -961,6 +1021,15 @@ String ClearInFile(char* fname, int index, int datasize)
checkRAM(F("ClearInFile"));
FLASH_GUARD();
String log = F("ClearInFile: ");
log += fname;
log += F(" index: ");
log += index;
log += F(" datasize: ");
log += datasize;
addLog(LOG_LEVEL_DEBUG, log);
fs::File f = SPIFFS.open(fname, "r+");
SPIFFS_CHECK(f, fname);
@@ -982,6 +1051,13 @@ String ClearInFile(char* fname, int index, int datasize)
String LoadFromFile(char* fname, int index, byte* memAddress, int datasize)
{
checkRAM(F("LoadFromFile"));
String log = F("LoadFromFile: ");
log += fname;
log += F(" index: ");
log += index;
log += F(" datasize: ");
log += datasize;
addLog(LOG_LEVEL_DEBUG, log);
fs::File f = SPIFFS.open(fname, "r+");
SPIFFS_CHECK(f, fname);
@@ -1090,11 +1166,12 @@ void ResetFactory(void)
SecuritySettings.IPblockLevel = DEFAULT_IP_BLOCK_LEVEL;
Settings.Delay = DEFAULT_DELAY;
Settings.Pin_i2c_sda = 4;
Settings.Pin_i2c_scl = 5;
Settings.Pin_status_led = -1;
Settings.Pin_status_led_Inversed = true;
Settings.Pin_i2c_sda = DEFAULT_PIN_I2C_SDA;
Settings.Pin_i2c_scl = DEFAULT_PIN_I2C_SCL;
Settings.Pin_status_led = DEFAULT_PIN_STATUS_LED;
Settings.Pin_status_led_Inversed = DEFAULT_PIN_STATUS_LED_INVERSED;
Settings.Pin_sd_cs = -1;
Settings.Pin_Reset = -1;
Settings.Protocol[0] = DEFAULT_PROTOCOL;
strcpy_P(Settings.Name, PSTR(DEFAULT_NAME));
Settings.deepSleep = false;
@@ -1128,6 +1205,7 @@ void ResetFactory(void)
Settings.SyslogLevel = DEFAULT_SYSLOG_LEVEL;
Settings.SerialLogLevel = DEFAULT_SERIAL_LOG_LEVEL;
Settings.SyslogFacility = DEFAULT_SYSLOG_FACILITY;
Settings.WebLogLevel = DEFAULT_WEB_LOG_LEVEL;
Settings.SDLogLevel = DEFAULT_SD_LOG_LEVEL;
Settings.UseValueLogger = DEFAULT_USE_SD_LOG;
@@ -1168,7 +1246,7 @@ void ResetFactory(void)
delay(1000);
WiFi.persistent(true); // use SDK storage of SSID/WPA parameters
intent_to_reboot = true;
WiFi.disconnect(); // this will store empty ssid/wpa into sdk storage
WifiDisconnect(); // this will store empty ssid/wpa into sdk storage
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
#if defined(ESP8266)
ESP.reset();
@@ -1213,6 +1291,78 @@ unsigned long FreeMem(void)
#endif
}
/********************************************************************************************\
Get system information
\*********************************************************************************************/
String getLastBootCauseString() {
switch (lastBootCause)
{
case BOOT_CAUSE_MANUAL_REBOOT: return F("Manual reboot");
case BOOT_CAUSE_DEEP_SLEEP: //nobody should ever see this, since it should sleep again right away.
return F("Deep sleep");
case BOOT_CAUSE_COLD_BOOT:
return F("Cold boot");
case BOOT_CAUSE_EXT_WD:
return F("External Watchdog");
}
return F("Unknown");
}
String getSystemBuildString() {
String result;
result += BUILD;
result += F(" ");
result += F(BUILD_NOTES);
return result;
}
String getPluginDescriptionString() {
String result;
#ifdef PLUGIN_BUILD_NORMAL
result += F(" [Normal]");
#endif
#ifdef PLUGIN_BUILD_TESTING
result += F(" [Testing]");
#endif
#ifdef PLUGIN_BUILD_DEV
result += F(" [Development]");
#endif
return result;
}
String getSystemLibraryString() {
String result;
#if defined(ESP32)
result += F("ESP32 SDK ");
result += ESP.getSdkVersion();
#else
result += F("ESP82xx Core ");
result += ESP.getCoreVersion();
result += F(", NONOS SDK ");
result += system_get_sdk_version();
result += F(", LWIP: ");
result += getLWIPversion();
#endif
return result;
}
#ifndef ESP32
String getLWIPversion() {
String result;
result += LWIP_VERSION_MAJOR;
result += F(".");
result += LWIP_VERSION_MINOR;
result += F(".");
result += LWIP_VERSION_REVISION;
if (LWIP_VERSION_IS_RC) {
result += F("-RC");
result += LWIP_VERSION_RC;
} else if (LWIP_VERSION_IS_DEVELOPMENT) {
result += F("-dev");
}
return result;
}
#endif
/********************************************************************************************\
Check if string is valid float
@@ -1279,6 +1429,7 @@ void initLog()
//make sure addLog doesnt do any stuff before initalisation of Settings is complete.
Settings.UseSerial=true;
Settings.SyslogLevel=0;
Settings.SyslogFacility=0;
Settings.SerialLogLevel=2; //logging during initialisation
Settings.WebLogLevel=2;
Settings.SDLogLevel=0;
@@ -1287,6 +1438,19 @@ void initLog()
/********************************************************************************************\
Logging
\*********************************************************************************************/
String getLogLevelDisplayString(byte index, int& logLevel) {
switch (index) {
case 0: logLevel = LOG_LEVEL_ERROR; return F("Error");
case 1: logLevel = LOG_LEVEL_INFO; return F("Info");
case 2: logLevel = LOG_LEVEL_DEBUG; return F("Debug");
case 3: logLevel = LOG_LEVEL_DEBUG_MORE; return F("Debug More");
case 4: logLevel = LOG_LEVEL_DEBUG_DEV; return F("Debug dev");
default: logLevel = -1; return "";
}
}
void addLog(byte loglevel, String& string)
{
addLog(loglevel, string.c_str());
@@ -1313,6 +1477,8 @@ boolean loglevelActiveFor(byte destination, byte logLevel) {
case LOG_TO_SERIAL: {
if (!SerialAvailableForWrite()) return false;
logLevelSettings = Settings.SerialLogLevel;
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED)
logLevelSettings = 2;
break;
}
case LOG_TO_SYSLOG: {
@@ -1341,13 +1507,15 @@ boolean loglevelActive(byte logLevel, byte logLevelSettings) {
void addLog(byte logLevel, const char *line)
{
if (loglevelActiveFor(LOG_TO_SERIAL, logLevel)) {
Serial.print(millis());
Serial.print(F(" : "));
Serial.println(line);
}
if (loglevelActiveFor(LOG_TO_SYSLOG, logLevel)) {
syslog(line);
syslog(logLevel, line);
}
if (loglevelActiveFor(LOG_TO_WEBLOG, logLevel)) {
Logging.add(line);
Logging.add(logLevel, line);
}
#ifdef FEATURE_SD
@@ -1549,35 +1717,217 @@ String parseTemplate(String &tmpString, byte lineSize)
{
// here we know the task and value, so find the uservar
match = true;
String value = "";
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[y]);
if (Device[DeviceIndex].VType == SENSOR_TYPE_LONG)
value = (unsigned long)UserVar[y * VARS_PER_TASK + z] + ((unsigned long)UserVar[y * VARS_PER_TASK + z + 1] << 16);
else
value = toString(UserVar[y * VARS_PER_TASK + z], ExtraTaskSettings.TaskDeviceValueDecimals[z]);
bool isvalid;
String value = formatUserVar(y, z, isvalid);
if (isvalid) {
// start changes by giig1967g - 2018-04-20
// Syntax: [task#value#transformation#justification]
// valueFormat="transformation#justification"
if (valueFormat.length() > 0) //do the checks only if a Format is defined to optimize loop
{
String valueJust = "";
int oidx;
if ((oidx = valueFormat.indexOf('O')) >= 0) // Output
{
valueFormat.remove(oidx);
oidx = valueFormat.indexOf('!'); // inverted or active low
float val = value.toFloat();
if (oidx >= 0) {
valueFormat.remove(oidx);
value = val == 0 ? " ON" : "OFF";
} else {
value = val == 0 ? "OFF" : " ON";
hashtagIndex = valueFormat.indexOf('#');
if (hashtagIndex >= 0)
{
valueJust = valueFormat.substring(hashtagIndex + 1); //Justification part
valueFormat = valueFormat.substring(0, hashtagIndex); //Transformation part
}
// valueFormat="transformation"
// valueJust="justification"
if (valueFormat.length() > 0) //do the checks only if a Format is defined to optimize loop
{
const int val = value == "0" ? 0 : 1; //to be used for GPIO status (0 or 1)
const float valFloat = value.toFloat();
String tempValueFormat = valueFormat;
const int tempValueFormatLength = tempValueFormat.length();
const int invertedIndex = tempValueFormat.indexOf('!');
const bool inverted = invertedIndex >= 0 ? 1 : 0;
if (inverted)
tempValueFormat.remove(invertedIndex,1);
const int rightJustifyIndex = tempValueFormat.indexOf('R');
const bool rightJustify = rightJustifyIndex >= 0 ? 1 : 0;
if (rightJustify)
tempValueFormat.remove(rightJustifyIndex,1);
//Check Transformation syntax
if (tempValueFormatLength > 0)
{
switch (tempValueFormat[0])
{
case 'V': //value = value without transformations
break;
case 'O':
value = val == inverted ? F("OFF") : F(" ON"); //(equivalent to XOR operator)
break;
case 'C':
value = val == inverted ? F("CLOSE") : F(" OPEN");
break;
case 'M':
value = val == inverted ? F("AUTO") : F(" MAN");
break;
case 'm':
value = val == inverted ? F("A") : F("M");
break;
case 'H':
value = val == inverted ? F("COLD") : F(" HOT");
break;
case 'U':
value = val == inverted ? F("DOWN") : F(" UP");
break;
case 'u':
value = val == inverted ? F("D") : F("U");
break;
case 'Y':
value = val == inverted ? F(" NO") : F("YES");
break;
case 'y':
value = val == inverted ? F("N") : F("Y");
break;
case 'X':
value = val == inverted ? F("O") : F("X");
break;
case 'I':
value = val == inverted ? F("OUT") : F(" IN");
break;
case 'Z' :// return "0" or "1"
value = val == inverted ? F("0") : F("1");
break;
case 'D' ://Dx.y min 'x' digits zero filled & 'y' decimal fixed digits
{
int x;
int y;
x = 0;
y = 0;
switch (tempValueFormatLength)
{
case 2: //Dx
if (isDigit(tempValueFormat[1]))
{
x = (int)tempValueFormat[1]-'0';
}
break;
case 3: //D.y
if (tempValueFormat[1]=='.' && isDigit(tempValueFormat[2]))
{
y = (int)tempValueFormat[2]-'0';
}
break;
case 4: //Dx.y
if (isDigit(tempValueFormat[1]) && tempValueFormat[2]=='.' && isDigit(tempValueFormat[3]))
{
x = (int)tempValueFormat[1]-'0';
y = (int)tempValueFormat[3]-'0';
}
break;
case 1: //D
default: //any other combination x=0; y=0;
break;
}
value = toString(valFloat,y);
int indexDot;
indexDot = value.indexOf('.') > 0 ? value.indexOf('.') : value.length();
for (byte f = 0; f < (x - indexDot); f++)
value = "0" + value;
break;
}
case 'F' :// FLOOR (round down)
value = (int)floorf(valFloat);
break;
case 'E' :// CEILING (round up)
value = (int)ceilf(valFloat);
break;
default:
value = F("ERR");
break;
}
// Check Justification syntax
const int valueJustLength = valueJust.length();
if (valueJustLength > 0) //do the checks only if a Justification is defined to optimize loop
{
value.trim(); //remove right justification spaces for backward compatibility
switch (valueJust[0])
{
case 'P' :// Prefix Fill with n spaces: Pn
if (valueJustLength > 1)
{
if (isDigit(valueJust[1])) //Check Pn where n is between 0 and 9
{
int filler = valueJust[1] - value.length() - '0' ; //char '0' = 48; char '9' = 58
for (byte f = 0; f < filler; f++)
newString += " ";
}
}
break;
case 'S' :// Suffix Fill with n spaces: Sn
if (valueJustLength > 1)
{
if (isDigit(valueJust[1])) //Check Sn where n is between 0 and 9
{
int filler = valueJust[1] - value.length() - '0' ; //48
for (byte f = 0; f < filler; f++)
value += " ";
}
}
break;
case 'L': //left part of the string
if (valueJustLength > 1)
{
if (isDigit(valueJust[1])) //Check n where n is between 0 and 9
{
value = value.substring(0,(int)valueJust[1]-'0');
}
}
break;
case 'R': //Right part of the string
if (valueJustLength > 1)
{
if (isDigit(valueJust[1])) //Check n where n is between 0 and 9
{
value = value.substring(std::max(0,(int)value.length()-((int)valueJust[1]-'0')));
}
}
break;
case 'U': //Substring Ux.y where x=firstChar and y=number of characters
if (valueJustLength > 1)
{
if (isDigit(valueJust[1]) && valueJust[2]=='.' && isDigit(valueJust[3]) && valueJust[1] > '0' && valueJust[3] > '0')
{
value = value.substring(std::min((int)value.length(),(int)valueJust[1]-'0'-1),(int)valueJust[1]-'0'-1+(int)valueJust[3]-'0');
}
else
{
newString += F("ERR");
}
}
break;
default:
newString += F("ERR");
break;
}
}
if (rightJustify)
{
int filler = lineSize - newString.length() - value.length() - tmpString.length() ;
for (byte f = 0; f < filler; f++)
newString += " ";
}
}
addLog(LOG_LEVEL_DEBUG,"DEBUG: Formatted String='"+newString+value+"'");
}
}
}
//end of changes by giig1967g - 2018-04-18
if (valueFormat == "R")
{
int filler = lineSize - newString.length() - value.length() - tmpString.length() ;
for (byte f = 0; f < filler; f++)
newString += " ";
newString += String(value);
addLog(LOG_LEVEL_DEBUG_DEV,"DEBUG DEV: Parsed String='"+newString+"'");
break;
}
newString += String(value);
break;
}
if (!match) // try if this is a get config request
{
@@ -1981,6 +2331,7 @@ String rulesProcessingFile(String fileName, String& event)
boolean conditional = false;
boolean condition = false;
boolean ifBranche = false;
boolean ifBrancheJustMatch = false;
byte buf[RULES_BUFFER_SIZE];
int len = 0;
@@ -2074,25 +2425,57 @@ String rulesProcessingFile(String fileName, String& event)
if (match) // rule matched for one action or a block of actions
{
int split = lcAction.indexOf("if "); // check for optional "if" condition
if (split != -1)
boolean elseif = lcAction.startsWith("elseif ");
if (elseif == false && split != -1)
{
conditional = true;
String check = lcAction.substring(split + 3);
condition = conditionMatchExtended(check);
log = F("[if ");
log += check;
log += "]=";
condition = ifBrancheJustMatch == false && conditionMatchExtended(check);
if(condition == true)
{
ifBrancheJustMatch = true;
}
ifBranche = true;
isCommand = false;
log += condition ? F("true") : F("false");
addLog(LOG_LEVEL_DEBUG, log);
}
if(elseif)
{
String check = lcAction.substring(7);
log = F("[elseif ");
log += check;
log += "]=";
condition = ifBrancheJustMatch == false && conditionMatchExtended(check);
if(condition == true)
{
ifBrancheJustMatch = true;
}
ifBranche = true;
isCommand = false;
log += condition ? F("true") : F("false");
addLog(LOG_LEVEL_DEBUG, log);
}
if (lcAction == "else") // in case of an "else" block of actions, set ifBranche to false
{
ifBranche = false;
isCommand = false;
log = F("else = ");
log += (conditional && (condition == ifBranche)) ? F("true") : F("false");
addLog(LOG_LEVEL_DEBUG, log);
}
if (lcAction == "endif") // conditional block ends here
{
conditional = false;
isCommand = false;
ifBranche = false;
ifBrancheJustMatch = false;
}
// process the action if it's a command and unconditional, or conditional and the condition matches the if or else block.
@@ -2142,7 +2525,7 @@ String rulesProcessingFile(String fileName, String& event)
nestingLevel--;
checkRAM(F("rulesProcessingFile2"));
return (String());
return (F(""));
}
@@ -2409,11 +2792,11 @@ void rulesTimers()
{
for (byte x = 0; x < RULES_TIMER_MAX; x++)
{
if (RulesTimer[x] != 0L) // timer active?
if (!RulesTimer[x].paused && RulesTimer[x].timestamp != 0L) // timer active?
{
if (timeOutReached(RulesTimer[x])) // timer finished?
if (timeOutReached(RulesTimer[x].timestamp)) // timer finished?
{
RulesTimer[x] = 0L; // turn off this timer
RulesTimer[x].timestamp = 0L; // turn off this timer
String event = F("Rules#Timer=");
event += x + 1;
rulesProcessing(event);
@@ -2455,9 +2838,7 @@ void SendValueLogger(byte TaskIndex)
String logger;
LoadTaskSettings(TaskIndex);
byte BaseVarIndex = TaskIndex * VARS_PER_TASK;
byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[TaskIndex]);
byte sensorType = Device[DeviceIndex].VType;
for (byte varNr = 0; varNr < Device[DeviceIndex].ValueCount; varNr++)
{
logger += getDateString('-');
@@ -2470,11 +2851,7 @@ void SendValueLogger(byte TaskIndex)
logger += F(",");
logger += ExtraTaskSettings.TaskDeviceValueNames[varNr];
logger += F(",");
if (sensorType == SENSOR_TYPE_LONG)
logger += (unsigned long)UserVar[BaseVarIndex] + ((unsigned long)UserVar[BaseVarIndex + 1] << 16);
else
logger += String(UserVar[BaseVarIndex + varNr], ExtraTaskSettings.TaskDeviceValueDecimals[varNr]);
logger += formatUserVarNoCheck(TaskIndex, varNr);
logger += F("\r\n");
}
@@ -2605,7 +2982,7 @@ void checkRAM( String &a ) {
}
#ifdef PLUGIN_BUILD_TESTING
//#ifdef PLUGIN_BUILD_TESTING
#define isdigit(n) (n >= '0' && n <= '9')
@@ -2613,11 +2990,15 @@ void checkRAM( String &a ) {
Generate a tone of specified frequency on pin
\*********************************************************************************************/
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) {
analogWriteFreq(frequency);
//NOTE: analogwrite reserves IRAM and uninitalized ram.
analogWrite(_pin,100);
delay(duration);
analogWrite(_pin,0);
#ifdef ESP32
delay(duration);
#else
analogWriteFreq(frequency);
//NOTE: analogwrite reserves IRAM and uninitalized ram.
analogWrite(_pin,100);
delay(duration);
analogWrite(_pin,0);
#endif
}
/********************************************************************************************\
@@ -2779,7 +3160,7 @@ void play_rtttl(uint8_t _pin, const char *p )
checkRAM(F("play_rtttl2"));
}
#endif
//#endif
#ifdef FEATURE_ARDUINO_OTA
@@ -2790,9 +3171,16 @@ void play_rtttl(uint8_t _pin, const char *p )
void ArduinoOTAInit()
{
checkRAM(F("ArduinoOTAInit"));
#if defined(ESP8266)
// Default port is 8266
ArduinoOTA.setPort(8266);
ArduinoOTA.setHostname(Settings.Name);
#endif
#if defined(ESP32)
ArduinoOTA.setPort(3232);
#endif
ArduinoOTA.setHostname(Settings.Name);
if (SecuritySettings.Password[0]!=0)
ArduinoOTA.setPassword(SecuritySettings.Password);
+224
View File
@@ -0,0 +1,224 @@
# ifndef MODBUS_H
# define MODBUS_H
enum MODBUS_states_t {MODBUS_IDLE, MODBUS_RECEIVE, MODBUS_RECEIVE_PAYLOAD};
enum MODBUS_registerTypes_t {signed16, unsigned16, signed32, unsigned32, signed64, unsigned64};
#define MODBUS_FUNCTION_READ 4
class Modbus
{
public:
Modbus(void);
bool handle();
bool begin(uint8_t function, uint8_t ModbusID, uint16_t ModbusRegister, MODBUS_registerTypes_t type, char* IPaddress);
double read() {
if (resultReceived) {
resultReceived = false;
return result;
}
else
return -1;
};
bool available() {
return resultReceived;
};
unsigned int getReadErrors() {
return errcnt;
};
void resetReadErrors() {
errcnt = 0;
};
void stop() {
TXRXstate = MODBUS_IDLE;
handle();
};
bool tryRead (uint8_t ModbusID, uint16_t M_register, MODBUS_registerTypes_t type, char* IPaddress, double &result);
private:
WiFiClient *ModbusClient; // pointer to tcp client
unsigned int errcnt;
char sendBuffer[12] = {0, 1, 0, 0, 0, 6, 0x7e, 4, 0x9d, 7, 0, 1};
String LogString = ""; // for debug logging
unsigned long timeout; // send and read timeout
MODBUS_states_t TXRXstate;// state for handle() state machine
unsigned int RXavailable;
unsigned int payLoad; // number of bytes to receive as payload. Payload may come as seperate frame.
bool hasTimeout();
MODBUS_registerTypes_t incomingValue; // how to interpret the incoming value
double result; // incoming value, converted to double
bool resultReceived; // incoming value is valid ?
bool isBusy(void) {
return TXRXstate != MODBUS_IDLE;
};
uint16_t currentRegister;
uint8_t currentFunction;
};
#endif
Modbus::Modbus() : ModbusClient(nullptr), errcnt(0), timeout(0),
TXRXstate(MODBUS_IDLE), RXavailable(0), payLoad(0) {}
bool Modbus::begin(uint8_t function, uint8_t ModbusID, uint16_t ModbusRegister, MODBUS_registerTypes_t type, char* IPaddress)
{
currentRegister = ModbusRegister;
currentFunction = function;
incomingValue = type;
resultReceived = false;
ModbusClient = new WiFiClient();
ModbusClient->setNoDelay(true);
ModbusClient->setTimeout(200);
timeout = millis();
ModbusClient->flush();
if (ModbusClient->connected()) {
LogString += F(" already connected. ");
} else {
LogString += F("connect: "); LogString += IPaddress;
if ( !ModbusClient->connect(IPaddress, 502)) {
LogString += F(" fail. ");
TXRXstate = MODBUS_IDLE;
errcnt++;
if (LogString.length() > 1 ) addLog(LOG_LEVEL_DEBUG, LogString);
return false;
}
}
LogString += F(" OK, sending read request: ");
sendBuffer[6] = ModbusID ;
sendBuffer[7] = function;
sendBuffer[8] = (ModbusRegister >> 8) ;
sendBuffer[9] = (ModbusRegister & 0x00ff) ;
if ((incomingValue == signed64) || (incomingValue == unsigned64))
sendBuffer[11] = 4;
if ((incomingValue == signed32) || (incomingValue == unsigned32))
sendBuffer[11] = 2;
if ((incomingValue == signed16) || (incomingValue == unsigned16))
sendBuffer[11] = 1;
ModbusClient->flush();
ModbusClient->write(&sendBuffer[0], sizeof(sendBuffer));
for (unsigned int i = 0; i < sizeof(sendBuffer); i++) {
LogString += ((unsigned int)(sendBuffer[i]));
LogString += (" ");
}
TXRXstate = MODBUS_RECEIVE;
if (LogString.length() > 1 ) addLog(LOG_LEVEL_DEBUG, LogString);
return true;
}
bool Modbus::handle() {
unsigned int RXavailable = 0;
LogString = "";
int64_t rxValue = 0;
switch ( TXRXstate ) {
case MODBUS_IDLE:
// clean up;
if (ModbusClient) {
ModbusClient->flush();
ModbusClient->stop();
delete (ModbusClient);
delay(1);
ModbusClient = nullptr;
}
break;
case MODBUS_RECEIVE:
if (hasTimeout()) break;
if (ModbusClient->available() < 9) break;
LogString += F("reading bytes: ");
for (int a = 0; a < 9; a++) {
payLoad = ModbusClient->read();
LogString += (payLoad); LogString += F(" ");
}
LogString += F("> ");
if (payLoad > 8) {
LogString += "Payload too large !? ";
errcnt++;
TXRXstate = MODBUS_IDLE;
}
case MODBUS_RECEIVE_PAYLOAD:
if (hasTimeout()) break;
RXavailable = ModbusClient->available();
if (payLoad != RXavailable) {
TXRXstate = MODBUS_RECEIVE_PAYLOAD;
break;
}
for (unsigned int i = 0; i < RXavailable; i++) {
rxValue = rxValue << 8;
char a = ModbusClient->read();
rxValue = rxValue | a;
LogString += ((int)a); LogString += (" ");
}
switch (incomingValue) {
case signed16:
result = (int16_t) rxValue;
break;
case unsigned16:
result = (uint16_t) rxValue;
break;
case signed32:
result = (int32_t) rxValue;
break;
case unsigned32:
result = (uint32_t) rxValue;
break;
case signed64:
result = (int64_t) rxValue;
break;
case unsigned64:
result = (uint64_t) rxValue;
break;
}
LogString += "value: "; LogString += result;
//if ((Settings.UseNTP) && (hour() == 0)) errcnt = 0;
TXRXstate = MODBUS_IDLE;
resultReceived = true;
break;
default:
LogString += F("default. ");
TXRXstate = MODBUS_IDLE;
break;
}
if (LogString.length() > 1 ) addLog(LOG_LEVEL_DEBUG, LogString);
return true;
}
bool Modbus::hasTimeout()
{
if ( (millis() - timeout) > 10000) { // too many bytes or timeout
LogString += F("Modbus RX timeout. "); LogString += String(ModbusClient->available());
errcnt++;
TXRXstate = MODBUS_IDLE;
return true;
}
return false;
}
// tryread can be called in a round robin fashion. It will initiate a read if Modbus is idle and update the result once it is available.
// subsequent calls (if Modbus is busy etc. ) will return false and not update the result.
// Use to read multiple values non blocking in an re-entrant function. Not tested yet.
bool Modbus::tryRead (uint8_t ModbusID, uint16_t M_register, MODBUS_registerTypes_t type, char* IPaddress, double &result) {
if (isBusy()) return false; // not done yet
if (available()) {
if ((currentFunction == MODBUS_FUNCTION_READ ) && (currentRegister == M_register)) {
result = read(); // result belongs to this request.
return true;
}
} else {
begin(MODBUS_FUNCTION_READ, ModbusID, M_register, type, IPaddress); // idle and no result -> begin read request
}
return false;
}
+25 -8
View File
@@ -2,15 +2,15 @@
// Syslog
// UDP system messaging
// SSDP
#if LWIP_VERSION_MAJOR == 2
#define IP2STR(addr) (uint8_t)((uint32_t)addr & 0xFF), (uint8_t)(((uint32_t)addr >> 8) & 0xFF), (uint8_t)(((uint32_t)addr >> 16) & 0xFF), (uint8_t)(((uint32_t)addr >> 24) & 0xFF)
#endif
// #if LWIP_VERSION_MAJOR == 2
#define IPADDR2STR(addr) (uint8_t)((uint32_t)addr & 0xFF), (uint8_t)(((uint32_t)addr >> 8) & 0xFF), (uint8_t)(((uint32_t)addr >> 16) & 0xFF), (uint8_t)(((uint32_t)addr >> 24) & 0xFF)
// #endif
/*********************************************************************************************\
Syslog client
\*********************************************************************************************/
void syslog(const char *message)
void syslog(byte logLevel, const char *message)
{
if (Settings.Syslog_IP[0] != 0 && wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED)
{
@@ -18,10 +18,18 @@ void syslog(const char *message)
portUDP.beginPacket(broadcastIP, 514);
char str[256];
str[0] = 0;
byte prio = Settings.SyslogFacility * 8;
if ( logLevel == LOG_LEVEL_ERROR )
prio += 3; // syslog error
else if ( logLevel == LOG_LEVEL_INFO )
prio += 5; // syslog notice
else
prio += 7;
// An RFC3164 compliant message must be formated like : "<PRIO>[TimeStamp ]Hostname TaskName: Message"
// Using Settings.Name as the Hostname (Hostname must NOT content space)
snprintf_P(str, sizeof(str), PSTR("<7>%s EspEasy: %s"), Settings.Name, message);
snprintf_P(str, sizeof(str), PSTR("<%u>%s EspEasy: %s"), prio, Settings.Name, message);
// Using Setting.Unit to build a Hostname
//snprintf_P(str, sizeof(str), PSTR("<7>EspEasy_%u ESP: %s"), Settings.Unit, message);
@@ -434,7 +442,7 @@ void SSDP_send(byte method) {
SSDP_INTERVAL,
Settings.Build,
uuid,
IP2STR(&ip)
IPADDR2STR(&ip)
);
_server->append(buffer, len);
@@ -599,7 +607,7 @@ bool WiFiConnected(uint32_t timeout_ms) {
// Apparently something needs network, perform check to see if it is ready now.
// if (!tryConnectWiFi())
// return false;
while (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) {
while (!WiFiConnected()) {
if (timeOutReached(timer)) {
return false;
}
@@ -609,6 +617,7 @@ bool WiFiConnected(uint32_t timeout_ms) {
}
bool hostReachable(const IPAddress& ip) {
if (!WiFiConnected()) return false;
// Only do 1 ping at a time to return early
byte retry = 3;
while (retry > 0) {
@@ -624,13 +633,21 @@ bool hostReachable(const IPAddress& ip) {
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."));
WifiDisconnect();
}
logConnectionStatus();
return false;
}
bool hostReachable(const String& hostname) {
if (!WiFiConnected()) return false;
IPAddress remote_addr;
if (WiFi.hostByName(hostname.c_str(), remote_addr))
if (WiFi.hostByName(hostname.c_str(), remote_addr)) {
return hostReachable(remote_addr);
}
String log = F("Hostname cannot be resolved: ");
log += hostname;
addLog(LOG_LEVEL_ERROR, log);
+64 -10
View File
@@ -54,6 +54,12 @@ void formatMAC(const uint8_t* mac, char (&strMAC)[20]) {
sprintf_P(strMAC, PSTR("%02X:%02X:%02X:%02X:%02X:%02X"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
String formatMAC(const uint8_t* mac) {
char str[20];
formatMAC(mac, str);
return String(str);
}
/*********************************************************************************************\
Workaround for removing trailing white space when String() converts a float with 0 decimals
\*********************************************************************************************/
@@ -67,12 +73,27 @@ String toString(float value, byte decimals)
/*********************************************************************************************\
Format a value to the set number of decimals
\*********************************************************************************************/
String formatUserVar(struct EventStruct *event, byte rel_index)
{
float f(UserVar[event->BaseVarIndex + rel_index]);
if (!isValidFloat(f)) {
String doFormatUserVar(byte TaskIndex, byte rel_index, bool mustCheck, bool& isvalid) {
isvalid = true;
const byte BaseVarIndex = TaskIndex * VARS_PER_TASK;
const byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[TaskIndex]);
if (Device[DeviceIndex].ValueCount <= rel_index) {
isvalid = false;
String log = F("No sensor value for TaskIndex: ");
log += TaskIndex;
log += F(" varnumber: ");
log += rel_index;
addLog(LOG_LEVEL_ERROR, log);
return "";
}
if (Device[DeviceIndex].VType == SENSOR_TYPE_LONG) {
return String((unsigned long)UserVar[BaseVarIndex] + ((unsigned long)UserVar[BaseVarIndex + 1] << 16));
}
float f(UserVar[BaseVarIndex + rel_index]);
if (mustCheck && !isValidFloat(f)) {
isvalid = false;
String log = F("Invalid float value for TaskIndex: ");
log += event->TaskIndex;
log += TaskIndex;
log += F(" varnumber: ");
log += rel_index;
addLog(LOG_LEVEL_DEBUG, log);
@@ -81,6 +102,25 @@ String formatUserVar(struct EventStruct *event, byte rel_index)
return toString(f, ExtraTaskSettings.TaskDeviceValueDecimals[rel_index]);
}
String formatUserVarNoCheck(byte TaskIndex, byte rel_index) {
bool isvalid;
return doFormatUserVar(TaskIndex, rel_index, false, isvalid);
}
String formatUserVar(byte TaskIndex, byte rel_index, bool& isvalid) {
return doFormatUserVar(TaskIndex, rel_index, true, isvalid);
}
String formatUserVarNoCheck(struct EventStruct *event, byte rel_index)
{
return formatUserVarNoCheck(event->TaskIndex, rel_index);
}
String formatUserVar(struct EventStruct *event, byte rel_index, bool& isvalid)
{
return formatUserVar(event->TaskIndex, rel_index, isvalid);
}
/*********************************************************************************************\
Wrap a string with given pre- and postfix string.
\*********************************************************************************************/
@@ -102,7 +142,15 @@ String to_json_object_value(const String& object, const String& value) {
result = wrap_String(object, F("\""));
result += F(":");
if (value.length() == 0 || !isFloat(value)) {
result += wrap_String(value, F("\""));
if (value.indexOf('\n') == -1 && value.indexOf('"') == -1 && value.indexOf("Pragma") == -1) {
result += wrap_String(value, F("\""));
} else {
String tmpValue(value);
tmpValue.replace('\n', '^');
tmpValue.replace('"', '\'');
tmpValue.replace("Pragma", "Bugje!");
result += wrap_String(tmpValue, F("\""));
}
} else {
result += value;
}
@@ -277,9 +325,13 @@ void parseSystemVariables(String& s, boolean useURLencode)
#endif
repl(F("%CR%"), F("\r"), s, useURLencode);
repl(F("%LF%"), F("\n"), s, useURLencode);
repl(F("%SP%"), F(" "), s, useURLencode); //space
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()))
SMART_REPL(F("%ssid%"), (wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? F("--") : WiFi.SSID())
SMART_REPL(F("%bssid%"), (wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? F("00:00:00:00:00:00") : WiFi.BSSIDstr())
SMART_REPL(F("%wi_ch%"), String((wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? 0 : WiFi.channel()))
SMART_REPL(F("%unit%"), String(Settings.Unit))
SMART_REPL(F("%mac%"), String(WiFi.macAddress()))
#if defined(ESP8266)
@@ -288,6 +340,7 @@ void parseSystemVariables(String& s, boolean useURLencode)
if (s.indexOf(F("%sys")) != -1) {
SMART_REPL(F("%sysload%"), String(100 - (100 * loopCounterLast / loopCounterMax)))
SMART_REPL(F("%sysheap%"), String(ESP.getFreeHeap()));
SMART_REPL(F("%systm_hm%"), getTimeString(':', false))
SMART_REPL(F("%systm_hm_am%"), getTimeString_ampm(':', false))
SMART_REPL(F("%systime%"), getTimeString(':'))
@@ -300,6 +353,7 @@ void parseSystemVariables(String& s, boolean useURLencode)
SMART_REPL_TIME(F("%syshour%"), PSTR("%02d"), hour())
SMART_REPL_TIME(F("%sysmin%"), PSTR("%02d"), minute())
SMART_REPL_TIME(F("%syssec%"),PSTR("%02d"), second())
SMART_REPL_TIME(F("%syssec_d%"),PSTR("%d"), ((hour()*60) + minute())*60 + second());
SMART_REPL_TIME(F("%sysday%"), PSTR("%02d"), day())
SMART_REPL_TIME(F("%sysmonth%"),PSTR("%02d"), month())
SMART_REPL_TIME(F("%sysyear%"), PSTR("%04d"), year())
@@ -329,10 +383,10 @@ void parseEventVariables(String& s, struct EventStruct *event, boolean useURLenc
if (event->sensorType == SENSOR_TYPE_LONG) {
SMART_REPL(F("%val1%"), String((unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)))
} else {
SMART_REPL(F("%val1%"), formatUserVar(event, 0))
SMART_REPL(F("%val2%"), formatUserVar(event, 1))
SMART_REPL(F("%val3%"), formatUserVar(event, 2))
SMART_REPL(F("%val4%"), formatUserVar(event, 3))
SMART_REPL(F("%val1%"), formatUserVarNoCheck(event, 0))
SMART_REPL(F("%val2%"), formatUserVarNoCheck(event, 1))
SMART_REPL(F("%val3%"), formatUserVarNoCheck(event, 2))
SMART_REPL(F("%val4%"), formatUserVarNoCheck(event, 3))
}
}
}
+24 -6
View File
@@ -202,7 +202,7 @@ unsigned long getNtpTime()
return 0;
}
IPAddress timeServerIP;
String log = F("NTP : NTP send to ");
String log = F("NTP : NTP host ");
if (Settings.NTPHost[0] != 0) {
WiFi.hostByName(Settings.NTPHost, timeServerIP);
log += Settings.NTPHost;
@@ -219,7 +219,13 @@ unsigned long getNtpTime()
nextSyncTime = sysTime + 5;
}
log += F(" (");
log += timeServerIP.toString();
log += F(")");
if (!hostReachable(timeServerIP)) {
log += F(" unreachable");
addLog(LOG_LEVEL_INFO, log);
return 0;
}
@@ -229,9 +235,7 @@ unsigned long getNtpTime()
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
log += F(" (");
log += timeServerIP.toString();
log += F(")");
log += F(" queried");
addLog(LOG_LEVEL_DEBUG_MORE, log);
while (udp.parsePacket() > 0) ; // discard any previously received packets
@@ -282,7 +286,7 @@ unsigned long getNtpTime()
// Return the time difference as a signed value, taking into account the timers may overflow.
// Returned timediff is between -24.9 days and +24.9 days.
// Returned value is positive when "next" is after "prev"
long timeDiff(unsigned long prev, unsigned long next)
long timeDiff(const unsigned long prev, const unsigned long next)
{
long signed_diff = 0;
// To cast a value to a signed long, the difference may not exceed half the ULONG_MAX
@@ -326,7 +330,21 @@ boolean timeOutReached(unsigned long timer)
return passed >= 0;
}
void setNextTimeInterval(unsigned long& timer, const unsigned long step) {
timer += step;
const long passed = timePassedSince(timer);
if (passed < 0) {
// Event has not yet happened, which is fine.
return;
}
if (static_cast<unsigned long>(passed) > step) {
// No need to keep running behind, start again.
timer = millis() + step;
return;
}
// Try to get in sync again.
timer = millis() + (step - passed);
}
/********************************************************************************************\
+1116 -1092
View File
File diff suppressed because it is too large Load Diff
+483
View File
@@ -0,0 +1,483 @@
#ifndef WEBSTATICDATA_h
#define WEBSTATICDATA_h
#define PGMT( pgm_ptr ) ( reinterpret_cast< const __FlashStringHelper * >( pgm_ptr ) )
/*********************************************************************************************\
* ESP Easy logo Favicon.ico 16x16 8 bit
\*********************************************************************************************/
// Generated using xxd: xxd -i favicon.ico > favicon.ino
static const char favicon_8b_ico[] PROGMEM = {
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x00,
0x20, 0x00, 0x68, 0x04, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x12, 0x0b,
0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xef, 0xc0, 0x89, 0x11, 0xfe, 0xfb, 0xf8, 0xac, 0xff, 0xff,
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa,
0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa,
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf3,
0xe9, 0xac, 0xef, 0xc0, 0x89, 0x11, 0xfe, 0xfb, 0xf8, 0xac, 0xf1, 0xc8,
0x95, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xef, 0xc2,
0x8a, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfc, 0xf3, 0xe9, 0xac, 0xff, 0xff,
0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa,
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd9, 0x69,
0x00, 0xff, 0xd9, 0x69, 0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xc2,
0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xd9, 0x69, 0x00, 0xff, 0xd9, 0x69, 0x00, 0xff, 0xef, 0xc2,
0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
0xff, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa,
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63,
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xc2,
0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa,
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2,
0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa,
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63,
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xc2,
0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xc8,
0x95, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa,
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63,
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2,
0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa,
0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63,
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2,
0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xf1,
0xe6, 0xac, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xf1, 0xc8,
0x95, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2,
0x8a, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xfe, 0xfb,
0xf8, 0xac, 0xef, 0xc0, 0x89, 0x11, 0xfb, 0xf1, 0xe6, 0xac, 0xfe, 0xfa,
0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa,
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa,
0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfb,
0xf8, 0xac, 0xef, 0xc0, 0x89, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned int favicon_8b_ico_len = 1150;
static const char pgDefaultCSS[] PROGMEM = {
//color scheme: #07D #D50 #DB0 #A0D
"* {font-family: sans-serif; font-size: 12pt; margin: 0px; padding: 0px; box-sizing: border-box; }"
"h1 {font-size: 16pt; color: #07D; margin: 8px 0; font-weight: bold; }"
"h2 {font-size: 12pt; margin: 0 -4px; padding: 6px; background-color: #444; color: #FFF; font-weight: bold; }"
"h3 {font-size: 12pt; margin: 16px -4px 0 -4px; padding: 4px; background-color: #EEE; color: #444; font-weight: bold; }"
"h6 {font-size: 10pt; color: #07D; }"
// buttons
".button {margin: 4px; padding: 4px 16px; background-color: #07D; color: #FFF; text-decoration: none; border-radius: 4px; border: none;}"
".button.link { }"
".button.help {padding: 2px 4px; border-style: solid; border-width: 1px; border-color: gray; border-radius: 50%; }"
".button:hover {background: #369; }"
// inputs, select, tetarea generall
"input, select, textarea {margin: 4px; padding: 4px 8px; border-radius: 4px; background-color: #eee; border-style: solid; border-width: 1px; border-color: gray;}"
// inputs
"input:hover {background-color: #ccc; }"
"input.wide {max-width: 500px; width:80%; }"
"input.widenumber {max-width: 500px; width:100px; }"
// select
"#selectwidth {max-width: 500px; width:80%; padding: 4px 8px;}"
"select:hover {background-color: #ccc; }"
// custom checkboxes
".container {display: block; padding-left: 35px; margin-left: 4px; margin-top: 0px; position: relative; cursor: pointer; font-size: 12pt; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }"
// Hide the browser's default checkbox
".container input {position: absolute; opacity: 0; cursor: pointer; }"
// Create a custom checkbox
".checkmark {position: absolute; top: 0; left: 0; height: 25px; width: 25px; background-color: #eee; border-style: solid; border-width: 1px; border-color: gray; border-radius: 4px;}"
// On mouse-over, add a grey background color
".container:hover input ~ .checkmark {background-color: #ccc; }"
// When the checkbox is checked, add a blue background
".container input:checked ~ .checkmark { background-color: #07D; }"
// Create the checkmark/indicator (hidden when not checked)
".checkmark:after {content: ''; position: absolute; display: none; }"
// Show the checkmark when checked
".container input:checked ~ .checkmark:after {display: block; }"
// Style the checkmark/indicator
".container .checkmark:after {left: 7px; top: 3px; width: 5px; height: 10px; border: solid white; border-width: 0 3px 3px 0; -webkit-transform: rotate(45deg); -ms-transform: rotate(45deg); transform: rotate(45deg); }"
// custom radio buttons
".container2 {display: block; padding-left: 35px; margin-left: 9px; margin-bottom: 20px; position: relative; cursor: pointer; font-size: 12pt; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }"
// Hide the browser's default radio button
".container2 input {position: absolute; opacity: 0; cursor: pointer; }"
// Create a custom radio button
".dotmark {position: absolute; top: 0; left: 0; height: 26px; width: 26px; background-color: #eee; border-style: solid; border-width: 1px; border-color: gray; border-radius: 50%;}"
// On mouse-over, add a grey background color
".container2:hover input ~ .dotmark {background-color: #ccc; }"
// When the radio button is checked, add a blue background
".container2 input:checked ~ .dotmark { background-color: #07D;}"
// Create the dot/indicator (hidden when not checked)
".dotmark:after {content: ''; position: absolute; display: none; }"
// Show the dot when checked
".container2 input:checked ~ .dotmark:after {display: block; }"
// Style the dot/indicator
".container2 .dotmark:after {top: 8px; left: 8px; width: 8px; height: 8px; border-radius: 50%; background: white; }"
// toast messsage
"#toastmessage {visibility: hidden; min-width: 250px; margin-left: -125px; background-color: #07D;"
"color: #fff; text-align: center; border-radius: 4px; padding: 16px; position: fixed;"
"z-index: 1; left: 282px; bottom: 30%; font-size: 17px; border-style: solid; border-width: 1px; border-color: gray;}"
"#toastmessage.show {visibility: visible; -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s; animation: fadein 0.5s, fadeout 0.5s 2.5s; }"
// fade in
"@-webkit-keyframes fadein {from {bottom: 20%; opacity: 0;} to {bottom: 30%; opacity: 0.9;} }"
"@keyframes fadein {from {bottom: 20%; opacity: 0;} to {bottom: 30%; opacity: 0.9;} }"
// fade out
"@-webkit-keyframes fadeout {from {bottom: 30%; opacity: 0.9;} to {bottom: 0; opacity: 0;} }"
"@keyframes fadeout {from {bottom: 30%; opacity: 0.9;} to {bottom: 0; opacity: 0;} }"
// web log viewer and log levels
//low level? Not used? white
".level_0 { color: #F1F1F1; }"
//ERROR yellow
".level_1 { color: #FCFF95; }"
//INFO blue
".level_2 { color: #9DCEFE; }"
//DEBUG green
".level_3 { color: #A4FC79; }"
//DEBUG_MORE orange
".level_4 { color: #F2AB39; }"
//DEBUG_DEV dark orange
".level_9 { color: #FF5500; }"
//the cmd window
".logviewer { color: #F1F1F1; background-color: #272727; font-family: 'Lucida Console', Monaco, monospace; "
" height: 530px; max-width: 1000px; width: 80%; padding: 4px 8px; overflow: auto; border-style: solid; border-color: gray; }"
// text textarea
"textarea {max-width: 1000px; width:80%; padding: 4px 8px;}"
"textarea:hover {background-color: #ccc; }"
// tables
"table.normal th {padding: 6px; background-color: #444; color: #FFF; border-color: #888; font-weight: bold; }"
"table.normal td {padding: 4px; height: 30px;}"
"table.normal tr {padding: 4px; }"
"table.normal {color: #000; width: 100%; min-width: 420px; border-collapse: collapse; }"
//every second row
"table.multirow th {padding: 6px; background-color: #444; color: #FFF; border-color: #888; font-weight: bold; }"
"table.multirow td {padding: 4px; text-align: center; height: 30px;}"
"table.multirow tr {padding: 4px; }"
"table.multirow tr:nth-child(even){background-color: #DEE6FF; }"
"table.multirow {color: #000; width: 100%; min-width: 420px; border-collapse: collapse; }"
// inside a form
".note {color: #444; font-style: italic; }"
//header with title and menu
".headermenu {position: fixed; top: 0; left: 0; right: 0; height: 90px; padding: 8px 12px; background-color: #F8F8F8; border-bottom: 1px solid #DDD; z-index: 1;}"
".apheader {padding: 8px 12px; background-color: #F8F8F8;}"
".bodymenu {margin-top: 96px;}"
// menu
".menubar {position: inherit; top: 55px; }"
".menu {float: left; padding: 4px 16px 8px 16px; color: #444; white-space: nowrap; border: solid transparent; border-width: 4px 1px 1px; border-radius: 4px 4px 0 0; text-decoration: none; }"
".menu.active {color: #000; background-color: #FFF; border-color: #07D #DDD #FFF; }"
".menu:hover {color: #000; background: #DEF; }"
".menu_button {display: none;}"
// symbols for enabled
".on {color: green; }"
".off {color: red; }"
// others
".div_l {float: left; }"
".div_r {float: right; margin: 2px; padding: 1px 10px; border-radius: 4px; background-color: #080; color: white; }"
".div_br {clear: both; }"
// The alert message box
".alert {padding: 20px; background-color: #f44336; 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
".closebtn:hover {color: black; }"
"section{overflow-x: auto; width: 100%; }"
// For screens with width less than 960 pixels
"@media screen and (max-width: 960px) {"
"header:hover .menubar {display: block;}"
".menu_button {display: block; text-align: center;}"
".bodymenu{ margin-top: 0px; }"
".menubar{ display: none; top: 0px; position: relative; float: left; width: 100%;}"
".headermenu{ position: relative; height: auto; float: left; width: 100%; padding: 5px; z-index: 1;}"
".headermenu h1{ padding: 8px 12px; }"
".headermenu a{ text-align: center; width: 100%; padding:7px 10px; height: auto; border: 0px; border-radius:0px; }; }"
"\0"
};
// JavaScript blobs
static const char jsReboot[] PROGMEM = {
"<script>"
"i=document.getElementById('rbtmsg');"
"i.innerHTML=\"Please reboot: <input id='reboot' class='button link' value='Reboot' type='submit' onclick='r()'>\";"
"var x = new XMLHttpRequest();"
//done
"function d(){"
"i.innerHTML='';"
"clearTimeout(t);"
"}"
//keep requesting mainpage until no more errors
"function c(){"
"i.innerHTML+='.';"
"x.onload=d;"
"x.open('GET', window.location.origin);"
"x.send();"
"}"
//rebooting
"function b(){"
"i.innerHTML='Rebooting..';"
"t=setInterval(c,2000);"
"}"
//request reboot
"function r(){"
"i.innerHTML+=' (requesting)';"
"x.onload=b;"
"x.open('GET', window.location.origin+'/?cmd=reboot');"
"x.send();"
"}"
"</script>"
};
static const char jsToastMessageBegin[] PROGMEM = {
"<script>"
"function toasting() {"
"var x = document.getElementById('toastmessage');"
"x.innerHTML = '"
};
static const char jsToastMessageEnd[] PROGMEM = {
"'; x.className = 'show';"
" setTimeout(function(){x.innerHTML = '';"
" x.className = x.className.replace('show', '');"
" }, 2000);"
"} </script>"
};
static const char jsClipboardCopyPart1[] PROGMEM = {
"<script>function setClipboard() { var clipboard = '';"
" max_loop = 100;"
" for (var i = 1; i < max_loop; i++){"
" var cur_id = '"
};
static const char jsClipboardCopyPart2[] PROGMEM = {
"_' + i;"
" var test = document.getElementById(cur_id);"
" if (test == null){ i = max_loop + 1;"
" } else {"
" clipboard += test.innerHTML.replace(/<[Bb][Rr]\\s*\\/?>/gim,'\\n') + '"
};
//Fix HTML
static const char jsClipboardCopyPart3[] PROGMEM = {
"'; } }"
"clipboard = clipboard.replace(/<\\/[Dd][Ii][Vv]\\s*\\/?>/gim,'\\n');"
"clipboard = clipboard.replace(/<[^>]*>/gim,'');"
"var tempInput = document.createElement('textarea');"
"tempInput.style = 'position: absolute;"
"left: -1000px; top: -1000px'; tempInput.innerHTML = clipboard;"
"document.body.appendChild(tempInput);"
"tempInput.select();"
"document.execCommand('copy');"
"document.body.removeChild(tempInput);"
"alert('Copied: \"' + clipboard + '\" to clipboard!') }"
"</script>"
};
static const char jsUpdateSensorValuesDevicePage[] PROGMEM = {
"<script>"
"loopDeLoop(1000, 0);"
"function loopDeLoop(timeForNext, activeRequests) {"
"var maximumRequests = 1;"
"var c;"
"var k;"
"var err = '';"
"var url = '/json';"
"var check = 0;"
"if (isNaN(activeRequests)){activeRequests = maximumRequests;}"
"if (timeForNext == null){timeForNext = 1000;}"
"var i = setInterval(function() {"
"if (check > 0) {"
"clearInterval(i);"
"return;"
"}"
"++activeRequests;"
// to handle requests pending...
"if (activeRequests > maximumRequests) {"
"check = 1;"
"} else {"
"fetch(url).then(function(response) {"
"if (response.status !== 200) {"
"console.log('Looks like there was a problem. Status Code: ' + response.status);"
"return;"
"}"
"response.json().then(function(data) {"
"timeForNext = data.TTL;"
"for (c = 0; c < data.Sensors.length; c++) {"
"for (k = 0; k < data.Sensors[c].TaskValues.length; k++) {"
"try {"
"valueEntry = data.Sensors[c].TaskValues[k].Value;"
"} catch (err) {"
"valueEntry = err.name;"
"} finally {"
"if (valueEntry !== 'TypeError') {"
//to fix trailing zeros (fixed decimals)
"tempValue = data.Sensors[c].TaskValues[k].Value;"
"decimalsValue = data.Sensors[c].TaskValues[k].NrDecimals;"
"tempValue = parseFloat(tempValue).toFixed(decimalsValue);"
"document.getElementById('value_' + (data.Sensors[c].TaskNumber - 1) + '_' + (data.Sensors[c].TaskValues[k].ValueNumber - 1)).innerHTML = tempValue;"
"document.getElementById('valuename_' + (data.Sensors[c].TaskNumber - 1) + '_' + (data.Sensors[c].TaskValues[k].ValueNumber - 1)).innerHTML = data.Sensors[c].TaskValues[k].Name + ':';"
"}"
"}"
"}"
"}"
"timeForNext = data.TTL;"
//"console.log('Next fetch in: ' + timeForNext + 'mSec, active requests: ' + activeRequests);"
"clearInterval(i);"
"loopDeLoop(timeForNext, 0);"
"return;"
"});"
"})"
".catch(function(err) {"
"console.log(err.message);"
"timeForNext = 5000;"
"clearInterval(i);"
"loopDeLoop(timeForNext, 0);"
"return;"
"});"
"check = 1;"
"}}, timeForNext);"
"}"
"</script>"
};
static const char jsFetchAndParseLog[] PROGMEM = {
"<script>"
"document.getElementById('copyText_1').innerHTML = 'Fetching log entries...';"
"loopDeLoop(1000, 0);"
"function loopDeLoop(timeForNext, activeRequests) {"
"var maximumRequests = 1;"
"var url = '/logjson';"
"if (isNaN(activeRequests)){activeRequests = maximumRequests;}"
"if (timeForNext == null){timeForNext = 1000;}"
//to make sure we don't run to often... JS seems to like it that way.
"if (timeForNext <= 500){"
"scrolling_type = 'auto';"
"} else {"
"scrolling_type = 'smooth';"
"}"
//"console.log('Next fetch in: ' + timeForNext + 'mSec');"
"var c;"
"var check = 0;"
"var i = setInterval(function() {"
// to handle runs that didn't find any json
"if (check > 0) {"
"clearInterval(i);"
"return;"
"}"
"++activeRequests;"
// to handle requests pending...
"if (activeRequests > maximumRequests) {"
"check = 1;"
"} else {"
"fetch(url).then(function(response) {"
"if (response.status !== 200) {"
"console.log('Looks like there was a problem. Status Code: ' + response.status);"
"return;"
"}"
"response.json().then(function(data) {"
"for (c = 0; c < data.Log.nrEntries + 1; c++) {"
"try {"
"logEntry = data.Log.Entries[c].timestamp;"
"} catch (err) {"
"logEntry = err.name;"
"} finally {"
"if (logEntry !== \"TypeError\") {"
"if (document.getElementById('copyText_1').innerHTML == 'Fetching log entries...') {"
"document.getElementById('copyText_1').innerHTML = '';"
"}"
"document.getElementById('copyText_1').innerHTML += '<div class=level_' + data.Log.Entries[c].level + ' id=' + data.Log.Entries[c].timestamp + '><font color=\"gray\">' + data.Log.Entries[c].timestamp + ':</font> ' + data.Log.Entries[c].text + '</div>';"
"autoscroll_on = document.getElementById('autoscroll').checked;"
"if (autoscroll_on == true) {"
"document.getElementById(data.Log.Entries[c].timestamp).scrollIntoView({"
"behavior: scrolling_type"
"});"
"}"
"}"
"}"
"}"
"timeForNext = data.Log.TTL;"
//"console.log('Next fetch in: ' + timeForNext + 'mSec, active requests: ' + activeRequests);"
"clearInterval(i);"
"loopDeLoop(timeForNext, 0);"
"return;"
"})"
"})"
".catch(function(err) {"
"document.getElementById('copyText_1').innerHTML += '<div>>> ' + err.message + ' <<</div>';"
"autoscroll_on = document.getElementById('autoscroll').checked;"
"document.getElementById('copyText_1').scrollTop = document.getElementById('copyText_1').scrollHeight;"
"timeForNext = 5000;"
"clearInterval(i);"
"loopDeLoop(timeForNext, 0);"
"return;"
"})};"
"check = 1;"
"}, timeForNext);"
"}"
"</script>"
};
#endif // WEBSTATICDATA_h
+2
View File
@@ -1,3 +1,4 @@
#ifdef USES_C001
//#######################################################################################################
//########################### Controller Plugin 001: Domoticz HTTP ######################################
//#######################################################################################################
@@ -165,3 +166,4 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
}
return success;
}
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef USES_C002
//#######################################################################################################
//########################### Controller Plugin 002: Domoticz MQTT ######################################
//#######################################################################################################
@@ -209,3 +210,4 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
}
return success;
}
#endif
+3 -1
View File
@@ -1,3 +1,4 @@
#ifdef USES_C003
//#######################################################################################################
//########################### Controller Plugin 003: Nodo Telnet #######################################
//#######################################################################################################
@@ -54,7 +55,7 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
String url = F("variableset ");
url += event->idx;
url += ",";
url += formatUserVar(event, 0);
url += formatUserVarNoCheck(event, 0);
url += "\n";
// strcpy_P(log, PSTR("TELNT: Sending enter"));
@@ -107,3 +108,4 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
}
return success;
}
#endif
+3 -1
View File
@@ -1,3 +1,4 @@
#ifdef USES_C004
//#######################################################################################################
//########################### Controller Plugin 004: ThingSpeak #########################################
//#######################################################################################################
@@ -75,7 +76,7 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
postDataStr += F("&field");
postDataStr += event->idx + x;
postDataStr += "=";
postDataStr += formatUserVar(event, x);
postDataStr += formatUserVarNoCheck(event, x);
}
String hostName = F("api.thingspeak.com"); // PM_CZ: HTTP requests must contain host headers.
if (ControllerSettings.UseDNS)
@@ -127,3 +128,4 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
}
return success;
}
#endif
+3 -4
View File
@@ -1,3 +1,4 @@
#ifdef USES_C005
//#######################################################################################################
//########################### Controller Plugin 005: OpenHAB MQTT #######################################
//#######################################################################################################
@@ -104,10 +105,7 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
{
String tmppubname = pubname;
tmppubname.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]);
if (event->sensorType == SENSOR_TYPE_LONG)
value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
else
value = formatUserVar(event, x);
value = formatUserVarNoCheck(event, x);
MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
String log = F("MQTT : ");
@@ -122,3 +120,4 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
return success;
}
#endif
+3 -4
View File
@@ -1,3 +1,4 @@
#ifdef USES_C006
//#######################################################################################################
//########################### Controller Plugin 006: PiDome MQTT ########################################
//#######################################################################################################
@@ -98,10 +99,7 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
{
String tmppubname = pubname;
tmppubname.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]);
if (event->sensorType == SENSOR_TYPE_LONG)
value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
else
value = formatUserVar(event, x);
value = formatUserVarNoCheck(event, x);
MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
}
break;
@@ -109,3 +107,4 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
}
return success;
}
#endif
+3 -1
View File
@@ -1,3 +1,4 @@
#ifdef USES_C007
//#######################################################################################################
//########################### Controller Plugin 007: Emoncms ############################################
//#######################################################################################################
@@ -70,7 +71,7 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
postDataStr += F("field");
postDataStr += event->idx + i;
postDataStr += ":";
postDataStr += formatUserVar(event, i);
postDataStr += formatUserVarNoCheck(event, i);
}
postDataStr += "}";
postDataStr += F("&apikey=");
@@ -122,3 +123,4 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
}
return success;
}
#endif
+8 -9
View File
@@ -1,3 +1,4 @@
#ifdef USES_C008
//#######################################################################################################
//########################### Controller Plugin 008: Generic HTTP #######################################
//#######################################################################################################
@@ -43,10 +44,10 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
byte valueCount = getValueCountFromSensorType(event->sensorType);
for (byte x = 0; x < valueCount; x++)
{
if (event->sensorType == SENSOR_TYPE_LONG)
HTTPSend(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16));
else
HTTPSend(event, x, UserVar[event->BaseVarIndex + x], 0);
bool isvalid;
String formattedValue = formatUserVar(event, x, isvalid);
if (isvalid)
HTTPSend(event, x, formattedValue);
if (valueCount > 1)
{
delayBackground(Settings.MessageDelay);
@@ -66,7 +67,7 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
//********************************************************************************
// Generic HTTP get request
//********************************************************************************
boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
boolean HTTPSend(struct EventStruct *event, byte varIndex, const String& formattedValue)
{
if (!WiFiConnected(100)) {
return false;
@@ -108,10 +109,7 @@ boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned
parseControllerVariables(url, event, true);
url.replace(F("%valname%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex]));
if (longValue)
url.replace(F("%value%"), String(longValue));
else
url.replace(F("%value%"), toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]));
url.replace(F("%value%"), formattedValue);
// url.toCharArray(log, 80);
addLog(LOG_LEVEL_DEBUG_MORE, url);
@@ -151,3 +149,4 @@ boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned
return(true);
}
#endif
+3 -7
View File
@@ -1,3 +1,4 @@
#ifdef USES_C009
//#######################################################################################################
//########################### Controller Plugin 009: FHEM HTTP ##########################################
//#######################################################################################################
@@ -102,13 +103,7 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
val[F("deviceName")] = ExtraTaskSettings.TaskDeviceName;
val[F("valueName")] = ExtraTaskSettings.TaskDeviceValueNames[x];
val[F("type")] = event->sensorType;
if (event->sensorType == SENSOR_TYPE_LONG) {
val[F("value")] = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
}
else { // All other sensor types
val[F("value")] = formatUserVar(event, x);
}
val[F("value")] = formatUserVarNoCheck(event, x);
}
// Create json buffer
@@ -197,3 +192,4 @@ void FHEMHTTPsend(String & url, String & buffer, byte index)
client.flush();
client.stop();
}
#endif
+8 -9
View File
@@ -1,3 +1,4 @@
#ifdef USES_C010
//#######################################################################################################
//########################### Controller Plugin 010: Generic UDP ########################################
//#######################################################################################################
@@ -42,10 +43,10 @@ boolean CPlugin_010(byte function, struct EventStruct *event, String& string)
byte valueCount = getValueCountFromSensorType(event->sensorType);
for (byte x = 0; x < valueCount; x++)
{
if (event->sensorType == SENSOR_TYPE_LONG)
C010_Send(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16));
else
C010_Send(event, x, UserVar[event->BaseVarIndex + x], 0);
bool isvalid;
String formattedValue = formatUserVar(event, x, isvalid);
if (isvalid)
C010_Send(event, x, formattedValue);
if (valueCount > 1)
{
delayBackground(Settings.MessageDelay);
@@ -65,7 +66,7 @@ boolean CPlugin_010(byte function, struct EventStruct *event, String& string)
//********************************************************************************
// Generic UDP message
//********************************************************************************
void C010_Send(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
void C010_Send(struct EventStruct *event, byte varIndex, const String& formattedValue)
{
ControllerSettingsStruct ControllerSettings;
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
@@ -82,10 +83,7 @@ void C010_Send(struct EventStruct *event, byte varIndex, float value, unsigned l
msg += ControllerSettings.Publish;
parseControllerVariables(msg, event, false);
msg.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[varIndex]);
if (longValue)
msg.replace(F("%value%"), String(longValue));
else
msg.replace(F("%value%"), toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]));
msg.replace(F("%value%"), formattedValue);
if (wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED) {
ControllerSettings.beginPacket(portUDP);
@@ -97,3 +95,4 @@ void C010_Send(struct EventStruct *event, byte varIndex, float value, unsigned l
addLog(LOG_LEVEL_DEBUG_MORE, log);
}
#endif
+3 -1
View File
@@ -1,8 +1,9 @@
#ifdef USES_C011
//#######################################################################################################
//########################### Controller Plugin 011: Generic HTTP #######################################
//#######################################################################################################
#ifdef PLUGIN_BUILD_TESTING
// #ifdef PLUGIN_BUILD_TESTING
#define CPLUGIN_011
#define CPLUGIN_ID_011 11
@@ -283,3 +284,4 @@ void ReplaceTokenByValue(String& s, struct EventStruct *event)
}
#endif
+3 -2
View File
@@ -1,8 +1,9 @@
#ifdef USES_C012
//#######################################################################################################
//########################### Controller Plugin 012: Blynk #############################################
//#######################################################################################################
#ifdef PLUGIN_BUILD_TESTING
// #ifdef PLUGIN_BUILD_TESTING
#define CPLUGIN_012
#define CPLUGIN_ID_012 12
@@ -54,7 +55,7 @@ boolean CPlugin_012_send(struct EventStruct *event, int nrValues) {
postDataStr = F("update/V") ;
postDataStr += event->idx + i;
postDataStr += F("?value=");
postDataStr += formatUserVar(event, i);
postDataStr += formatUserVarNoCheck(event, i);
success = Blynk_get(postDataStr, event->ControllerIndex);
}
return success;
+2 -1
View File
@@ -1,3 +1,4 @@
#ifdef USES_C013
//#######################################################################################################
//########################### Controller Plugin 013: ESPEasy P2P network ################################
//#######################################################################################################
@@ -262,4 +263,4 @@ void C013_Receive(struct EventStruct *event) {
}
}
}
#endif
+1 -1
View File
@@ -31,7 +31,7 @@ int mapVccToDomoticz() {
// Format including trailing semi colon
String formatUserVarDomoticz(struct EventStruct *event, byte rel_index) {
String text = formatUserVar(event, rel_index);
String text = formatUserVarNoCheck(event, rel_index);
text += F(";");
return text;
}
+4 -2
View File
@@ -6,11 +6,13 @@ byte getValueCountFromSensorType(byte sensorType)
{
switch (sensorType)
{
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
case SENSOR_TYPE_NONE:
return 0;
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
case SENSOR_TYPE_SWITCH:
case SENSOR_TYPE_DIMMER:
return 1;
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
return 1;
case SENSOR_TYPE_TEMP_HUM:
case SENSOR_TYPE_TEMP_BARO:
+7 -4
View File
@@ -1,3 +1,4 @@
#ifdef USES_N001
//#######################################################################################################
//########################### Notification Plugin 001: Email ############################################
//#######################################################################################################
@@ -64,7 +65,7 @@ boolean NPlugin_001(byte function, struct EventStruct *event, String& string)
return success;
}
boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, const String& aSub, const String& aMesg) {
boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, const String& aSub, String& aMesg) {
// String& aDomain , String aTo, String aFrom, String aSub, String aMesg, String aHost, int aPort)
boolean myStatus = false;
@@ -92,6 +93,7 @@ boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings,
mailheader.replace(String(F("$ato")), notificationsettings.Receiver);
mailheader.replace(String(F("$subject")), aSub);
mailheader.replace(String(F("$espeasyversion")), String(BUILD));
aMesg.replace("\r", "<br/>"); // re-write line breaks for Content-type: text/html
// Wait for Client to Start Sending
// The MTA Exchange
@@ -100,10 +102,10 @@ boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings,
if (!NPlugin_001_MTA(client, "", F("220 "))) break;
if (!NPlugin_001_MTA(client, String(F("EHLO ")) + notificationsettings.Domain, F("250 "))) break;
if (!NPlugin_001_Auth(client, notificationsettings.User, notificationsettings.Pass)) break;
if (!NPlugin_001_MTA(client, String(F("MAIL FROM:")) + notificationsettings.Sender + "", F("250 "))) break;
if (!NPlugin_001_MTA(client, String(F("RCPT TO:")) + notificationsettings.Receiver + "", F("250 "))) break;
if (!NPlugin_001_MTA(client, String(F("MAIL FROM:<")) + notificationsettings.Sender + ">", F("250 "))) break;
if (!NPlugin_001_MTA(client, String(F("RCPT TO:<")) + notificationsettings.Receiver + ">", F("250 "))) break;
if (!NPlugin_001_MTA(client, F("DATA"), F("354 "))) break;
if (!NPlugin_001_MTA(client, mailheader + aMesg + String(F("\r\n.\r\n")), F("250 "))) break;
if (!NPlugin_001_MTA(client, mailheader + aMesg + String(F("\r\n.\r\n")), F("250 "))) break;
myStatus = true;
break;
@@ -174,3 +176,4 @@ boolean NPlugin_001_MTA(WiFiClient& client, String aStr, const String &aWaitForP
return false;
}
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef USES_N002
//#######################################################################################################
//########################### Notification Plugin 002: Buzzer ###########################################
//#######################################################################################################
@@ -56,3 +57,4 @@ boolean NPlugin_002(byte function, struct EventStruct *event, String& string)
}
return success;
}
#endif
+5 -7
View File
@@ -69,13 +69,13 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
options[1] = F("Dimmer");
int optionValues[2] = { PLUGIN_001_TYPE_SWITCH, PLUGIN_001_TYPE_DIMMER };
const byte switchtype = P001_getSwitchType(event);
addFormSelector(string, F("Switch Type"), F("plugin_001_type"), 2, options, optionValues, switchtype);
addFormSelector(F("Switch Type"), F("plugin_001_type"), 2, options, optionValues, switchtype);
if (switchtype == PLUGIN_001_TYPE_DIMMER)
{
char tmpString[128];
sprintf_P(tmpString, PSTR("<TR><TD>Dim value:<TD><input type='text' name='plugin_001_dimvalue' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
string += tmpString;
addHtml(tmpString);
}
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
@@ -84,9 +84,9 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
buttonOptions[1] = F("Push Button Active Low");
buttonOptions[2] = F("Push Button Active High");
int buttonOptionValues[3] = {PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH};
addFormSelector(string, F("Switch Button Type"), F("plugin_001_button"), 3, buttonOptions, buttonOptionValues, choice);
addFormSelector(F("Switch Button Type"), F("plugin_001_button"), 3, buttonOptions, buttonOptionValues, choice);
addFormCheckBox(string, F("Send Boot state"),F("plugin_001_boot"),
addFormCheckBox(F("Send Boot state"),F("plugin_001_boot"),
Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
success = true;
@@ -149,7 +149,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
}
break;
}
case PLUGIN_UNCONDITIONAL_POLL:
{
// port monitoring, on request by rule command
@@ -389,7 +389,6 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
}
// FIXME: Absolutely no error checking in play_rtttl, until then keep it only in testing
#ifdef PLUGIN_BUILD_TESTING
//play a tune via a RTTTL string, look at https://www.letscontrolit.com/forum/viewtopic.php?f=4&t=343&hilit=speaker&start=10 for more info.
if (command == F("rtttl"))
{
@@ -423,7 +422,6 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
}
}
#endif
break;
}
+12 -12
View File
@@ -49,23 +49,23 @@ boolean Plugin_002(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
#if defined(ESP32)
string += F("<TR><TD>Analog Pin:<TD>");
addPinSelect(false, string, "taskdevicepin1", Settings.TaskDevicePin1[event->TaskIndex]);
addHtml(F("<TR><TD>Analog Pin:<TD>"));
addPinSelect(false, "taskdevicepin1", Settings.TaskDevicePin1[event->TaskIndex]);
#endif
addFormCheckBox(string, F("Oversampling"), F("plugin_002_oversampling"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
addFormSubHeader(string, F("Two Point Calibration"));
addFormCheckBox(F("Oversampling"), F("plugin_002_oversampling"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
addFormCheckBox(string, F("Calibration Enabled"), F("plugin_002_cal"), Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
addFormSubHeader(F("Two Point Calibration"));
addFormNumericBox(string, F("Point 1"), F("plugin_002_adc1"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][0], 0, 1023);
string += F(" &#8793; ");
addTextBox(string, F("plugin_002_out1"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0], 3), 10);
addFormCheckBox(F("Calibration Enabled"), F("plugin_002_cal"), Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
addFormNumericBox(string, F("Point 2"), F("plugin_002_adc2"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1], 0, 1023);
string += F(" &#8793; ");
addTextBox(string, F("plugin_002_out2"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1], 3), 10);
addFormNumericBox(F("Point 1"), F("plugin_002_adc1"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][0], 0, 1023);
addHtml(F(" &#8793; "));
addTextBox(F("plugin_002_out1"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0], 3), 10);
addFormNumericBox(F("Point 2"), F("plugin_002_adc2"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1], 0, 1023);
addHtml(F(" &#8793; "));
addTextBox(F("plugin_002_out2"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1], 3), 10);
success = true;
break;
+4 -4
View File
@@ -65,16 +65,16 @@ boolean Plugin_003(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(string, F("Debounce Time (mSec)"), F("plugin_003")
addFormNumericBox(F("Debounce Time (mSec)"), F("plugin_003")
, Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
String options[4] = { F("Delta"), F("Delta/Total/Time"), F("Total"), F("Delta/Total") };
addFormSelector(string, F("Counter Type"), F("plugin_003_countertype"), 4, options, NULL, choice );
addFormSelector(F("Counter Type"), F("plugin_003_countertype"), 4, options, NULL, choice );
if (choice !=0)
string += F("<span style=\"color:red\">Total count is not persistent!</span>");
addHtml(F("<span style=\"color:red\">Total count is not persistent!</span>"));
String modeRaise[4];
modeRaise[0] = F("LOW");
@@ -87,7 +87,7 @@ boolean Plugin_003(byte function, struct EventStruct *event, String& string)
modeValues[2] = RISING;
modeValues[3] = FALLING;
addFormSelector(string, F("Mode Type"), F("plugin_003_raisetype"), 4, modeRaise, modeValues, choice2 );
addFormSelector(F("Mode Type"), F("plugin_003_raisetype"), 4, modeRaise, modeValues, choice2 );
success = true;
break;
+12 -8
View File
@@ -64,9 +64,9 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
savedAddress[i] = ExtraTaskSettings.TaskDevicePluginConfigLong[i];
// find all suitable devices
addRowLabel(string, F("Device Address"));
addSelector_Head(string, F("plugin_004_dev"), false);
addSelector_Item(string, "", -1, false, false, F(""));
addRowLabel(F("Device Address"));
addSelector_Head(F("plugin_004_dev"), false);
addSelector_Item("", -1, false, false, F(""));
uint8_t tmpAddress[8];
byte count = 0;
Plugin_004_DS_reset();
@@ -80,10 +80,10 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
if (j < 7) option += F("-");
}
bool selected = (memcmp(tmpAddress, savedAddress, 8) == 0) ? true : false;
addSelector_Item(string, option, count, selected, false, F(""));
addSelector_Item(option, count, selected, false, F(""));
count ++;
}
addSelector_Foot(string);
addSelector_Foot();
// Device Resolution select
if (ExtraTaskSettings.TaskDevicePluginConfigLong[0] != 0)
@@ -92,8 +92,8 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
resolutionChoice = 9;
String resultsOptions[4] = { "9", "10", "11", "12" };
int resultsOptionValues[4] = { 9, 10, 11, 12 };
addFormSelector(string, F("Device Resolution"), F("plugin_004_res"), 4, resultsOptions, resultsOptionValues, resolutionChoice);
string += F(" Bit");
addFormSelector(F("Device Resolution"), F("plugin_004_res"), 4, resultsOptions, resultsOptionValues, resolutionChoice);
addHtml(F(" Bit"));
}
success = true;
break;
@@ -251,13 +251,17 @@ boolean Plugin_004_DS_readTemp(uint8_t ROM[8], float * value)
return false;
}
if ((ROM[0] == 0x28 ) || (ROM[0] == 0x3b)) // DS18B20 or DS1825
if ((ROM[0] == 0x28 ) || (ROM[0] == 0x3b) || (ROM[0] == 0x22)) // DS18B20 or DS1825 or DS1822
{
DSTemp = (ScratchPad[1] << 8) + ScratchPad[0];
if (DSTemp == 0x550) // power-on reset value
return false;
*value = (float(DSTemp) * 0.0625);
}
else if (ROM[0] == 0x10) // DS1820 DS18S20
{
if (ScratchPad[0] == 0xaa) // power-on reset value
return false;
DSTemp = (ScratchPad[1] << 11) | ScratchPad[0] << 3;
DSTemp = ((DSTemp & 0xfff0) << 3) - 16 +
(((ScratchPad[7] - ScratchPad[6]) << 7) / ScratchPad[7]);
+1 -1
View File
@@ -51,7 +51,7 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
const String options[] = { F("DHT 11"), F("DHT 22"), F("DHT 12"), F("Sonoff am2301"), F("Sonoff si7021") };
int indices[] = { 11, 22, 12, 23, 70 };
addFormSelector(string, F("DHT Type"), F("plugin_005_dhttype"), 5, options, indices, Settings.TaskDevicePluginConfig[event->TaskIndex][0] );
addFormSelector(F("DHT Type"), F("plugin_005_dhttype"), 5, options, indices, Settings.TaskDevicePluginConfig[event->TaskIndex][0] );
success = true;
break;
+1 -1
View File
@@ -50,7 +50,7 @@ boolean Plugin_006(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(string, F("Altitude [m]"), F("_p006_bmp085_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
addFormNumericBox(F("Altitude [m]"), F("_p006_bmp085_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
success = true;
break;
}
+1 -1
View File
@@ -47,7 +47,7 @@ boolean Plugin_009(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormCheckBox(string, F("Send Boot state") ,F("plugin_009_boot"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
addFormCheckBox(F("Send Boot state") ,F("plugin_009_boot"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
success = true;
break;
+4 -4
View File
@@ -57,8 +57,8 @@ boolean Plugin_010(byte function, struct EventStruct *event, String& string)
int optionValues[2];
optionValues[0] = BH1750_DEFAULT_I2CADDR;
optionValues[1] = BH1750_SECOND_I2CADDR;
addFormSelectorI2C(string, F("plugin_010"), 2, optionValues, choice);
addFormNote(string, F("ADDR Low=0x23, High=0x5c"));
addFormSelectorI2C(F("plugin_010"), 2, optionValues, choice);
addFormNote(F("ADDR Low=0x23, High=0x5c"));
byte choiceMode = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
String optionsMode[4];
@@ -71,9 +71,9 @@ boolean Plugin_010(byte function, struct EventStruct *event, String& string)
optionValuesMode[1] = RESOLUTION_NORMAL;
optionValuesMode[2] = RESOLUTION_HIGH;
optionValuesMode[3] = RESOLUTION_AUTO_HIGH;
addFormSelector(string, F("Measurement mode"), F("plugin_010_mode"), 4, optionsMode, optionValuesMode, choiceMode);
addFormSelector(F("Measurement mode"), F("plugin_010_mode"), 4, optionsMode, optionValuesMode, choiceMode);
addFormCheckBox(string, F("Send sensor to sleep"), F("plugin_010_sleep"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
addFormCheckBox(F("Send sensor to sleep"), F("plugin_010_sleep"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
success = true;
break;
+1 -1
View File
@@ -48,7 +48,7 @@ boolean Plugin_011(byte function, struct EventStruct *event, String& string)
{
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[2] = { F("Digital"), F("Analog") };
addFormSelector(string, F("Port Type"), F("plugin_011"), 2, options, NULL, choice);
addFormSelector(F("Port Type"), F("plugin_011"), 2, options, NULL, choice);
success = true;
break;
+40 -48
View File
@@ -12,6 +12,9 @@
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C *lcd=NULL;
int Plugin_012_cols = 16;
int Plugin_012_rows = 2;
int Plugin_012_mode = 1;
#define PLUGIN_012
#define PLUGIN_ID_012 12
@@ -30,7 +33,7 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
{
Device[++deviceCount].Number = PLUGIN_ID_012;
Device[deviceCount].Type = DEVICE_TYPE_I2C;
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
Device[deviceCount].VType = SENSOR_TYPE_NONE;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
@@ -67,7 +70,7 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
//options[x] = F("0x");
//options[x] += String(optionValues[x], HEX);
}
addFormSelectorI2C(string, F("plugin_012_adr"), 16, optionValues, choice);
addFormSelectorI2C(F("plugin_012_adr"), 16, optionValues, choice);
byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
@@ -75,30 +78,30 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
options2[0] = F("2 x 16");
options2[1] = F("4 x 20");
int optionValues2[2] = { 1, 2 };
addFormSelector(string, F("Display Size"), F("plugin_012_size"), 2, options2, optionValues2, choice2);
addFormSelector(F("Display Size"), F("plugin_012_size"), 2, options2, optionValues2, choice2);
char deviceTemplate[4][80];
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
for (byte varNr = 0; varNr < 4; varNr++)
{
string += F("<TR><TD>Line ");
string += varNr + 1;
string += F(":<TD><input type='text' size='80' maxlength='80' name='Plugin_012_template");
string += varNr + 1;
string += F("' value='");
string += deviceTemplate[varNr];
string += F("'>");
addHtml(F("<TR><TD>Line "));
addHtml(String(varNr + 1));
addHtml(F(":<TD><input type='text' size='80' maxlength='80' name='Plugin_012_template"));
addHtml(String(varNr + 1));
addHtml(F("' value='"));
addHtml(deviceTemplate[varNr]);
addHtml(F("'>"));
}
addRowLabel(string, "Display button");
addPinSelect(false, string, "taskdevicepin3", Settings.TaskDevicePin3[event->TaskIndex]);
addRowLabel("Display button");
addPinSelect(false, "taskdevicepin3", Settings.TaskDevicePin3[event->TaskIndex]);
char tmpString[128];
sprintf_P(tmpString, PSTR("<TR><TD>Display Timeout:<TD><input type='text' name='plugin_12_timer' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
string += tmpString;
addHtml(tmpString);
String options3[3];
@@ -106,7 +109,7 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
options3[1] = F("Truncate exceeding message");
options3[2] = F("Clear then truncate exceeding message");
int optionValues3[3] = { 0,1,2 };
addFormSelector(string, F("LCD command Mode"), F("plugin_012_mode"), 3, options3, optionValues3, Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
addFormSelector(F("LCD command Mode"), F("plugin_012_mode"), 3, options3, optionValues3, Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
success = true;
break;
@@ -137,17 +140,21 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
case PLUGIN_INIT:
{
if (!lcd)
{
byte row = 2;
byte col = 16;
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 2)
{
row = 4;
col = 20;
}
lcd = new LiquidCrystal_I2C(Settings.TaskDevicePluginConfig[event->TaskIndex][0], col, row);
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 2) {
Plugin_012_rows = 4;
Plugin_012_cols = 20;
} else if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 1) {
Plugin_012_rows = 2;
Plugin_012_cols = 16;
}
Plugin_012_mode = Settings.TaskDevicePluginConfig[event->TaskIndex][3];
//TODO:LiquidCrystal_I2C class doesn't have destructor. So if LCD type (size) is changed better reboot for changes to take effect.
// workaround is to fix the cols and rows at its maximum (20 and 4)
if (!lcd)
lcd = new LiquidCrystal_I2C(Settings.TaskDevicePluginConfig[event->TaskIndex][0], 20, 4); //Plugin_012_cols, Plugin_012_rows);
// Setup LCD display
lcd->init(); // initialize the lcd
lcd->backlight();
@@ -190,20 +197,12 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
char deviceTemplate[4][80];
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
byte row = 2;
byte col = 16;
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 2)
{
row = 4;
col = 20;
}
for (byte x = 0; x < row; x++)
for (byte x = 0; x < Plugin_012_rows; x++)
{
String tmpString = deviceTemplate[x];
if (lcd && tmpString.length())
{
String newString = P012_parseTemplate(tmpString, col);
String newString = P012_parseTemplate(tmpString, Plugin_012_cols);
lcd->setCursor(0, x);
lcd->print(newString);
}
@@ -214,13 +213,6 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
case PLUGIN_WRITE:
{
byte rows = 2;
byte cols = 16;
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 2){
rows = 4;
cols = 20;
}
String tmpString = string;
int argIndex = tmpString.indexOf(',');
if (argIndex)
@@ -244,7 +236,7 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
else if (lcd && tmpString.equalsIgnoreCase(F("LCD")))
{
success = true;
tmpString = P012_parseTemplate(string, cols);
tmpString = P012_parseTemplate(string, Plugin_012_cols);
argIndex = tmpString.lastIndexOf(',');
tmpString = tmpString.substring(argIndex + 1);
@@ -252,18 +244,18 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
int rowPos = event->Par1 - 1;
//clear line before writing new string
if (Settings.TaskDevicePluginConfig[event->TaskIndex][3] == 2){
if (Plugin_012_mode == 2){
lcd->setCursor(colPos, rowPos);
for (byte i = colPos; i < cols; i++) {
for (byte i = colPos; i < Plugin_012_cols; i++) {
lcd->print(F(" "));
}
}
// truncate message exceeding cols
lcd->setCursor(colPos, rowPos);
if(Settings.TaskDevicePluginConfig[event->TaskIndex][3] == 1 || Settings.TaskDevicePluginConfig[event->TaskIndex][3] == 2){
if(Plugin_012_mode == 1 || Plugin_012_mode == 2){
lcd->setCursor(colPos, rowPos);
for (byte i = 0; i < cols - colPos; i++) {
for (byte i = 0; i < Plugin_012_cols - colPos; i++) {
if(tmpString[i]){
lcd->print(tmpString[i]);
}
@@ -276,14 +268,14 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
boolean stillProcessing = 1;
byte charCount = 1;
while(stillProcessing) {
if (++colPos > cols) { // have we printed 20 characters yet (+1 for the logic)
if (++colPos > Plugin_012_cols) { // have we printed 20 characters yet (+1 for the logic)
rowPos += 1;
lcd->setCursor(0,rowPos); // move cursor down
colPos = 1;
}
//dont print if "lower" than the lcd
if(rowPos < rows ){
if(rowPos < Plugin_012_rows ){
lcd->print(tmpString[charCount - 1]);
}
+33 -45
View File
@@ -1,20 +1,19 @@
#ifdef USES_P013
//#######################################################################################################
//#################################### Plugin 013: HC-SR04 ##############################################
//############################### Plugin 013: HC-SR04, RCW-0001, etc. ###################################
//#######################################################################################################
#define PLUGIN_013
#define PLUGIN_ID_013 13
#define PLUGIN_NAME_013 "Distance - HC-SR04"
#define PLUGIN_NAME_013 "Distance - HC-SR04, RCW-0001, etc."
#define PLUGIN_VALUENAME1_013 "Distance"
void Plugin_013_interrupt() ICACHE_RAM_ATTR;
#include <NewPing.h>
boolean Plugin_013_init = false;
volatile unsigned long Plugin_013_timer = 0;
volatile unsigned long Plugin_013_state = 0;
byte Plugin_013_TRIG_Pin = 0;
byte Plugin_013_IRQ_Pin = 0;
NewPing *sonar = NULL;
boolean Plugin_013(byte function, struct EventStruct *event, String& string)
{
@@ -59,11 +58,11 @@ boolean Plugin_013(byte function, struct EventStruct *event, String& string)
options[0] = F("Value");
options[1] = F("State");
int optionValues[2] = { 1, 2 };
addFormSelector(string, F("Mode"), F("plugin_013_mode"), 2, options, optionValues, choice);
addFormSelector(F("Mode"), F("plugin_013_mode"), 2, options, optionValues, choice);
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2)
{
addFormNumericBox(string, F("Threshold"), F("plugin_013_threshold"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
addFormNumericBox(F("Threshold"), F("plugin_013_threshold"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
}
success = true;
break;
@@ -83,21 +82,38 @@ boolean Plugin_013(byte function, struct EventStruct *event, String& string)
case PLUGIN_INIT:
{
Plugin_013_init = true;
pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT);
pinMode(Settings.TaskDevicePin2[event->TaskIndex], INPUT_PULLUP);
Plugin_013_TRIG_Pin = Settings.TaskDevicePin1[event->TaskIndex];
Plugin_013_IRQ_Pin = Settings.TaskDevicePin2[event->TaskIndex];
attachInterrupt(Settings.TaskDevicePin2[event->TaskIndex], Plugin_013_interrupt, CHANGE);
if (sonar)
{
delete sonar;
sonar=NULL;
}
sonar = new NewPing(Plugin_013_TRIG_Pin, Plugin_013_IRQ_Pin);
success = true;
break;
}
case PLUGIN_EXIT:
{
if (sonar)
{
delete sonar;
sonar=NULL;
}
break;
}
case PLUGIN_READ: // If we select value mode, read and send the value based on global timer
{
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 1)
{
Plugin_013_TRIG_Pin = Settings.TaskDevicePin1[event->TaskIndex];
float value = Plugin_013_read();
String log = F("SR04 : Distance: ");
String log = F("ULTRASONIC : Distance: ");
if (value > 0)
{
UserVar[event->BaseVarIndex] = value;
@@ -125,7 +141,7 @@ boolean Plugin_013(byte function, struct EventStruct *event, String& string)
state = 1;
if (state != switchstate[event->TaskIndex])
{
String log = F("SR04 : State ");
String log = F("ULTRASONIC : State ");
log += state;
addLog(LOG_LEVEL_INFO,log);
switchstate[event->TaskIndex] = state;
@@ -146,39 +162,11 @@ boolean Plugin_013(byte function, struct EventStruct *event, String& string)
float Plugin_013_read()
/*********************************************************************/
{
float value = -1;
Plugin_013_timer = 0;
Plugin_013_state = 0;
noInterrupts();
digitalWrite(Plugin_013_TRIG_Pin, LOW);
delayMicroseconds(2);
digitalWrite(Plugin_013_TRIG_Pin, HIGH);
delayMicroseconds(10);
digitalWrite(Plugin_013_TRIG_Pin, LOW);
interrupts();
if (!sonar)
{
return 0;
}
delay(25); // wait for measurement to finish (max 400 cm * 58 uSec = 23uSec)
if (Plugin_013_state == 2)
{
value = (float)Plugin_013_timer / 58;
}
return value;
}
/*********************************************************************/
void Plugin_013_interrupt()
/*********************************************************************/
{
byte pinState = digitalRead(Plugin_013_IRQ_Pin);
if (pinState == 1) // Start of pulse
{
Plugin_013_state = 1;
Plugin_013_timer = micros();
}
else // End of pulse, calculate timelapse between start & end
{
Plugin_013_state = 2;
Plugin_013_timer = micros() - Plugin_013_timer;
}
return sonar->ping_cm();
}
#endif // USES_P013
+2 -2
View File
@@ -86,8 +86,8 @@ boolean Plugin_014(byte function, struct EventStruct *event, String& string)
options[2] = F("Temp 12 bits / RH 8 bits");
optionValues[3] = SI7021_RESOLUTION_11T_11RH;
options[3] = F("Temp 11 bits / RH 11 bits");
addFormSelector(string, F("Resolution"), F("plugin_014_res"), SI7021_RESOLUTION_OPTION, options, optionValues, choice);
//addUnit(string, F("bits"));
addFormSelector(F("Resolution"), F("plugin_014_res"), SI7021_RESOLUTION_OPTION, options, optionValues, choice);
//addUnit(F("bits"));
success = true;
break;
+26 -9
View File
@@ -12,6 +12,8 @@
#define PLUGIN_ID_015 15
#define PLUGIN_NAME_015 "Light/Lux - TSL2561"
#define PLUGIN_VALUENAME1_015 "Lux"
#define PLUGIN_VALUENAME2_015 "Infrared"
#define PLUGIN_VALUENAME3_015 "Broadband"
boolean Plugin_015_init = false;
@@ -219,7 +221,7 @@ boolean plugin_015_getData(unsigned int &data0, unsigned int &data1)
}
boolean plugin_015_getLux(unsigned char gain, unsigned int ms, unsigned int CH0, unsigned int CH1, double &lux)
boolean plugin_015_getLux(unsigned char gain, unsigned int ms, unsigned int CH0, unsigned int CH1, double &lux, double &infrared, double &broadband)
// Convert raw data to lux
// gain: 0 (1X) or 1 (16X), see setTiming()
// ms: integration time in ms, from setTiming() or from manual integration
@@ -246,6 +248,10 @@ boolean plugin_015_getLux(unsigned char gain, unsigned int ms, unsigned int CH0,
// We will need the ratio for subsequent calculations
ratio = d1 / d0;
// save original values
infrared = d1;
broadband = d0;
// Normalize for integration time
d0 *= (402.0/ms);
d1 *= (402.0/ms);
@@ -290,7 +296,6 @@ boolean plugin_015_getLux(unsigned char gain, unsigned int ms, unsigned int CH0,
}
boolean Plugin_015(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
@@ -301,12 +306,12 @@ boolean Plugin_015(byte function, struct EventStruct *event, String& string)
{
Device[++deviceCount].Number = PLUGIN_ID_015;
Device[deviceCount].Type = DEVICE_TYPE_I2C;
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
Device[deviceCount].VType = SENSOR_TYPE_TRIPLE;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = true;
Device[deviceCount].ValueCount = 1;
Device[deviceCount].ValueCount = 3;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = true;
Device[deviceCount].GlobalSyncOption = true;
@@ -322,6 +327,9 @@ boolean Plugin_015(byte function, struct EventStruct *event, String& string)
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_015));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_015));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_015));
break;
}
@@ -338,7 +346,7 @@ boolean Plugin_015(byte function, struct EventStruct *event, String& string)
optionValues1[0] = TSL2561_ADDR;
optionValues1[1] = TSL2561_ADDR_1;
optionValues1[2] = TSL2561_ADDR_0;
addFormSelectorI2C(string, F("plugin_015_tsl2561_i2c"), 3, optionValues1, choice1);
addFormSelectorI2C(F("plugin_015_tsl2561_i2c"), 3, optionValues1, choice1);
#define TSL2561_INTEGRATION_OPTION 3
@@ -351,12 +359,12 @@ boolean Plugin_015(byte function, struct EventStruct *event, String& string)
options2[1] = F("101 ms");
optionValues2[2] = 0x02;
options2[2] = F("402 ms");
addFormSelector(string, F("Integration time"), F("plugin_015_integration"), TSL2561_INTEGRATION_OPTION, options2, optionValues2, choice2);
addFormSelector(F("Integration time"), F("plugin_015_integration"), TSL2561_INTEGRATION_OPTION, options2, optionValues2, choice2);
addFormCheckBox(string, F("Send sensor to sleep:"), F("plugin_015_sleep"),
addFormCheckBox(F("Send sensor to sleep:"), F("plugin_015_sleep"),
Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
addFormCheckBox(string, F("Enable 16x Gain:"), F("plugin_015_gain"),
addFormCheckBox(F("Enable 16x Gain:"), F("plugin_015_gain"),
Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
success = true;
@@ -403,12 +411,17 @@ boolean Plugin_015(byte function, struct EventStruct *event, String& string)
{
double lux; // Resulting lux value
double infrared; // Resulting infrared value
double broadband; // Resulting broadband value
boolean good; // True if neither sensor is saturated
// Perform lux calculation:
good = plugin_015_getLux(gain,ms,data0,data1,lux);
good = plugin_015_getLux(gain,ms,data0,data1,lux, infrared, broadband);
UserVar[event->BaseVarIndex] = lux;
UserVar[event->BaseVarIndex + 1] = infrared;
UserVar[event->BaseVarIndex + 2] = broadband;
if (!good)
{
addLog(LOG_LEVEL_INFO,F("TSL2561: Sensor saturated! > 65535 Lux"));
@@ -423,6 +436,10 @@ boolean Plugin_015(byte function, struct EventStruct *event, String& string)
log += String(gain,HEX);
log += F(": Lux: ");
log += UserVar[event->BaseVarIndex];
log += F(": Infrared: ");
log += UserVar[event->BaseVarIndex + 1];
log += F(": Broadband: ");
log += UserVar[event->BaseVarIndex + 2];
addLog(LOG_LEVEL_INFO,log);
}
else
-2
View File
@@ -4,7 +4,6 @@
//#######################################################################################################
#ifdef PLUGIN_BUILD_NORMAL
#include <IRremoteESP8266.h>
IRrecv *irReceiver;
@@ -93,5 +92,4 @@ boolean Plugin_016(byte function, struct EventStruct *event, String& string)
return success;
}
#endif
#endif // USES_P016
+1 -1
View File
@@ -67,7 +67,7 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormPinSelect(string, F("Reset Pin"), F("taskdevicepin3"), Settings.TaskDevicePin3[event->TaskIndex]);
addFormPinSelect(F("Reset Pin"), F("taskdevicepin3"), Settings.TaskDevicePin3[event->TaskIndex]);
success = true;
break;
}
+1 -1
View File
@@ -47,7 +47,7 @@ boolean Plugin_019(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormCheckBox(string, F("Send Boot state"), F("plugin_019_boot"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
addFormCheckBox(F("Send Boot state"), F("plugin_019_boot"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
success = true;
break;
+10 -8
View File
@@ -46,9 +46,9 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(string, F("TCP Port"), F("plugin_020_port"), ExtraTaskSettings.TaskDevicePluginConfigLong[0]);
addFormNumericBox(string, F("Baud Rate"), F("plugin_020_baud"), ExtraTaskSettings.TaskDevicePluginConfigLong[1]);
addFormNumericBox(string, F("Data bits"), F("plugin_020_data"), ExtraTaskSettings.TaskDevicePluginConfigLong[2]);
addFormNumericBox(F("TCP Port"), F("plugin_020_port"), ExtraTaskSettings.TaskDevicePluginConfigLong[0]);
addFormNumericBox(F("Baud Rate"), F("plugin_020_baud"), ExtraTaskSettings.TaskDevicePluginConfigLong[1]);
addFormNumericBox(F("Data bits"), F("plugin_020_data"), ExtraTaskSettings.TaskDevicePluginConfigLong[2]);
byte choice = ExtraTaskSettings.TaskDevicePluginConfigLong[3];
String options[3];
@@ -59,13 +59,13 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
optionValues[0] = 0;
optionValues[1] = 2;
optionValues[2] = 3;
addFormSelector(string, F("Parity"), F("plugin_020_parity"), 3, options, optionValues, choice);
addFormSelector(F("Parity"), F("plugin_020_parity"), 3, options, optionValues, choice);
addFormNumericBox(string, F("Stop bits"), F("plugin_020_stop"), ExtraTaskSettings.TaskDevicePluginConfigLong[4]);
addFormNumericBox(F("Stop bits"), F("plugin_020_stop"), ExtraTaskSettings.TaskDevicePluginConfigLong[4]);
addFormPinSelect(string, F("Reset target after boot"), F("taskdevicepin1"), Settings.TaskDevicePin1[event->TaskIndex]);
addFormPinSelect(F("Reset target after boot"), F("taskdevicepin1"), Settings.TaskDevicePin1[event->TaskIndex]);
addFormNumericBox(string, F("RX Receive Timeout (mSec)"), F("plugin_020_rxwait"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
addFormNumericBox(F("RX Receive Timeout (mSec)"), F("plugin_020_rxwait"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
@@ -73,7 +73,7 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
options2[0] = F("None");
options2[1] = F("Generic");
options2[2] = F("RFLink");
addFormSelector(string, F("Event processing"), F("plugin_020_events"), 3, options2, NULL, choice2);
addFormSelector(F("Event processing"), F("plugin_020_events"), 3, options2, NULL, choice2);
success = true;
break;
@@ -173,6 +173,8 @@ boolean Plugin_020(byte function, struct EventStruct *event, String& string)
if (connectionState == 1) // there was a client connected before...
{
connectionState = 0;
// workaround see: https://github.com/esp8266/Arduino/issues/4497#issuecomment-373023864
ser2netClient = WiFiClient();
addLog(LOG_LEVEL_ERROR, F("Ser2N: Client disconnected!"));
}
+6 -6
View File
@@ -47,16 +47,16 @@ boolean Plugin_021(byte function, struct EventStruct *event, String& string)
{
// char tmpString[128];
string += F("<TR><TD>Check Task:<TD>");
addTaskSelect(string, "plugin_021_task", Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
addHtml(F("<TR><TD>Check Task:<TD>"));
addTaskSelect("plugin_021_task", Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
LoadTaskSettings(Settings.TaskDevicePluginConfig[event->TaskIndex][0]); // we need to load the values from another task for selection!
string += F("<TR><TD>Check Value:<TD>");
addTaskValueSelect(string, "plugin_021_value", Settings.TaskDevicePluginConfig[event->TaskIndex][1], Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
addHtml(F("<TR><TD>Check Value:<TD>"));
addTaskValueSelect("plugin_021_value", Settings.TaskDevicePluginConfig[event->TaskIndex][1], Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
addFormTextBox(string, F("Set Level"), F("plugin_021_setvalue"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0]), 8);
addFormTextBox(F("Set Level"), F("plugin_021_setvalue"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0]), 8);
addFormTextBox(string, F("Hysteresis"), F("plugin_021_hyst"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1]), 8);
addFormTextBox(F("Hysteresis"), F("plugin_021_hyst"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1]), 8);
LoadTaskSettings(event->TaskIndex); // we need to restore our original taskvalues!
success = true;
+1 -1
View File
@@ -26,7 +26,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
{
Device[++deviceCount].Number = PLUGIN_ID_022;
Device[deviceCount].Type = DEVICE_TYPE_I2C;
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
Device[deviceCount].VType = SENSOR_TYPE_NONE;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
+8 -8
View File
@@ -43,7 +43,7 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
{
Device[++deviceCount].Number = PLUGIN_ID_023;
Device[deviceCount].Type = DEVICE_TYPE_I2C;
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
Device[deviceCount].VType = SENSOR_TYPE_NONE;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
@@ -71,33 +71,33 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
/*String options[2] = { F("3C"), F("3D") };*/
int optionValues[2] = { 0x3C, 0x3D };
addFormSelectorI2C(string, F("plugin_023_adr"), 2, optionValues, choice);
addFormSelectorI2C(F("plugin_023_adr"), 2, optionValues, choice);
byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
String options2[2] = { F("Normal"), F("Rotated") };
int optionValues2[2] = { 1, 2 };
addFormSelector(string, F("Rotation"), F("plugin_023_rotate"), 2, options2, optionValues2, choice2);
addFormSelector(F("Rotation"), F("plugin_023_rotate"), 2, options2, optionValues2, choice2);
byte choice3 = Settings.TaskDevicePluginConfig[event->TaskIndex][3];
String options3[3] = { F("128x64"), F("128x32"), F("64x48") };
int optionValues3[3] = { 1, 3, 2 };
addFormSelector(string, F("Display Size"), F("plugin_023_size"), 3, options3, optionValues3, choice3);
addFormSelector(F("Display Size"), F("plugin_023_size"), 3, options3, optionValues3, choice3);
byte choice4 = Settings.TaskDevicePluginConfig[event->TaskIndex][4];
String options4[2] = { F("Normal"), F("Optimized") };
int optionValues4[2] = { 1, 2 };
addFormSelector(string, F("Font Width"), F("plugin_023_font_width"), 2, options4, optionValues4, choice4);
addFormSelector(F("Font Width"), F("plugin_023_font_width"), 2, options4, optionValues4, choice4);
char deviceTemplate[8][64];
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
for (byte varNr = 0; varNr < 8; varNr++)
{
addFormTextBox(string, String(F("Line ")) + (varNr + 1), String(F("Plugin_023_template")) + (varNr + 1), deviceTemplate[varNr], 64);
addFormTextBox(String(F("Line ")) + (varNr + 1), String(F("Plugin_023_template")) + (varNr + 1), deviceTemplate[varNr], 64);
}
addFormPinSelect(string, F("Display button"), F("taskdevicepin3"), Settings.TaskDevicePin3[event->TaskIndex]);
addFormPinSelect(F("Display button"), F("taskdevicepin3"), Settings.TaskDevicePin3[event->TaskIndex]);
addFormNumericBox(string, F("Display Timeout"), F("plugin_23_timer"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
addFormNumericBox(F("Display Timeout"), F("plugin_23_timer"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
success = true;
break;
+1 -1
View File
@@ -78,7 +78,7 @@ boolean Plugin_024(byte function, struct EventStruct *event, String& string)
options[0] = F("IR object temperature");
optionValues[1] = (0x06);
options[1] = F("Ambient temperature");
addFormSelector(string, F("Option"), F("plugin_024_option"), MLX90614_OPTION, options, optionValues, choice);
addFormSelector(F("Option"), F("plugin_024_option"), MLX90614_OPTION, options, optionValues, choice);
success = true;
break;
+12 -12
View File
@@ -67,9 +67,9 @@ boolean Plugin_025(byte function, struct EventStruct *event, String& string)
#define ADS1115_I2C_OPTION 4
byte addr = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
int optionValues[ADS1115_I2C_OPTION] = { 0x48, 0x49, 0x4A, 0x4B };
addFormSelectorI2C(string, F("plugin_025_i2c"), ADS1115_I2C_OPTION, optionValues, addr);
addFormSelectorI2C(F("plugin_025_i2c"), ADS1115_I2C_OPTION, optionValues, addr);
addFormSubHeader(string, F("Input"));
addFormSubHeader(F("Input"));
#define ADS1115_PGA_OPTION 6
byte pga = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
@@ -81,7 +81,7 @@ boolean Plugin_025(byte function, struct EventStruct *event, String& string)
F("8x gain (FS=0.512V)"),
F("16x gain (FS=0.256V)")
};
addFormSelector(string, F("Gain"), F("plugin_025_gain"), ADS1115_PGA_OPTION, pgaOptions, NULL, pga);
addFormSelector(F("Gain"), F("plugin_025_gain"), ADS1115_PGA_OPTION, pgaOptions, NULL, pga);
#define ADS1115_MUX_OPTION 8
byte mux = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
@@ -95,19 +95,19 @@ boolean Plugin_025(byte function, struct EventStruct *event, String& string)
F("AIN2 - GND (Single-Ended)"),
F("AIN3 - GND (Single-Ended)"),
};
addFormSelector(string, F("Input Multiplexer"), F("plugin_025_mode"), ADS1115_MUX_OPTION, muxOptions, NULL, mux);
addFormSelector(F("Input Multiplexer"), F("plugin_025_mode"), ADS1115_MUX_OPTION, muxOptions, NULL, mux);
addFormSubHeader(string, F("Two Point Calibration"));
addFormSubHeader(F("Two Point Calibration"));
addFormCheckBox(string, F("Calibration Enabled"), F("plugin_025_cal"), Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
addFormCheckBox(F("Calibration Enabled"), F("plugin_025_cal"), Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
addFormNumericBox(string, F("Point 1"), F("plugin_025_adc1"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][0], -32768, 32767);
string += F(" &#8793; ");
addTextBox(string, F("plugin_025_out1"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0], 3), 10);
addFormNumericBox(F("Point 1"), F("plugin_025_adc1"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][0], -32768, 32767);
addHtml(F(" &#8793; "));
addTextBox(F("plugin_025_out1"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0], 3), 10);
addFormNumericBox(string, F("Point 2"), F("plugin_025_adc2"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1], -32768, 32767);
string += F(" &#8793; ");
addTextBox(string, F("plugin_025_out2"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1], 3), 10);
addFormNumericBox(F("Point 2"), F("plugin_025_adc2"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1], -32768, 32767);
addHtml(F(" &#8793; "));
addTextBox(F("plugin_025_out2"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1], 3), 10);
success = true;
break;
+1 -1
View File
@@ -52,7 +52,7 @@ boolean Plugin_026(byte function, struct EventStruct *event, String& string)
options[7] = F("IP 3.Octet");
options[8] = F("IP 4.Octet");
options[9] = F("Web activity");
addFormSelector(string, F("Indicator"), F("plugin_026"), 10, options, NULL, choice);
addFormSelector(F("Indicator"), F("plugin_026"), 10, options, NULL, choice);
success = true;
break;
+3 -3
View File
@@ -138,13 +138,13 @@ boolean Plugin_027(byte function, struct EventStruct *event, String& string)
optionValuesMode[0] = 0;
optionValuesMode[1] = 1;
optionValuesMode[2] = 2;
addFormSelector(string, F("Measure range"), F("plugin_027_range"), 3, optionsMode, optionValuesMode, choiceMode);
addFormSelector(F("Measure range"), F("plugin_027_range"), 3, optionsMode, optionValuesMode, choiceMode);
addFormSelectorI2C(string, F("plugin_027_i2c"), 4, Plugin_27_i2c_addresses, Plugin_027_i2c_addr(event));
addFormSelectorI2C(F("plugin_027_i2c"), 4, Plugin_27_i2c_addresses, Plugin_027_i2c_addr(event));
byte choiceMeasureType = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
String options[4] = { F("Voltage"), F("Current"), F("Power"), F("Voltage/Current/Power") };
addFormSelector(string, F("Measurement Type"), F("plugin_027_measuretype"), 4, options, NULL, choiceMeasureType );
addFormSelector(F("Measurement Type"), F("plugin_027_measuretype"), 4, options, NULL, choiceMeasureType );
success = true;
break;
+8 -8
View File
@@ -213,25 +213,25 @@ boolean Plugin_028(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
const uint8_t i2cAddress = Plugin_028_i2c_addr(event);
addFormSelectorI2C(string, F("plugin_028_bme280_i2c"), 2, Plugin_28_i2c_addresses, i2cAddress);
addFormSelectorI2C(F("plugin_028_bme280_i2c"), 2, Plugin_28_i2c_addresses, i2cAddress);
const uint8_t idx = Plugin_028_device_index(i2cAddress);
if (_sensorID[idx] != Unknown_DEVICE) {
String detectedString = F("Detected: ");
detectedString += Plugin_028_getFullDeviceName();
addUnit(string, detectedString);
addUnit(detectedString);
}
addFormNote(string, F("SDO Low=0x76, High=0x77"));
addFormNote(F("SDO Low=0x76, High=0x77"));
addFormNumericBox(string, F("Altitude"), F("plugin_028_bme280_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
addUnit(string, F("m"));
addFormNumericBox(F("Altitude"), F("plugin_028_bme280_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
addUnit(F("m"));
addFormNumericBox(string, F("Temperature offset"), F("plugin_028_bme280_tempoffset"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
addUnit(string, F("x 0.1C"));
addFormNumericBox(F("Temperature offset"), F("plugin_028_bme280_tempoffset"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
addUnit(F("x 0.1C"));
String offsetNote = F("Offset in units of 0.1 degree Celcius");
if (Plugin_028_hasHumidity()) {
offsetNote += F(" (also correct humidity)");
}
addFormNote(string, offsetNote);
addFormNote(offsetNote);
success = true;
break;
+3 -3
View File
@@ -5,7 +5,7 @@
#define PLUGIN_029
#define PLUGIN_ID_029 29
#define PLUGIN_NAME_029 "Output - (Domoticz MQTT helper)"
#define PLUGIN_NAME_029 "Output - Domoticz MQTT Helper"
#define PLUGIN_VALUENAME1_029 "Output"
boolean Plugin_029(byte function, struct EventStruct *event, String& string)
{
@@ -50,10 +50,10 @@ boolean Plugin_029(byte function, struct EventStruct *event, String& string)
if (Settings.Protocol[i] == 2) { controllerNr = i; }
}
string += F("<TR><TD>IDX:<TD>");
addHtml(F("<TR><TD>IDX:<TD>"));
String id = F("TDID"); //="taskdeviceid"
id += controllerNr + 1;
addNumericBox(string, id, Settings.TaskDeviceID[controllerNr][event->TaskIndex], 0, 9999);
addNumericBox(id, Settings.TaskDeviceID[controllerNr][event->TaskIndex], 0, 9999);
success = true;
break;
}
+4 -4
View File
@@ -106,11 +106,11 @@ boolean Plugin_030(byte function, struct EventStruct *event, String& string)
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
/*String options[2] = { F("0x76 - default settings (SDO Low)"), F("0x77 - alternate settings (SDO HIGH)") };*/
int optionValues[2] = { 0x76, 0x77 };
addFormSelectorI2C(string, F("plugin_030_bmp280_i2c"), 2, optionValues, choice);
addFormNote(string, F("SDO Low=0x76, High=0x77"));
addFormSelectorI2C(F("plugin_030_bmp280_i2c"), 2, optionValues, choice);
addFormNote(F("SDO Low=0x76, High=0x77"));
addFormNumericBox(string, F("Altitude"), F("plugin_030_bmp280_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
addUnit(string, F("m"));
addFormNumericBox(F("Altitude"), F("plugin_030_bmp280_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
addUnit(F("m"));
success = true;
break;
+2 -2
View File
@@ -73,9 +73,9 @@ boolean Plugin_032(byte function, struct EventStruct *event, String& string)
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
/*String options[2] = { F("0x77 - default I2C address"), F("0x76 - alternate I2C address") };*/
int optionValues[2] = { 0x77, 0x76 };
addFormSelectorI2C(string, F("plugin_032_ms5611_i2c"), 2, optionValues, choice);
addFormSelectorI2C(F("plugin_032_ms5611_i2c"), 2, optionValues, choice);
addFormNumericBox(string, F("Altitude [m]"), F("plugin_032_ms5611_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
addFormNumericBox(F("Altitude [m]"), F("plugin_032_ms5611_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
success = true;
break;
+1 -1
View File
@@ -71,7 +71,7 @@ boolean Plugin_033(byte function, struct EventStruct *event, String& string)
optionValues[9] = SENSOR_TYPE_LONG;
optionValues[10] = SENSOR_TYPE_WIND;
addFormSelector(string, F("Simulate Data Type"), F("plugin_033_sensortype"), 11, options, optionValues, choice );
addFormSelector(F("Simulate Data Type"), F("plugin_033_sensortype"), 11, options, optionValues, choice );
success = true;
break;
-2
View File
@@ -2,7 +2,6 @@
//#######################################################################################################
//#################################### Plugin 035: Output IR ############################################
//#######################################################################################################
#ifdef PLUGIN_BUILD_NORMAL
#include <IRremoteESP8266.h>
IRsend *Plugin_035_irSender;
@@ -233,5 +232,4 @@ boolean Plugin_035(byte function, struct EventStruct *event, String& string)
return success;
}
#endif
#endif // USES_P035
+14 -14
View File
@@ -26,10 +26,10 @@
#define P36_CONTRAST_HIGH 0xFF
#include "SSD1306.h"
#include "SH1106Wire.h"
#include "OLED_SSD1306_SH1106_images.h"
#include "Dialog_Plain_12_font.h"
#include "SSD1306.h"
#include "SH1106Wire.h"
#include "OLED_SSD1306_SH1106_images.h"
#include "Dialog_Plain_12_font.h"
#define P36_WIFI_STATE_UNSET -2
#define P36_WIFI_STATE_NOT_CONNECTED -1
@@ -62,7 +62,7 @@ boolean Plugin_036(byte function, struct EventStruct *event, String& string)
{
Device[++deviceCount].Number = PLUGIN_ID_036;
Device[deviceCount].Type = DEVICE_TYPE_I2C;
Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
Device[deviceCount].VType = SENSOR_TYPE_NONE;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
@@ -94,7 +94,7 @@ boolean Plugin_036(byte function, struct EventStruct *event, String& string)
options5[0] = F("SSD1306");
options5[1] = F("SH1106");
int optionValues5[2] = { 1, 2 };
addFormSelector(string, F("Controler"), F("plugin_036_controler"), 2, options5, optionValues5, choice5);
addFormSelector(F("Controler"), F("plugin_036_controler"), 2, options5, optionValues5, choice5);
byte choice0 = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
/*
@@ -105,14 +105,14 @@ boolean Plugin_036(byte function, struct EventStruct *event, String& string)
int optionValues0[2];
optionValues0[0] = 0x3C;
optionValues0[1] = 0x3D;
addFormSelectorI2C(string, F("plugin_036_adr"), 2, optionValues0, choice0);
addFormSelectorI2C(F("plugin_036_adr"), 2, optionValues0, choice0);
byte choice1 = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
String options1[2];
options1[0] = F("Normal");
options1[1] = F("Rotated");
int optionValues1[2] = { 1, 2 };
addFormSelector(string, F("Rotation"), F("plugin_036_rotate"), 2, options1, optionValues1, choice1);
addFormSelector(F("Rotation"), F("plugin_036_rotate"), 2, options1, optionValues1, choice1);
byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
String options2[4];
@@ -121,7 +121,7 @@ boolean Plugin_036(byte function, struct EventStruct *event, String& string)
options2[2] = F("3");
options2[3] = F("4");
int optionValues2[4] = { 1, 2, 3, 4 };
addFormSelector(string, F("Lines per Frame"), F("plugin_036_nlines"), 4, options2, optionValues2, choice2);
addFormSelector(F("Lines per Frame"), F("plugin_036_nlines"), 4, options2, optionValues2, choice2);
byte choice3 = Settings.TaskDevicePluginConfig[event->TaskIndex][3];
String options3[5];
@@ -136,18 +136,18 @@ boolean Plugin_036(byte function, struct EventStruct *event, String& string)
optionValues3[2] = 4;
optionValues3[3] = 8;
optionValues3[4] = 32;
addFormSelector(string, F("Scroll"), F("plugin_036_scroll"), 5, options3, optionValues3, choice3);
addFormSelector(F("Scroll"), F("plugin_036_scroll"), 5, options3, optionValues3, choice3);
LoadCustomTaskSettings(event->TaskIndex, (byte*)&P036_deviceTemplate, sizeof(P036_deviceTemplate));
for (byte varNr = 0; varNr < P36_Nlines; varNr++)
{
addFormTextBox(string, String(F("Line ")) + (varNr + 1), String(F("Plugin_036_template")) + (varNr + 1), P036_deviceTemplate[varNr], P36_Nchars);
addFormTextBox(String(F("Line ")) + (varNr + 1), String(F("Plugin_036_template")) + (varNr + 1), P036_deviceTemplate[varNr], P36_Nchars);
}
addFormPinSelect(string, F("Display button"), F("taskdevicepin3"), Settings.TaskDevicePin3[event->TaskIndex]);
addFormPinSelect(F("Display button"), F("taskdevicepin3"), Settings.TaskDevicePin3[event->TaskIndex]);
addFormNumericBox(string, F("Display Timeout"), F("plugin_036_timer"), Settings.TaskDevicePluginConfig[event->TaskIndex][4]);
addFormNumericBox(F("Display Timeout"), F("plugin_036_timer"), Settings.TaskDevicePluginConfig[event->TaskIndex][4]);
byte choice6 = Settings.TaskDevicePluginConfig[event->TaskIndex][6];
if (choice6 == 0) choice6 = P36_CONTRAST_HIGH;
@@ -159,7 +159,7 @@ boolean Plugin_036(byte function, struct EventStruct *event, String& string)
optionValues6[0] = P36_CONTRAST_LOW;
optionValues6[1] = P36_CONTRAST_MED;
optionValues6[2] = P36_CONTRAST_HIGH;
addFormSelector(string, F("Contrast"), F("plugin_036_contrast"), 3, options6, optionValues6, choice6);
addFormSelector(F("Contrast"), F("plugin_036_contrast"), 3, options6, optionValues6, choice6);
success = true;
break;
+7 -3
View File
@@ -36,8 +36,11 @@ void Plugin_037_update_connect_status() {
String event = connected ? F("MQTTimport#Connected") : F("MQTTimport#Disconnected");
rulesProcessing(event);
}
if (!connected)
if (!connected) {
// workaround see: https://github.com/esp8266/Arduino/issues/4497#issuecomment-373023864
espclient_037 = WiFiClient();
addLog(LOG_LEVEL_ERROR, F("IMPT : MQTT 037 Connection lost"));
}
}
}
@@ -92,7 +95,7 @@ boolean Plugin_037(byte function, struct EventStruct *event, String& string)
for (byte varNr = 0; varNr < 4; varNr++)
{
addFormTextBox(string, String(F("MQTT Topic ")) + (varNr + 1), String(F("Plugin_037_template")) +
addFormTextBox(String(F("MQTT Topic ")) + (varNr + 1), String(F("Plugin_037_template")) +
(varNr + 1), deviceTemplate[varNr], 40);
}
success = true;
@@ -118,8 +121,9 @@ boolean Plugin_037(byte function, struct EventStruct *event, String& string)
case PLUGIN_INIT:
{
if (!MQTTclient_037)
if (!MQTTclient_037) {
MQTTclient_037 = new PubSubClient(espclient_037);
}
// When we edit the subscription data from the webserver, the plugin is called again with init.
// In order to resubscribe we have to disconnect and reconnect in order to get rid of any obsolete subscriptions
+4 -4
View File
@@ -27,7 +27,7 @@ Adafruit_NeoPixel *Plugin_038_pixels;
#define PLUGIN_038
#define PLUGIN_ID_038 38
#define PLUGIN_NAME_038 "Output - NeoPixel (basic)"
#define PLUGIN_NAME_038 "Output - NeoPixel (Basic)"
#define PLUGIN_VALUENAME1_038 ""
int MaxPixels = 0;
@@ -65,9 +65,9 @@ boolean Plugin_038(byte function, struct EventStruct *event, String& string)
const String options[] = { F("GRB"), F("GRBW") };
int indices[] = { 1, 2 };
addFormNumericBox(string, F("Led Count"), F("plugin_038_leds"), Settings.TaskDevicePluginConfig[event->TaskIndex][0],1,999);
addFormPinSelect(string, F("GPIO"), F("taskdevicepin1"), Settings.TaskDevicePin1[event->TaskIndex]);
addFormSelector(string, F("Strip Type"), F("plugin_038_strip"), 2, options, indices, Settings.TaskDevicePluginConfig[event->TaskIndex][1] );
addFormNumericBox(F("Led Count"), F("plugin_038_leds"), Settings.TaskDevicePluginConfig[event->TaskIndex][0],1,999);
addFormPinSelect(F("GPIO"), F("taskdevicepin1"), Settings.TaskDevicePin1[event->TaskIndex]);
addFormSelector(F("Strip Type"), F("plugin_038_strip"), 2, options, indices, Settings.TaskDevicePluginConfig[event->TaskIndex][1] );
success = true;
break;
+3 -3
View File
@@ -104,8 +104,8 @@ boolean Plugin_039(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormNote(string, F("<b>1st GPIO</b> = CS (Usable GPIOs : 0, 2, 4, 5, 15)"));
//string += F("<TR><TD>Info GPIO:<TD><b>1st GPIO</b> = CS (Usable GPIOs : 0, 2, 4, 5, 15)");
addFormNote(F("<b>1st GPIO</b> = CS (Usable GPIOs : 0, 2, 4, 5, 15)"));
//addHtml(F("<TR><TD>Info GPIO:<TD><b>1st GPIO</b> = CS (Usable GPIOs : 0, 2, 4, 5, 15)"));
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
String options[2];
@@ -113,7 +113,7 @@ boolean Plugin_039(byte function, struct EventStruct *event, String& string)
options[1] = F("MAX 31855");
//options[2] = F("MAX 31865");
int optionValues[2] = { 1, 2 };
addFormSelector(string, F("Adapter IC"), F("plugin_039_maxtype"), 2, options, optionValues, choice);
addFormSelector(F("Adapter IC"), F("plugin_039_maxtype"), 2, options, optionValues, choice);
success = true;
break;
+4 -5
View File
@@ -27,7 +27,7 @@ boolean Plugin_041(byte function, struct EventStruct *event, String& string)
{
Device[++deviceCount].Number = PLUGIN_ID_041;
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
Device[deviceCount].VType = SENSOR_TYPE_NONE;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
@@ -51,9 +51,9 @@ boolean Plugin_041(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(string, F("Red"), F("plugin_041_red"), Settings.TaskDevicePluginConfig[event->TaskIndex][0], 0, 255);
addFormNumericBox(string, F("Green"), F("plugin_041_green"), Settings.TaskDevicePluginConfig[event->TaskIndex][1], 0, 255);
addFormNumericBox(string, F("Blue"), F("plugin_041_blue"), Settings.TaskDevicePluginConfig[event->TaskIndex][2], 0, 255);
addFormNumericBox(F("Red"), F("plugin_041_red"), Settings.TaskDevicePluginConfig[event->TaskIndex][0], 0, 255);
addFormNumericBox(F("Green"), F("plugin_041_green"), Settings.TaskDevicePluginConfig[event->TaskIndex][1], 0, 255);
addFormNumericBox(F("Blue"), F("plugin_041_blue"), Settings.TaskDevicePluginConfig[event->TaskIndex][2], 0, 255);
success = true;
break;
}
@@ -66,7 +66,6 @@ boolean Plugin_041(byte function, struct EventStruct *event, String& string)
Plugin_041_red = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
Plugin_041_green = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
Plugin_041_blue = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
Plugin_041_update();
success = true;
break;
}
+34 -34
View File
@@ -135,7 +135,7 @@ boolean Plugin_042(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
string += F("<script src=\"jscolor.min.js\"></script>\n");
addHtml(F("<script src=\"jscolor.min.js\"></script>\n"));
char tmpString[128];
String options[8];
@@ -157,25 +157,25 @@ boolean Plugin_042(byte function, struct EventStruct *event, String& string)
}
// Candle Type Selection
addFormSelector(string, F("Flame Type"), F("web_Candle_Type"), 8, options, NULL, choice);
addFormSelector(F("Flame Type"), F("web_Candle_Type"), 8, options, NULL, choice);
// Advanced Color options
Candle_color = (ColorType)Settings.TaskDevicePluginConfig[event->TaskIndex][5];
string += F("<TR><TD>Color Handling:<TD>"); // checked
string += F("<input type='radio' id='web_Color_Default' name='web_Color_Type' value='0'");
addHtml(F("<TR><TD>Color Handling:<TD>")); // checked
addHtml(F("<input type='radio' id='web_Color_Default' name='web_Color_Type' value='0'"));
if (Candle_color == ColorDefault) {
string += F(" checked>");
addHtml(F(" checked>"));
} else {
string += F(">");
addHtml(F(">"));
}
string += F("<label for='web_Color_Default'> Use default color</label><br>");
string += F("<input type='radio' id='web_Color_Selected' name='web_Color_Type' value='1'");
addHtml(F("<label for='web_Color_Default'> Use default color</label><br>"));
addHtml(F("<input type='radio' id='web_Color_Selected' name='web_Color_Type' value='1'"));
if (Candle_color == ColorSelected) {
string += F(" checked>");
addHtml(F(" checked>"));
} else {
string += F(">");
addHtml(F(">"));
}
string += F("<label for='web_Color_Selected'> Use selected color</label><br>");
addHtml(F("<label for='web_Color_Selected'> Use selected color</label><br>"));
// Color Selection
char hexvalue[7] = {0};
@@ -185,36 +185,36 @@ boolean Plugin_042(byte function, struct EventStruct *event, String& string)
Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
// http://jscolor.com/examples/
string += F("<TR><TD>Color:<TD><input class=\"jscolor {onFineChange:'update(this)'}\" value='");
string += hexvalue;
string += F("'>");
addFormNumericBox(string, F("RGB Color"), F("web_RGB_Red"), Settings.TaskDevicePluginConfig[event->TaskIndex][0], 0, 255);
addNumericBox(string, F("web_RGB_Green"), Settings.TaskDevicePluginConfig[event->TaskIndex][1], 0, 255);
addNumericBox(string, F("web_RGB_Blue"), Settings.TaskDevicePluginConfig[event->TaskIndex][2], 0, 255);
addHtml(F("<TR><TD>Color:<TD><input class=\"jscolor {onFineChange:'update(this)'}\" value='"));
addHtml(hexvalue);
addHtml(F("'>"));
addFormNumericBox(F("RGB Color"), F("web_RGB_Red"), Settings.TaskDevicePluginConfig[event->TaskIndex][0], 0, 255);
addNumericBox(F("web_RGB_Green"), Settings.TaskDevicePluginConfig[event->TaskIndex][1], 0, 255);
addNumericBox(F("web_RGB_Blue"), Settings.TaskDevicePluginConfig[event->TaskIndex][2], 0, 255);
// Brightness Selection
string += F("<TR><TD>Brightness:<TD>min<input type='range' id='web_Bright_Slide' min='0' max='255' value='");
string += Settings.TaskDevicePluginConfig[event->TaskIndex][3];
string += F("'> max");
addHtml(F("<TR><TD>Brightness:<TD>min<input type='range' id='web_Bright_Slide' min='0' max='255' value='"));
addHtml(String(Settings.TaskDevicePluginConfig[event->TaskIndex][3]));
addHtml(F("'> max"));
sprintf_P(tmpString, PSTR("<TR><TD>Brightness Value:<TD><input type='text' name='web_Bright_Text' id='web_Bright_Text' size='3' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
string += tmpString;
addHtml(tmpString);
// Some Javascript we need to update the items
string += F("<script script type='text/javascript'>");
string += F("function update(picker) {");
string += F(" document.getElementById('web_RGB_Red').value = Math.round(picker.rgb[0]);");
string += F(" document.getElementById('web_RGB_Green').value = Math.round(picker.rgb[1]);");
string += F(" document.getElementById('web_RGB_Blue').value = Math.round(picker.rgb[2]);");
string += F("}");
string += F("</script>");
addHtml(F("<script script type='text/javascript'>"));
addHtml(F("function update(picker) {"));
addHtml(F(" document.getElementById('web_RGB_Red').value = Math.round(picker.rgb[0]);"));
addHtml(F(" document.getElementById('web_RGB_Green').value = Math.round(picker.rgb[1]);"));
addHtml(F(" document.getElementById('web_RGB_Blue').value = Math.round(picker.rgb[2]);"));
addHtml(F("}"));
addHtml(F("</script>"));
string += F("<script type='text/javascript'>window.addEventListener('load', function(){");
string += F("var slider = document.getElementById('web_Bright_Slide');");
string += F("slider.addEventListener('change', function(){");
string += F("document.getElementById('web_Bright_Text').value = this.value;");
string += F("});");
string += F("});</script>");
addHtml(F("<script type='text/javascript'>window.addEventListener('load', function(){"));
addHtml(F("var slider = document.getElementById('web_Bright_Slide');"));
addHtml(F("slider.addEventListener('change', function(){"));
addHtml(F("document.getElementById('web_Bright_Text').value = this.value;"));
addHtml(F("});"));
addHtml(F("});</script>"));
success = true;
break;
+10 -10
View File
@@ -50,18 +50,18 @@ boolean Plugin_043(byte function, struct EventStruct *event, String& string)
for (byte x = 0; x < PLUGIN_043_MAX_SETTINGS; x++)
{
addFormTextBox(string, String(F("Day,Time ")) + (x + 1), String(F("plugin_043_clock")) + (x), timeLong2String(ExtraTaskSettings.TaskDevicePluginConfigLong[x]), 32);
// string += F("<TR><TD>Day,Time ");
// string += x+1;
// string += F(":<TD><input type='text' name='plugin_043_clock");
// string += x;
// string += F("' value='");
// string += timeLong2String(ExtraTaskSettings.TaskDevicePluginConfigLong[x]);
// string += F("'>");
addFormTextBox(String(F("Day,Time ")) + (x + 1), String(F("plugin_043_clock")) + (x), timeLong2String(ExtraTaskSettings.TaskDevicePluginConfigLong[x]), 32);
// addHtml(F("<TR><TD>Day,Time "));
// addHtml(x+1);
// addHtml(F(":<TD><input type='text' name='plugin_043_clock"));
// addHtml(x);
// addHtml(F("' value='"));
// addHtml(timeLong2String(ExtraTaskSettings.TaskDevicePluginConfigLong[x]));
// addHtml(F("'>"));
string += F(" ");
addHtml(F(" "));
byte choice = ExtraTaskSettings.TaskDevicePluginConfig[x];
addSelector(string, String(F("plugin_043_state")) + (x), 3, options, NULL, NULL, choice, false);
addSelector(String(F("plugin_043_state")) + (x), 3, options, NULL, NULL, choice, false);
}
success = true;
break;
+7 -7
View File
@@ -66,9 +66,9 @@ boolean Plugin_044(byte function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(string, F("TCP Port"), F("plugin_044_port"), ExtraTaskSettings.TaskDevicePluginConfigLong[0]);
addFormNumericBox(string, F("Baud Rate"), F("plugin_044_baud"), ExtraTaskSettings.TaskDevicePluginConfigLong[1]);
addFormNumericBox(string, F("Data bits"), F("plugin_044_data"), ExtraTaskSettings.TaskDevicePluginConfigLong[2]);
addFormNumericBox(F("TCP Port"), F("plugin_044_port"), ExtraTaskSettings.TaskDevicePluginConfigLong[0]);
addFormNumericBox(F("Baud Rate"), F("plugin_044_baud"), ExtraTaskSettings.TaskDevicePluginConfigLong[1]);
addFormNumericBox(F("Data bits"), F("plugin_044_data"), ExtraTaskSettings.TaskDevicePluginConfigLong[2]);
byte choice = ExtraTaskSettings.TaskDevicePluginConfigLong[3];
String options[3];
@@ -76,13 +76,13 @@ boolean Plugin_044(byte function, struct EventStruct *event, String& string)
options[1] = F("Even");
options[2] = F("Odd");
int optionValues[3] = { 0, 2, 3 };
addFormSelector(string, F("Parity"), F("plugin_044_parity"), 3, options, optionValues, choice);
addFormSelector(F("Parity"), F("plugin_044_parity"), 3, options, optionValues, choice);
addFormNumericBox(string, F("Stop bits"), F("plugin_044_stop"), ExtraTaskSettings.TaskDevicePluginConfigLong[4]);
addFormNumericBox(F("Stop bits"), F("plugin_044_stop"), ExtraTaskSettings.TaskDevicePluginConfigLong[4]);
addFormPinSelect(string, F("Reset target after boot"), F("taskdevicepin1"), Settings.TaskDevicePin1[event->TaskIndex]);
addFormPinSelect(F("Reset target after boot"), F("taskdevicepin1"), Settings.TaskDevicePin1[event->TaskIndex]);
addFormNumericBox(string, F("RX Receive Timeout (mSec)"), F("plugin_044_rxwait"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
addFormNumericBox(F("RX Receive Timeout (mSec)"), F("plugin_044_rxwait"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
success = true;
break;

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