mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-28 04:07:47 +00:00
Compare commits
178
Commits
mega-20180213
...
v2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f59f25ee40 | ||
|
|
14030ec15b | ||
|
|
1fd6179408 | ||
|
|
22424fb03b | ||
|
|
97cd06440e | ||
|
|
8346e39ac9 | ||
|
|
22371649a4 | ||
|
|
8cbd9a0822 | ||
|
|
93f9d11738 | ||
|
|
cf3e0a3f0a | ||
|
|
ccfd14dbd3 | ||
|
|
3034738ad4 | ||
|
|
178d1c46a2 | ||
|
|
cdfd1d986e | ||
|
|
4b7aa53692 | ||
|
|
cc02fa4481 | ||
|
|
ab3a406706 | ||
|
|
3edfdbf5f7 | ||
|
|
1220c565c8 | ||
|
|
f0987dab41 | ||
|
|
af3e353181 | ||
|
|
c711d6ea51 | ||
|
|
1f084c51cc | ||
|
|
85e8d98da8 | ||
|
|
6d52a7e03a | ||
|
|
fa513b52f9 | ||
|
|
f98401524f | ||
|
|
4090b4f23c | ||
|
|
b89c00008d | ||
|
|
d57a617138 | ||
|
|
cefe6b4b7c | ||
|
|
2432740b41 | ||
|
|
44a934651c | ||
|
|
6787bc8c0e | ||
|
|
cf644b45b1 | ||
|
|
e6fe1c63a9 | ||
|
|
df978036f0 | ||
|
|
7cb375833d | ||
|
|
3218ea9839 | ||
|
|
eca8901fca | ||
|
|
6635eafe91 | ||
|
|
fe4d1f952f | ||
|
|
4475a225cc | ||
|
|
2aece1c143 | ||
|
|
70df225e7e | ||
|
|
19af52a3ef | ||
|
|
3d396575ff | ||
|
|
826deaac89 | ||
|
|
cce621cff8 | ||
|
|
57eb38dbd0 | ||
|
|
fd2451bb07 | ||
|
|
cc0b3dac26 | ||
|
|
d3434eb4d2 | ||
|
|
bd2665041f | ||
|
|
1fd429a029 | ||
|
|
e4d4463eab | ||
|
|
b29f56c6f4 | ||
|
|
779514481d | ||
|
|
0a752dd26f | ||
|
|
8112e0e67a | ||
|
|
89a9f842fd | ||
|
|
92932fddb2 | ||
|
|
89581fd0fb | ||
|
|
3f84a961ad | ||
|
|
96bfaa27f5 | ||
|
|
bcca0514dd | ||
|
|
bb9f8fc809 | ||
|
|
4d9504bce0 | ||
|
|
ff3a769033 | ||
|
|
e3de56a7a8 | ||
|
|
2682b0bd2f | ||
|
|
5097157a09 | ||
|
|
02ea957894 | ||
|
|
c2b0d76595 | ||
|
|
91b7cbe075 | ||
|
|
64b38df187 | ||
|
|
76f6dfdc59 | ||
|
|
3a6f7acd15 | ||
|
|
d65b126f84 | ||
|
|
8299e38b24 | ||
|
|
67a28a7f97 | ||
|
|
18b8e61d32 | ||
|
|
5821b0709c | ||
|
|
ec783fe03b | ||
|
|
9122565431 | ||
|
|
64a0f79e02 | ||
|
|
92e4a8da9b | ||
|
|
40e2d7ec8e | ||
|
|
7318e87965 | ||
|
|
9c3a28439f | ||
|
|
127627a22c | ||
|
|
e59401e24f | ||
|
|
769f76d3dc | ||
|
|
4eb7cf0859 | ||
|
|
a464f638ad | ||
|
|
a5cfe1beec | ||
|
|
a8fcb420e7 | ||
|
|
3ed6564063 | ||
|
|
5f575c0224 | ||
|
|
34c1ba158f | ||
|
|
04ca424085 | ||
|
|
7a8f476e05 | ||
|
|
e42ab85f4b | ||
|
|
3094cb5260 | ||
|
|
0e67480f46 | ||
|
|
c32f2cc89d | ||
|
|
ad489f0db2 | ||
|
|
d9267fa9c2 | ||
|
|
e82fb37870 | ||
|
|
26f00dcdec | ||
|
|
b2bb1d039b | ||
|
|
c58e975b7e | ||
|
|
08312cbcb7 | ||
|
|
953a53bb9a | ||
|
|
e9fac7926f | ||
|
|
810a0b2aa9 | ||
|
|
5d9137d1d2 | ||
|
|
8de49cd38e | ||
|
|
fe1c44f6b3 | ||
|
|
e39d588530 | ||
|
|
4ca318f5a6 | ||
|
|
37a24933f5 | ||
|
|
a6b447600f | ||
|
|
5fbb900e5b | ||
|
|
aa5dee01fb | ||
|
|
1a44ed6578 | ||
|
|
e86667e37e | ||
|
|
0db1f78421 | ||
|
|
780c34846e | ||
|
|
a938bc78c1 | ||
|
|
d2c7743197 | ||
|
|
d35a50be17 | ||
|
|
04de145dbb | ||
|
|
21840d0b26 | ||
|
|
555ccbe229 | ||
|
|
b5e4994392 | ||
|
|
51ede17d2a | ||
|
|
97ee69b371 | ||
|
|
f77ce9c8f7 | ||
|
|
848f43b704 | ||
|
|
3a5ef5da81 | ||
|
|
54628bfca9 | ||
|
|
aed566b6db | ||
|
|
504ea0c813 | ||
|
|
4ca5ef3f72 | ||
|
|
67c8477a61 | ||
|
|
3d07466904 | ||
|
|
03ee569510 | ||
|
|
af519748a6 | ||
|
|
2bece45712 | ||
|
|
10c73a001a | ||
|
|
233ca2bf43 | ||
|
|
edeea02f71 | ||
|
|
b31b1d913f | ||
|
|
fa3d4af8cb | ||
|
|
29320aab90 | ||
|
|
3bc8609611 | ||
|
|
c43d6b3769 | ||
|
|
e9e2ea32ed | ||
|
|
24b7d1f438 | ||
|
|
4febf08501 | ||
|
|
7f4eae19f4 | ||
|
|
c13952d04c | ||
|
|
e51f7683a5 | ||
|
|
1ad6fd6ea0 | ||
|
|
d2ec15a4bf | ||
|
|
f23d9fa3d3 | ||
|
|
3cea522ec4 | ||
|
|
a93a078c0b | ||
|
|
0e0e7be95a | ||
|
|
ce02c9e039 | ||
|
|
1e9dc1d14c | ||
|
|
9a6f7360da | ||
|
|
d835ef679c | ||
|
|
9144e7901b | ||
|
|
858ce397c3 | ||
|
|
78c9ff70be | ||
|
|
40eb3e7ceb |
+6
-1
@@ -27,7 +27,12 @@ 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 -s
|
||||
- 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
|
||||
|
||||
|
||||
before_deploy:
|
||||
- ./before_deploy
|
||||
|
||||
+25
-14
@@ -1,24 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION=$(git describe)
|
||||
echo "Creating release archives for $VERSION ..."
|
||||
#binaries
|
||||
|
||||
#ESP_Easy_v[version]-[build type]-dev[dev number]-ESP[chip type]-[size].bin
|
||||
#Naming convention:
|
||||
# ESP_Easy_[github version]_[plugin set]_[chip type]_[flash memory].bin
|
||||
|
||||
#cp .pioenvs/mini_512/firmware.bin dist/"ESPEasy_$VERSION""_mini_512.bin"
|
||||
|
||||
cp .pioenvs/normal_ESP8266_1024/firmware.bin dist/"ESP_Easy_$VERSION""_normal_ESP8266_1024.bin"
|
||||
cp .pioenvs/normal_ESP8266_4096/firmware.bin dist/"ESP_Easy_$VERSION""_normal_ESP8266_4096.bin"
|
||||
cp .pioenvs/normal_ESP8285_1024/firmware.bin dist/"ESP_Easy_$VERSION""_normal_ESP8285_1024.bin"
|
||||
for ENV in \
|
||||
normal_ESP8266_1024 \
|
||||
normal_ESP8266_4096 \
|
||||
normal_ESP8285_1024 \
|
||||
normal_ESP8266_1024_DOUT \
|
||||
test_ESP8266_1024\
|
||||
test_ESP8266_4096\
|
||||
test_ESP8266_4096_VCC\
|
||||
test_ESP8285_1024\
|
||||
dev_ESP8266_1024\
|
||||
dev_ESP8266_4096\
|
||||
dev_ESP8285_1024\
|
||||
dev_ESP8266PUYA_1024\
|
||||
dev_ESP8266PUYA_1024_VCC;\
|
||||
do
|
||||
echo
|
||||
echo "### Deploying environment $ENV for version $VERSION"
|
||||
BIN=.pioenvs/$ENV/firmware.bin
|
||||
cp $BIN dist/"ESP_Easy_$VERSION""_$ENV.bin"
|
||||
done
|
||||
|
||||
cp .pioenvs/test_ESP8266_1024/firmware.bin dist/"ESP_Easy_$VERSION""_test_ESP8266_1024.bin"
|
||||
cp .pioenvs/test_ESP8266_4096/firmware.bin dist/"ESP_Easy_$VERSION""_test_ESP8266_4096.bin"
|
||||
cp .pioenvs/test_ESP8285_1024/firmware.bin dist/"ESP_Easy_$VERSION""_test_ESP8285_1024.bin"
|
||||
|
||||
cp .pioenvs/dev_ESP8266_1024/firmware.bin dist/"ESP_Easy_$VERSION""_dev_ESP8266_1024.bin"
|
||||
cp .pioenvs/dev_ESP8266_4096/firmware.bin dist/"ESP_Easy_$VERSION""_dev_ESP8266_4096.bin"
|
||||
cp .pioenvs/dev_ESP8285_1024/firmware.bin dist/"ESP_Easy_$VERSION""_dev_ESP8285_1024.bin"
|
||||
|
||||
#create a source structure that is the same as the original ESPEasy project (and works with the howto on the wiki)
|
||||
rm -rf dist/Source 2>/dev/null
|
||||
@@ -28,4 +36,7 @@ cp -r src dist/Source/
|
||||
cp platformio.ini dist/Source/
|
||||
|
||||
cd dist
|
||||
|
||||
echo
|
||||
echo "### Creating zip archive"
|
||||
zip ../ESPEasy_$VERSION.zip -r .
|
||||
|
||||
Vendored
+433
@@ -1,3 +1,436 @@
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180510 (since v2.0-20180322)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Thu May 10 04:00:27 CEST 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
Revert "Update _P045_MPU6050.ino"
|
||||
|
||||
Maarten Paauw (1):
|
||||
Update _P045_MPU6050.ino
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180322 (since v2.0-20180321)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Thu Mar 22 04:00:24 CET 2018
|
||||
|
||||
Bartlomiej Zimon (3):
|
||||
- P012 fix command interpretation
|
||||
- P023 fix command interpretation
|
||||
- P048 fetch params only when needed
|
||||
|
||||
TD-er (4):
|
||||
- P035 move strings to flash
|
||||
[wifi] Make more robust checks and increase timeout
|
||||
[Memory] parseTemplate did not check if markers were found
|
||||
[WiFi] Take much more time for initial WiFi connect during setup
|
||||
|
||||
s0170071 (1):
|
||||
Serial WD crash
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180321 (since v2.0-20180320)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Mar 21 04:00:21 CET 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
[merge issue] Forgotten #endif in merge
|
||||
|
||||
Unknown (1):
|
||||
[wifi] Setup with factory settings could not complete
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180320 (since v2.0-20180319)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Mar 20 04:00:23 CET 2018
|
||||
|
||||
Unknown (2):
|
||||
Revert "Merge pull request #1116 from TD-er/feature/allow_own_defaults"
|
||||
[issue #1097] WiFi connect with deepsleep enabled trigger watchdog reset
|
||||
|
||||
es-ka (1):
|
||||
Fix wiring description for SN75176 transceiver
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180319 (since v2.0-20180316)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Mar 19 04:00:24 CET 2018
|
||||
|
||||
Gijs Noorlander (6):
|
||||
Add download button for current rule set (#1102)
|
||||
- add encoder write command #1086 (#1103)
|
||||
Changed so that running all tasks immediately with deep sleep enabled… (#1110)
|
||||
Merge pull request #1112 from uzi18/fix-p073
|
||||
Merge pull request #1114 from TD-er/feature/wifi_details_json
|
||||
Merge pull request #1118 from TD-er/bugfix/mqtt_publish_after_deep_sleep
|
||||
|
||||
Unknown (3):
|
||||
Merge pull request #1113 from TD-er/feature/reduce_impact_wifi_disconnect
|
||||
Merge pull request #1116 from TD-er/feature/allow_own_defaults
|
||||
[merge] MIssing #endif due to merging.
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180316 (since v2.0-20180313)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Fri Mar 16 04:00:23 CET 2018
|
||||
|
||||
Bartlomiej Zimon (1):
|
||||
Merge branch 'mega' of github.com:letscontrolit/ESPEasy into mega
|
||||
|
||||
Gijs Noorlander (3):
|
||||
MCP3221 allow values for calibration (#1073)
|
||||
[issue #1066] Fix Webserver handle_control (#1079)
|
||||
Fixed multi instance problem on SHT3x #433 (#1081)
|
||||
|
||||
Unknown (5):
|
||||
- move all structs from ESPEasy.ino into header file
|
||||
[v2.0 split globals] Base split on v2.0 version of ESPEasy.ino
|
||||
[issue #1057] AM PM display issue
|
||||
[issue #993] variable in MQTT subscribe topic
|
||||
[issue #951] Changed System#Initialized => System#Wake
|
||||
|
||||
mvdbro (4):
|
||||
#893 part1, send messages
|
||||
Custom controller GUI option
|
||||
#893, part 2 receiving
|
||||
Rules fix
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180313 (since v2.0-20180312)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Mar 13 04:00:23 CET 2018
|
||||
|
||||
Bartlomiej Zimon (2):
|
||||
- fix for #1065
|
||||
- remove double trimm()
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180312 (since v2.0-20180311)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Mar 12 04:00:19 CET 2018
|
||||
|
||||
Unknown (3):
|
||||
[issue #1039 ] Change CSS to show topmost SSID on large screens
|
||||
[webserver] Improve chunked transfer
|
||||
Rule Engine minor fix and added dev debugging
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180311 (since v2.0-20180310)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Mar 11 04:00:19 CET 2018
|
||||
|
||||
Unknown (10):
|
||||
Improve flash read performance
|
||||
Add read buffer to rule processing to speedup parsing
|
||||
Final ruleset speed-up
|
||||
[AM/PM] Am/Pm notation doesn't have '0' hours
|
||||
Update P07 Plugin
|
||||
[P073] Remove tm1637_bitDelay()
|
||||
[deepsleep] Make sure the 'shortcut' of running all services when sleep enabled
|
||||
[OLED] fix drawProgressBar
|
||||
[DNS lookup] Controllers sometimes try to connect to 0.0.0.0
|
||||
[issue #1039] Topmost SSID are covered on mobile Browser
|
||||
|
||||
mvdbro (1):
|
||||
Rule Engine, stop waisting time on non matching rules
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180310 (since v2.0-20180309)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sat Mar 10 04:00:20 CET 2018
|
||||
|
||||
Unknown (2):
|
||||
Move plugin init before WiFi init
|
||||
[Conversions] Use more decimals in conversions and add AM/PM for time.
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180309 (since v2.0-20180307)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Fri Mar 9 04:00:22 CET 2018
|
||||
|
||||
Unknown (3):
|
||||
[Rule Events] Add a number of events to handle in rules and awake timer
|
||||
[issue #1015] Add other simple conversions like Celsius to Fahrenheit, etc.
|
||||
[issue #1015] Add other simple conversions like Celsius to Fahrenheit, etc.
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180307 (since v2.0-20180306)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Mar 7 04:00:21 CET 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
[CSS] Quick fix for smaller displays (#1026)
|
||||
|
||||
Unknown (1):
|
||||
[issue #1012] Removed Content-Length header + improved webserver speed
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180306 (since v2.0-20180305)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Mar 6 04:00:17 CET 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
Fixes P073 plugin for latest TM1637 based 7 segments displays modules (#996) (#1022)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180305 (since v2.0-20180304b)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Mar 5 04:00:20 CET 2018
|
||||
|
||||
Unknown (2):
|
||||
[issue #528] Set DOUT flash mode for all 1M builds
|
||||
[issue #1003 ] Add conversion of wind direction to string
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180304b (since v2.0-20180304)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Mar 4 18:20:49 CET 2018
|
||||
|
||||
Edwin Eefting (1):
|
||||
dont build in silent mode to prevent travis timeouts
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180304 (since v2.0-20180303)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Mar 4 04:00:19 CET 2018
|
||||
|
||||
Gijs Noorlander (2):
|
||||
Merge pull request #1000 from uzi18/test3 (more comparisions in IF condition)
|
||||
_P072_HDC1080 allow to send values to the controllers (#999)
|
||||
|
||||
Unknown (2):
|
||||
[issue #993] Add %unit% variable in MQTT subscribe topic
|
||||
[issue #892 ] Only use sensor type when really needed
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180303 (since v2.0-20180302)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sat Mar 3 04:00:19 CET 2018
|
||||
|
||||
Unknown (5):
|
||||
revert json to non-chunking #988 from s0170071/mega
|
||||
[issue #293] json output nan values not double quoted
|
||||
Add Task device type to json by @s0170071
|
||||
[Issue #827] MQTT not using proper case for %sysname% variable.
|
||||
Add AND/OR to rules & prevent unwanted case changes in strings (#994)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180302 (since v2.0-20180228)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Fri Mar 2 04:00:21 CET 2018
|
||||
|
||||
Bartłomiej Zimoń (4):
|
||||
provide System@Sleep event (#875)
|
||||
add format #O to templates to show OFF/ON instead 0/1 (#949)
|
||||
fix #964, add timeStringToSeconds and use it to compare time conditions (#965)
|
||||
add format #O to templates to show OFF/ON instead 0/1 (#949)
|
||||
|
||||
Gijs Noorlander (1):
|
||||
Merge pull request #983 from kahvm/mega
|
||||
|
||||
Unknown (4):
|
||||
[issue #914] _P053_PMSx003 Dust Sensor looses sync
|
||||
[issue #914] Check first 2 bytes of packet
|
||||
[Build error fix] Must-keep-focus-when-pressing-buttons...
|
||||
[webserver] Layout of code to improve readability
|
||||
|
||||
mvdbro (1):
|
||||
Rule wildcard option on literal events
|
||||
|
||||
s0170071 (1):
|
||||
Add Factory Reset button to web interface (#954)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180228 (since v2.0-20180227)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Feb 28 04:00:19 CET 2018
|
||||
|
||||
Gijs Noorlander (2):
|
||||
[issue #966] Add %sysweekday% and %sysweekday_s% (#973)
|
||||
[issue #968] Use template parser for OLED commands (#974)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180227 (since v2.0-20180226)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Feb 27 04:00:22 CET 2018
|
||||
|
||||
Edwin Eefting (2):
|
||||
[test suite] changes from mega to 2.0
|
||||
[test suite] changes from mega to 2.0
|
||||
|
||||
Gijs Noorlander (1):
|
||||
[BuildError] StreamingBuffer code cleanup + fix order member initialize (#961)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180226 (since v2.0-20180221)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Feb 26 04:00:21 CET 2018
|
||||
|
||||
Bartłomiej Zimoń (1):
|
||||
provide System@Sleep event (#875) (#931)
|
||||
|
||||
Edwin Eefting (1):
|
||||
device page doesnt need next/previous page buttons anymore
|
||||
|
||||
Gijs Noorlander (6):
|
||||
[MQTT] LWT "Connected" message doesn't have the retained flag (#925)
|
||||
[v2.0] Added Vcc-binaries to deploy process #933 (#935)
|
||||
[v2.0 merge] 2kwebserver_merge_to_mega #929 (#934)
|
||||
[v2.0] Use ESPeasySoftwareSerial (#936)
|
||||
[timeouts] Improve response when hosts are not reachable (#939)
|
||||
[2k Webserver] Proper initialisation of StreamingBuffer members. (#941)
|
||||
|
||||
Unknown (1):
|
||||
[ping lib] Added ping library
|
||||
|
||||
s0170071 (2):
|
||||
V20 Webserver@LowMemory
|
||||
Update WebServer.ino
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180221 (since v2.0-20180220)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Feb 21 04:00:20 CET 2018
|
||||
|
||||
Edwin Eefting (1):
|
||||
apply PUYA patch to all available frameworks
|
||||
|
||||
Gijs Noorlander (1):
|
||||
[issue #899 ] Backport of DHT22 implementation on Mega (#913)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180220 (since v2.0-20180219)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Feb 20 04:00:19 CET 2018
|
||||
|
||||
Edwin Eefting (1):
|
||||
SENSOR_TYPE_TEMP_BARO changed, was probably implemented incorrectly before
|
||||
|
||||
Gijs Noorlander (3):
|
||||
[isue #877] Add VCC enable firmware file to release list (#894)
|
||||
[Cleanup] Move String manipulating functions to single file (#895)
|
||||
[issue #893] Fix globalSync not working when no controllers active (#896)
|
||||
|
||||
Unknown (3):
|
||||
[issue #847] Fix last letter of command is cut in OpenHAB MQTT
|
||||
[Event Log] Add event name to event processing time log
|
||||
[issue #899] DHT22 readings not received
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180219 (since v2.0-20180218)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Mon Feb 19 04:00:19 CET 2018
|
||||
|
||||
Gijs Noorlander (2):
|
||||
[issue #885] MAC address as system variable (#887)
|
||||
[issue #890] Split overlap for both Domoticz controllers to helper (#891)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180218 (since v2.0-20180217)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sun Feb 18 04:00:11 CET 2018
|
||||
|
||||
Gijs Noorlander (1):
|
||||
[issue #847 ] OpenHAB MQTT rewrite topic parser (#886)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180217 (since v2.0-20180214)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Sat Feb 17 04:00:18 CET 2018
|
||||
|
||||
Gijs Noorlander (4):
|
||||
[issue 866] Try to stop logging to serial when serial is not read. (#868)
|
||||
[issue #853] Favicon.ico (#874)
|
||||
[OLED Framed] ESP Easy logo (#876)
|
||||
[issue #869] Added 'LWT' to last will topic and improved CPU load (#883)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180214 (since v2.0-20180213)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Wed Feb 14 04:00:21 CET 2018
|
||||
|
||||
Edwin Eefting (3):
|
||||
workaround for PUYA flash chips with write issues #650
|
||||
travis build fix for PUYA
|
||||
updated deploy script for PUYA
|
||||
|
||||
Gijs Noorlander (1):
|
||||
[v2.0] Blynk controller (#865)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180213 (since v2.0-20180212)
|
||||
-------------------------------------------------
|
||||
|
||||
Release date: Tue Feb 13 04:00:20 CET 2018
|
||||
|
||||
Gijs Noorlander (8):
|
||||
[#804] Degree symbol for non-framed OLED display (#835)
|
||||
[issue #839] Add command support for setting contrast for OLED Framed (#841)
|
||||
[P001 Switch] Fix a mixup in previous fix for switch (#845)
|
||||
[v2.0] Fix compile errors on ESP32 (#848)
|
||||
Bugfix/oled framed less memory (#859)
|
||||
Formatting user vars (re-do of PR#482) + enabled check OpenHabMQTT (#851)
|
||||
[issue #825] Change labels and password form for Thingspeak controller (#849)
|
||||
[MQTT] Allow for background tests while waiting for wifi (#860)
|
||||
|
||||
soif (1):
|
||||
P012 - Fix/handle lines exceeding LCD width + allow to clear line b4 print (#852)
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
Changes in release v2.0-20180212 (since v2.0-20180209)
|
||||
-------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
|
||||
ESPeasySoftwareSerial.cpp - Implementation of the Arduino software serial for ESP8266.
|
||||
Copyright (c) 2015-2016 Peter Lerup. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// The Arduino standard GPIO routines are not enough,
|
||||
// must use some from the Espressif SDK as well
|
||||
extern "C" {
|
||||
#include "gpio.h"
|
||||
}
|
||||
|
||||
#include <ESPeasySoftwareSerial.h>
|
||||
|
||||
#define MAX_PIN 15
|
||||
#define USABLE_PINS 10
|
||||
#define NR_CONCURRENT_SOFT_SERIALS 3
|
||||
|
||||
// As the Arduino attachInterrupt has no parameter, lists of objects
|
||||
// and callbacks corresponding to each possible GPIO pins have to be defined
|
||||
static ESPeasySoftwareSerial *ObjList[NR_CONCURRENT_SOFT_SERIALS];
|
||||
static uint8_t PinControllerMap[NR_CONCURRENT_SOFT_SERIALS]={}; // Zero all elements
|
||||
|
||||
void ICACHE_RAM_ATTR sws_isr_0() { ObjList[0]->rxRead(); };
|
||||
void ICACHE_RAM_ATTR sws_isr_1() { ObjList[1]->rxRead(); };
|
||||
void ICACHE_RAM_ATTR sws_isr_2() { ObjList[2]->rxRead(); };
|
||||
/*void ICACHE_RAM_ATTR sws_isr_3() { ObjList[3]->rxRead(); };
|
||||
void ICACHE_RAM_ATTR sws_isr_4() { ObjList[4]->rxRead(); };
|
||||
void ICACHE_RAM_ATTR sws_isr_5() { ObjList[5]->rxRead(); };
|
||||
// Pin 6 to 11 can not be used
|
||||
void ICACHE_RAM_ATTR sws_isr_12() { ObjList[6]->rxRead(); };
|
||||
void ICACHE_RAM_ATTR sws_isr_13() { ObjList[7]->rxRead(); };
|
||||
void ICACHE_RAM_ATTR sws_isr_14() { ObjList[8]->rxRead(); };
|
||||
void ICACHE_RAM_ATTR sws_isr_15() { ObjList[9]->rxRead(); };
|
||||
*/
|
||||
|
||||
static void (*ISRList[NR_CONCURRENT_SOFT_SERIALS])() = {
|
||||
sws_isr_0,
|
||||
sws_isr_1,
|
||||
sws_isr_2 /*,
|
||||
sws_isr_3,
|
||||
sws_isr_4,
|
||||
sws_isr_5,
|
||||
// Pin 6 to 11 can not be used
|
||||
sws_isr_12,
|
||||
sws_isr_13,
|
||||
sws_isr_14,
|
||||
sws_isr_15
|
||||
*/
|
||||
};
|
||||
|
||||
ESPeasySoftwareSerial::ESPeasySoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic, uint16_t buffSize) {
|
||||
m_rxValid = m_txValid = m_txEnableValid = false;
|
||||
m_buffer = NULL;
|
||||
m_invert = inverse_logic;
|
||||
if (isValidGPIOpin(receivePin)) {
|
||||
m_rxPin = receivePin;
|
||||
m_buffSize = buffSize;
|
||||
m_buffer = (uint8_t*)malloc(m_buffSize);
|
||||
if (m_buffer != NULL) {
|
||||
m_rxValid = true;
|
||||
m_inPos = m_outPos = 0;
|
||||
pinMode(m_rxPin, INPUT);
|
||||
const uint8_t index = pinToIndex(m_rxPin);
|
||||
if (index == NR_CONCURRENT_SOFT_SERIALS) {
|
||||
return; // Not possible to add software Serial.
|
||||
}
|
||||
ObjList[index] = this;
|
||||
enableRx(true);
|
||||
}
|
||||
}
|
||||
if (isValidGPIOpin(transmitPin)) {
|
||||
m_txValid = true;
|
||||
m_txPin = transmitPin;
|
||||
pinMode(m_txPin, OUTPUT);
|
||||
digitalWrite(m_txPin, !m_invert);
|
||||
}
|
||||
// Default speed
|
||||
begin(9600);
|
||||
}
|
||||
|
||||
ESPeasySoftwareSerial::~ESPeasySoftwareSerial() {
|
||||
enableRx(false);
|
||||
if (m_rxValid) {
|
||||
const uint8_t index = pinToIndex(m_rxPin);
|
||||
if (index < NR_CONCURRENT_SOFT_SERIALS) {
|
||||
PinControllerMap[index] = 0;
|
||||
ObjList[index] = NULL;
|
||||
}
|
||||
}
|
||||
if (m_buffer)
|
||||
free(m_buffer);
|
||||
}
|
||||
|
||||
bool ESPeasySoftwareSerial::isValidGPIOpin(uint8_t pin) {
|
||||
if (pin >= 0 && pin <= 5) {
|
||||
return true;
|
||||
}
|
||||
if (pin >= 12 && pin <= MAX_PIN) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t ESPeasySoftwareSerial::pinToIndex(uint8_t pin) {
|
||||
// Pin will be stored in the map, only "1" will be added,
|
||||
// to allow simple initialize to 0 and still use GPIO-0.
|
||||
const uint8_t stored_pin = pin + 1;
|
||||
for (unsigned i = 0; i < NR_CONCURRENT_SOFT_SERIALS; ++i) {
|
||||
if (PinControllerMap[i] == stored_pin) return i;
|
||||
}
|
||||
// Not found, add as first free option.
|
||||
for (unsigned i = 0; i < NR_CONCURRENT_SOFT_SERIALS; ++i) {
|
||||
if (PinControllerMap[i] == 0) {
|
||||
PinControllerMap[i] = stored_pin;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// No more controllers available.
|
||||
return NR_CONCURRENT_SOFT_SERIALS;
|
||||
}
|
||||
|
||||
void ESPeasySoftwareSerial::begin(long speed) {
|
||||
// Use getCycleCount() loop to get as exact timing as possible
|
||||
m_bitTime = ESP.getCpuFreqMHz()*1000000/speed;
|
||||
}
|
||||
|
||||
void ESPeasySoftwareSerial::setTransmitEnablePin(uint8_t transmitEnablePin) {
|
||||
if (isValidGPIOpin(transmitEnablePin)) {
|
||||
m_txEnableValid = true;
|
||||
m_txEnablePin = transmitEnablePin;
|
||||
pinMode(m_txEnablePin, OUTPUT);
|
||||
digitalWrite(m_txEnablePin, LOW);
|
||||
} else {
|
||||
m_txEnableValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ESPeasySoftwareSerial::enableRx(bool on) {
|
||||
if (m_rxValid) {
|
||||
if (on) {
|
||||
attachInterrupt(m_rxPin, ISRList[pinToIndex(m_rxPin)], m_invert ? RISING : FALLING);
|
||||
} else {
|
||||
detachInterrupt(m_rxPin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ESPeasySoftwareSerial::read() {
|
||||
if (!m_rxValid || (m_inPos == m_outPos)) return -1;
|
||||
uint8_t ch = m_buffer[m_outPos];
|
||||
m_outPos = (m_outPos+1) % m_buffSize;
|
||||
return ch;
|
||||
}
|
||||
|
||||
int ESPeasySoftwareSerial::available() {
|
||||
if (!m_rxValid) return 0;
|
||||
int avail = m_inPos - m_outPos;
|
||||
if (avail < 0) avail += m_buffSize;
|
||||
return avail;
|
||||
}
|
||||
|
||||
#define WAIT { while (ESP.getCycleCount()-start < wait); wait += m_bitTime; }
|
||||
|
||||
size_t ESPeasySoftwareSerial::write(uint8_t b) {
|
||||
if (!m_txValid) return 0;
|
||||
|
||||
if (m_invert) b = ~b;
|
||||
// Disable interrupts in order to get a clean transmit
|
||||
cli();
|
||||
if (m_txEnableValid) digitalWrite(m_txEnablePin, HIGH);
|
||||
unsigned long wait = m_bitTime;
|
||||
digitalWrite(m_txPin, HIGH);
|
||||
unsigned long start = ESP.getCycleCount();
|
||||
// Start bit;
|
||||
digitalWrite(m_txPin, LOW);
|
||||
WAIT;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
digitalWrite(m_txPin, (b & 1) ? HIGH : LOW);
|
||||
WAIT;
|
||||
b >>= 1;
|
||||
}
|
||||
// Stop bit
|
||||
digitalWrite(m_txPin, HIGH);
|
||||
WAIT;
|
||||
if (m_txEnableValid) digitalWrite(m_txEnablePin, LOW);
|
||||
sei();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ESPeasySoftwareSerial::flush() {
|
||||
m_inPos = m_outPos = 0;
|
||||
}
|
||||
|
||||
int ESPeasySoftwareSerial::peek() {
|
||||
if (!m_rxValid || (m_inPos == m_outPos)) return -1;
|
||||
return m_buffer[m_outPos];
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR ESPeasySoftwareSerial::rxRead() {
|
||||
// Advance the starting point for the samples but compensate for the
|
||||
// initial delay which occurs before the interrupt is delivered
|
||||
unsigned long wait = m_bitTime + m_bitTime/3 - 500;
|
||||
unsigned long start = ESP.getCycleCount();
|
||||
uint8_t rec = 0;
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
WAIT;
|
||||
rec >>= 1;
|
||||
if (digitalRead(m_rxPin))
|
||||
rec |= 0x80;
|
||||
}
|
||||
if (m_invert) rec = ~rec;
|
||||
// Stop bit
|
||||
WAIT;
|
||||
// Store the received value in the buffer unless we have an overflow
|
||||
uint16_t next = (m_inPos+1) % m_buffSize;
|
||||
if (next != m_inPos) {
|
||||
m_buffer[m_inPos] = rec;
|
||||
m_inPos = next;
|
||||
}
|
||||
// Must clear this bit in the interrupt register,
|
||||
// it gets set even when interrupts are disabled
|
||||
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << m_rxPin);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
ESPeasySoftwareSerial.h
|
||||
|
||||
ESPeasySoftwareSerial.cpp - Implementation of the Arduino software serial for ESP8266.
|
||||
Copyright (c) 2015-2016 Peter Lerup. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef ESPeasySoftwareSerial_h
|
||||
#define ESPeasySoftwareSerial_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <Stream.h>
|
||||
|
||||
|
||||
// This class is compatible with the corresponding AVR one,
|
||||
// the constructor however has an optional rx buffer size.
|
||||
// Speed up to 115200 can be used.
|
||||
|
||||
|
||||
class ESPeasySoftwareSerial : public Stream
|
||||
{
|
||||
public:
|
||||
ESPeasySoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false, uint16_t buffSize = 64);
|
||||
virtual ~ESPeasySoftwareSerial();
|
||||
|
||||
void begin(long speed);
|
||||
void setTransmitEnablePin(uint8_t transmitEnablePin);
|
||||
|
||||
int peek();
|
||||
|
||||
virtual size_t write(uint8_t byte);
|
||||
virtual int read();
|
||||
virtual int available();
|
||||
virtual void flush();
|
||||
operator bool() {return m_rxValid || m_txValid;}
|
||||
|
||||
// Disable or enable interrupts on the rx pin
|
||||
void enableRx(bool on);
|
||||
|
||||
void rxRead();
|
||||
|
||||
using Print::write;
|
||||
|
||||
private:
|
||||
bool isValidGPIOpin(uint8_t pin);
|
||||
uint8_t pinToIndex(uint8_t pin);
|
||||
|
||||
// Member variables
|
||||
uint8_t m_rxPin, m_txPin, m_txEnablePin;
|
||||
bool m_rxValid, m_txValid, m_txEnableValid;
|
||||
bool m_invert;
|
||||
unsigned long m_bitTime;
|
||||
uint16_t m_inPos, m_outPos;
|
||||
uint16_t m_buffSize;
|
||||
uint8_t *m_buffer;
|
||||
|
||||
};
|
||||
|
||||
// If only one tx or rx wanted then use this as parameter for the unused pin
|
||||
#define SW_SERIAL_UNUSED_PIN -1
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
# EspESPeasySoftwareSerial
|
||||
|
||||
Implementation of the Arduino software serial library for the ESP8266
|
||||
|
||||
Same functionality as the corresponding AVR library but several instances can be active at the same time.
|
||||
Speed up to 115200 baud is supported. The constructor also has an optional input buffer size.
|
||||
|
||||
Please note that due to the fact that the ESP always have other activities ongoing, there will be some inexactness in interrupt
|
||||
timings. This may lead to bit errors when having heavy data traffic in high baud rates.
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
#include <ESPeasySoftwareSerial.h>
|
||||
|
||||
ESPeasySoftwareSerial swSer(14, 12, false, 256);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
swSer.begin(115200);
|
||||
|
||||
Serial.println("\nSoftware serial test started");
|
||||
|
||||
for (char ch = ' '; ch <= 'z'; ch++) {
|
||||
swSer.write(ch);
|
||||
}
|
||||
swSer.println("");
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
while (swSer.available() > 0) {
|
||||
Serial.write(swSer.read());
|
||||
}
|
||||
while (Serial.available() > 0) {
|
||||
swSer.write(Serial.read());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map for ESPeasySoftwareSerial
|
||||
# (esp8266)
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
ESPeasySoftwareSerial KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
begin KEYWORD2
|
||||
read KEYWORD2
|
||||
write KEYWORD2
|
||||
available KEYWORD2
|
||||
flush KEYWORD2
|
||||
overflow KEYWORD2
|
||||
peek KEYWORD2
|
||||
listen KEYWORD2
|
||||
end KEYWORD2
|
||||
isListening KEYWORD2
|
||||
stopListening KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "EspESPeasySoftwareSerial",
|
||||
"version": "3.3.1",
|
||||
"keywords": [
|
||||
"serial", "io", "softwareserial"
|
||||
],
|
||||
"description": "Implementation of the Arduino software serial for ESP8266. Adjusted to reduce memory footprint for ESPeasy",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/plerup/espsoftwareserial"
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms": "espressif8266"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
name=ESPeasySoftwareSerial
|
||||
version=1.0
|
||||
author=Peter Lerup
|
||||
maintainer=Peter Lerup <peter@lerup.com>
|
||||
sentence=Implementation of the Arduino software serial for ESP8266.
|
||||
paragraph=
|
||||
category=Signal Input/Output
|
||||
url=
|
||||
architectures=esp8266
|
||||
@@ -0,0 +1,456 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
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 this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser 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 Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "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
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY 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
|
||||
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
@@ -0,0 +1,40 @@
|
||||
# ESP8266Ping
|
||||
Let the ESP8266 ping a remote machine.
|
||||
|
||||
With this library an ESP8266 can ping a remote machine and know if it's reachable.
|
||||
It provide some basic measurements on ping messages (avg response time).
|
||||
|
||||
## Usage
|
||||
|
||||
First, include the library in your sketch along with WiFi library:
|
||||
|
||||
```Arduino
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266Ping.h>
|
||||
```
|
||||
|
||||
Next, simply call the `Ping.ping()` function
|
||||
|
||||
```Arduino
|
||||
IPAddress ip (192, 168, 0, 1); // The remote ip to ping
|
||||
bool ret = Ping.ping(ip);
|
||||
```
|
||||
|
||||
`ret` will be true if the remote responded to pings, false if not reachable.
|
||||
The library supports hostname too, just pass a string instead of the ip address:
|
||||
|
||||
```Arduino
|
||||
bool ret = Ping.ping("www.google.com");
|
||||
```
|
||||
|
||||
Additionally, the function accept a second integer parameter `count` that specify how many pings has to be sent:
|
||||
|
||||
```Arduino
|
||||
bool ret = Ping.ping(ip_or_host, 10);
|
||||
```
|
||||
|
||||
After `Ping.ping()` has been called, the average response time (in milliseconds) can be retrieved with
|
||||
|
||||
```Arduino
|
||||
int avg_time_ms = Ping.averageTime();
|
||||
```
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This example show how to ping a remote machine using it's hostname
|
||||
*/
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266Ping.h>
|
||||
|
||||
const char* ssid = "ssid";
|
||||
const char* password = "passphrase";
|
||||
|
||||
const char* remote_host = "www.google.com";
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(10);
|
||||
|
||||
// We start by connecting to a WiFi network
|
||||
|
||||
Serial.println();
|
||||
Serial.println("Connecting to WiFi");
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Serial.print("WiFi connected with ip ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
Serial.print("Pinging host ");
|
||||
Serial.println(remote_host);
|
||||
|
||||
if(Ping.ping(remote_host)) {
|
||||
Serial.println("Success!!");
|
||||
} else {
|
||||
Serial.println("Error :(");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() { }
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* With this library an ESP8266 can ping a remote machine and know if it's reachable.
|
||||
* It provides some basic measurements on ping messages (avg response time).
|
||||
*/
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266Ping.h>
|
||||
|
||||
const char* ssid = "ssid";
|
||||
const char* password = "passphrase";
|
||||
|
||||
const IPAddress remote_ip(192, 168, 0, 1);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(10);
|
||||
|
||||
// We start by connecting to a WiFi network
|
||||
|
||||
Serial.println();
|
||||
Serial.println("Connecting to WiFi");
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Serial.print("WiFi connected with ip ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
Serial.print("Pinging ip ");
|
||||
Serial.println(remote_ip);
|
||||
|
||||
if(Ping.ping(remote_ip)) {
|
||||
Serial.println("Success!!");
|
||||
} else {
|
||||
Serial.println("Error :(");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() { }
|
||||
@@ -0,0 +1,26 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For ESP8266Ping
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Library (KEYWORD3)
|
||||
#######################################
|
||||
|
||||
ESP8266Ping KEYWORD3
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
Ping KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
ping KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
name=ESPEasy_ESP8266Ping
|
||||
version=1.0
|
||||
author=Daniele Colanardi
|
||||
maintainer=Daniele Colanardi <dancol90@gmail.com>
|
||||
sentence=Let the ESP8266 ping a remote machine.
|
||||
paragraph=With this library an ESP8266 can ping a remote machine and know if it's reachable. It provide some basic measurements on ping messages (avg response time). Lib name renamed to avoid conflicts in Arduino IDE.
|
||||
category=Communication
|
||||
url=
|
||||
architectures=esp8266
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
ESP8266Ping - Ping library for ESP8266
|
||||
Copyright (c) 2015 Daniele Colanardi. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ESP8266Ping_H
|
||||
#define ESP8266Ping_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
extern "C" {
|
||||
#include <ping.h>
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DEBUG_PING
|
||||
#define DEBUG_PING(...) Serial.printf(__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_PING(...)
|
||||
#endif
|
||||
|
||||
class PingClass {
|
||||
public:
|
||||
PingClass();
|
||||
|
||||
bool ping(IPAddress dest, byte count = 5);
|
||||
bool ping(const char* host, byte count = 5);
|
||||
|
||||
int averageTime();
|
||||
|
||||
protected:
|
||||
static void _ping_sent_cb(void *opt, void *pdata);
|
||||
static void _ping_recv_cb(void *opt, void *pdata);
|
||||
|
||||
IPAddress _dest;
|
||||
ping_option _options;
|
||||
|
||||
static byte _expected_count, _errors, _success;
|
||||
static int _avg_time;
|
||||
};
|
||||
|
||||
#include "ESP8266Ping.impl.h"
|
||||
PingClass Ping;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
ESP8266Ping - Ping library for ESP8266
|
||||
Copyright (c) 2015 Daniele Colanardi. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
extern "C" void esp_schedule();
|
||||
extern "C" void esp_yield();
|
||||
|
||||
PingClass::PingClass() {}
|
||||
|
||||
bool PingClass::ping(IPAddress dest, byte count) {
|
||||
_expected_count = count;
|
||||
_errors = 0;
|
||||
_success = 0;
|
||||
|
||||
_avg_time = 0;
|
||||
|
||||
memset(&_options, 0, sizeof(struct ping_option));
|
||||
|
||||
// Repeat count (how many time send a ping message to destination)
|
||||
_options.count = count;
|
||||
// Time interval between two ping (seconds??)
|
||||
_options.coarse_time = 1;
|
||||
// Destination machine
|
||||
_options.ip = dest;
|
||||
|
||||
// Callbacks
|
||||
_options.recv_function = reinterpret_cast<ping_recv_function>(&PingClass::_ping_recv_cb);
|
||||
_options.sent_function = NULL; //reinterpret_cast<ping_sent_function>(&_ping_sent_cb);
|
||||
|
||||
// Let's go!
|
||||
if(ping_start(&_options)) {
|
||||
// Suspend till the process end
|
||||
esp_yield();
|
||||
}
|
||||
|
||||
return (_success > 0);
|
||||
}
|
||||
|
||||
bool PingClass::ping(const char* host, byte count) {
|
||||
IPAddress remote_addr;
|
||||
|
||||
if (WiFi.hostByName(host, remote_addr))
|
||||
return ping(remote_addr, count);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int PingClass::averageTime() {
|
||||
return _avg_time;
|
||||
}
|
||||
|
||||
void PingClass::_ping_recv_cb(void *opt, void *resp) {
|
||||
// Cast the parameters to get some usable info
|
||||
ping_resp* ping_resp = reinterpret_cast<struct ping_resp*>(resp);
|
||||
//ping_option* ping_opt = reinterpret_cast<struct ping_option*>(opt);
|
||||
|
||||
// Error or success?
|
||||
if (ping_resp->ping_err == -1)
|
||||
_errors++;
|
||||
else {
|
||||
_success++;
|
||||
_avg_time += ping_resp->resp_time;
|
||||
}
|
||||
|
||||
// Some debug info
|
||||
DEBUG_PING(
|
||||
"DEBUG: ping reply\n"
|
||||
"\ttotal_count = %d \n"
|
||||
"\tresp_time = %d \n"
|
||||
"\tseqno = %d \n"
|
||||
"\ttimeout_count = %d \n"
|
||||
"\tbytes = %d \n"
|
||||
"\ttotal_bytes = %d \n"
|
||||
"\ttotal_time = %d \n"
|
||||
"\tping_err = %d \n",
|
||||
ping_resp->total_count, ping_resp->resp_time, ping_resp->seqno,
|
||||
ping_resp->timeout_count, ping_resp->bytes, ping_resp->total_bytes,
|
||||
ping_resp->total_time, ping_resp->ping_err
|
||||
);
|
||||
|
||||
// Is it time to end?
|
||||
// Don't using seqno because it does not increase on error
|
||||
if (_success + _errors == _expected_count) {
|
||||
_avg_time = _avg_time / _expected_count;
|
||||
|
||||
DEBUG_PING("Avg resp time %d ms\n", _avg_time);
|
||||
|
||||
// Done, return to main functiom
|
||||
esp_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
byte PingClass::_expected_count = 0;
|
||||
byte PingClass::_errors = 0;
|
||||
byte PingClass::_success = 0;
|
||||
int PingClass::_avg_time = 0;
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <SensorSerial.h>
|
||||
|
||||
|
||||
SensorSerial::SensorSerial(int receivePin, int transmitPin, bool inverse_logic, unsigned int buffSize) : SoftwareSerial(receivePin, transmitPin, inverse_logic, buffSize)
|
||||
SensorSerial::SensorSerial(int receivePin, int transmitPin, bool inverse_logic, unsigned int buffSize) : ESPeasySoftwareSerial(receivePin, transmitPin, inverse_logic, buffSize)
|
||||
{
|
||||
//boolean sws = isValidGPIOpin(receivePin);
|
||||
_hw = receivePin < 0;
|
||||
@@ -37,7 +37,7 @@ void SensorSerial::begin(long speed)
|
||||
if (_hw)
|
||||
Serial.begin(speed);
|
||||
else
|
||||
SoftwareSerial::begin(speed);
|
||||
ESPeasySoftwareSerial::begin(speed);
|
||||
}
|
||||
|
||||
int SensorSerial::peek()
|
||||
@@ -45,7 +45,7 @@ int SensorSerial::peek()
|
||||
if (_hw)
|
||||
return Serial.peek();
|
||||
else
|
||||
return SoftwareSerial::peek();
|
||||
return ESPeasySoftwareSerial::peek();
|
||||
}
|
||||
|
||||
size_t SensorSerial::write(uint8_t byte)
|
||||
@@ -53,7 +53,7 @@ size_t SensorSerial::write(uint8_t byte)
|
||||
if (_hw)
|
||||
return Serial.write(byte);
|
||||
else
|
||||
return SoftwareSerial::write(byte);
|
||||
return ESPeasySoftwareSerial::write(byte);
|
||||
}
|
||||
|
||||
int SensorSerial::read()
|
||||
@@ -61,7 +61,7 @@ int SensorSerial::read()
|
||||
if (_hw)
|
||||
return Serial.read();
|
||||
else
|
||||
return SoftwareSerial::read();
|
||||
return ESPeasySoftwareSerial::read();
|
||||
}
|
||||
|
||||
int SensorSerial::available()
|
||||
@@ -69,7 +69,7 @@ int SensorSerial::available()
|
||||
if (_hw)
|
||||
return Serial.available();
|
||||
else
|
||||
return SoftwareSerial::available();
|
||||
return ESPeasySoftwareSerial::available();
|
||||
}
|
||||
|
||||
void SensorSerial::flush()
|
||||
@@ -77,5 +77,5 @@ void SensorSerial::flush()
|
||||
if (_hw)
|
||||
Serial.flush();
|
||||
else
|
||||
SoftwareSerial::flush();
|
||||
ESPeasySoftwareSerial::flush();
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
#define _SENSORSERIAL_H_
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <SoftwareSerial.h>
|
||||
#include <ESPeasySoftwareSerial.h>
|
||||
|
||||
class SensorSerial : public SoftwareSerial
|
||||
class SensorSerial : public ESPeasySoftwareSerial
|
||||
{
|
||||
public:
|
||||
SensorSerial(int receivePin, int transmitPin = -1, bool inverse_logic = false, unsigned int buffSize = 64);
|
||||
|
||||
@@ -22,6 +22,10 @@ SOFTWARE.
|
||||
|
||||
See more at http://blog.squix.ch
|
||||
*/
|
||||
|
||||
#ifndef DIALOG_PLAIN_FONT_H
|
||||
#define DIALOG_PLAIN_FONT_H
|
||||
|
||||
// OLED library version >= 3.0.0
|
||||
// Created by http://oleddisplay.squix.ch/ Consider a donation
|
||||
// In case of problems make sure that you are using the font file with the correct version!
|
||||
@@ -481,3 +485,6 @@ const char Dialog_plain_12[] PROGMEM = {
|
||||
0x00,0x00,0xFC,0x7F,0x40,0x04,0x20,0x08,0x20,0x08,0x60,0x0C,0xC0,0x07, // 254
|
||||
0x00,0x00,0xE0,0x40,0x04,0x47,0x00,0x38,0x84,0x07,0xE0 // 255
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -349,7 +349,7 @@ void OLEDDisplay::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16
|
||||
drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1);
|
||||
drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001);
|
||||
|
||||
uint16_t maxProgressWidth = (width - doubleRadius - 1) * progress / 100;
|
||||
uint16_t maxProgressWidth = (width - doubleRadius + 1) * progress / 100;
|
||||
|
||||
fillCircle(xRadius, yRadius, innerRadius);
|
||||
fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3);
|
||||
|
||||
@@ -1,31 +1,24 @@
|
||||
#define WiFi_Logo_width 60
|
||||
#define WiFi_Logo_height 36
|
||||
const char WiFi_Logo_bits[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
|
||||
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x83, 0x01, 0x80, 0xFF, 0xFF, 0xFF,
|
||||
0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00,
|
||||
0xC0, 0xFF, 0xFF, 0x7C, 0x00, 0x60, 0x0C, 0x00, 0xC0, 0x31, 0x46, 0x7C,
|
||||
0xFC, 0x77, 0x08, 0x00, 0xE0, 0x23, 0xC6, 0x3C, 0xFC, 0x67, 0x18, 0x00,
|
||||
0xE0, 0x23, 0xE4, 0x3F, 0x1C, 0x00, 0x18, 0x00, 0xE0, 0x23, 0x60, 0x3C,
|
||||
0x1C, 0x70, 0x18, 0x00, 0xE0, 0x03, 0x60, 0x3C, 0x1C, 0x70, 0x18, 0x00,
|
||||
0xE0, 0x07, 0x60, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C,
|
||||
0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00,
|
||||
0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x8F, 0x71, 0x3C,
|
||||
0x1C, 0x70, 0x18, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x08, 0x00,
|
||||
0xC0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x1F,
|
||||
0x00, 0x00, 0x06, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x07, 0x00,
|
||||
0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF,
|
||||
0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
|
||||
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
#ifndef OLED_SSD1306_SH1106_IMAGES_H
|
||||
#define OLED_SSD1306_SH1106_IMAGES_H
|
||||
|
||||
#define espeasy_logo_width 36
|
||||
#define espeasy_logo_height 36
|
||||
const char espeasy_logo_bits[] PROGMEM= {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x60, 0x40, 0xc0, 0x00, 0x00, 0x70, 0xf0, 0xe0,
|
||||
0x01, 0x00, 0x78, 0xf8, 0xf0, 0x01, 0x00, 0x3c, 0x7c, 0xf8, 0x00, 0x00,
|
||||
0x1e, 0x3e, 0x7c, 0x00, 0x00, 0x0f, 0x1f, 0x3e, 0x00, 0x80, 0x87, 0x0f,
|
||||
0x1f, 0x00, 0xc0, 0xc3, 0x87, 0x0f, 0x00, 0xe0, 0xe1, 0xc3, 0x07, 0x00,
|
||||
0xf0, 0xf0, 0xe1, 0xc3, 0x00, 0x78, 0xf8, 0xf0, 0xe1, 0x01, 0x30, 0x7c,
|
||||
0xf8, 0xf0, 0x00, 0x00, 0x3e, 0x7c, 0x78, 0x00, 0x00, 0x1f, 0x3e, 0x3c,
|
||||
0x00, 0x80, 0x0f, 0x1f, 0x1e, 0x00, 0xc0, 0x87, 0x0f, 0x0f, 0x00, 0xe0,
|
||||
0xc3, 0x87, 0x07, 0x00, 0xf0, 0xe1, 0xc3, 0x03, 0x00, 0xf0, 0xf0, 0xe1,
|
||||
0x01, 0x00, 0x78, 0xf8, 0xf0, 0x00, 0x00, 0x30, 0x7c, 0x78, 0x00, 0x00,
|
||||
0x00, 0x3e, 0x3c, 0x00, 0x00, 0x00, 0x1f, 0x1e, 0x00, 0x00, 0x80, 0x0f,
|
||||
0x0f, 0x78, 0x00, 0xc0, 0x87, 0x07, 0xfc, 0x00, 0xe0, 0xc3, 0x03, 0xfc,
|
||||
0x01, 0xf0, 0xe1, 0x01, 0xfc, 0x01, 0xf8, 0xf0, 0x00, 0xfc, 0x00, 0x78,
|
||||
0x70, 0x00, 0x78, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
const char activeSymbole[] PROGMEM = {
|
||||
B00000000,
|
||||
@@ -49,3 +42,4 @@ const char inactiveSymbole[] PROGMEM = {
|
||||
B00000000
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -420,7 +420,7 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig
|
||||
|
||||
lastOutActivity = millis();
|
||||
|
||||
return rc == tlen + 4 + plength;
|
||||
return rc == tlen + 3 + llen + plength;
|
||||
}
|
||||
|
||||
boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
#define MQTTQOS1 (1 << 1)
|
||||
#define MQTTQOS2 (2 << 1)
|
||||
|
||||
#ifdef ESP8266
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
#include <functional>
|
||||
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
|
||||
#else
|
||||
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
PATCH=puya.patch
|
||||
|
||||
for DIR in ~/.platformio/packages/framework-arduinoespressif8266*/; do
|
||||
|
||||
#not applied yet? (in upstream or otherwise)
|
||||
if ! grep FLASH_QUIRK_WRITE_0_TO_1 $DIR/cores/esp8266/Esp.cpp >/dev/null; then
|
||||
echo "Patching $DIR"
|
||||
patch -p1 -d $DIR < $PATCH
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
cores/esp8266/Esp.cpp | 16 +++++++++++++++-
|
||||
1 file changed, 15 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp
|
||||
index f4c0b220..c5c32f74 100644
|
||||
--- a/cores/esp8266/Esp.cpp
|
||||
+++ b/cores/esp8266/Esp.cpp
|
||||
@@ -501,7 +501,21 @@ bool EspClass::flashEraseSector(uint32_t sector) {
|
||||
|
||||
bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size) {
|
||||
ets_isr_mask(FLASH_INT_MASK);
|
||||
- int rc = spi_flash_write(offset, (uint32_t*) data, size);
|
||||
+ int rc;
|
||||
+ uint32_t* ptr = data;
|
||||
+#ifdef FLASH_QUIRK_WRITE_0_TO_1
|
||||
+ static uint32_t read_buf[SPI_FLASH_SEC_SIZE / 4];
|
||||
+ rc = spi_flash_read(offset, read_buf, size);
|
||||
+ if (rc != 0) {
|
||||
+ ets_isr_unmask(FLASH_INT_MASK);
|
||||
+ return false;
|
||||
+ }
|
||||
+ for (size_t i = 0; i < size / 4; ++i) {
|
||||
+ read_buf[i] &= data[i];
|
||||
+ }
|
||||
+ ptr = read_buf;
|
||||
+#endif // FLASH_QUIRK_WRITE_0_TO_1
|
||||
+ rc = spi_flash_write(offset, ptr, size);
|
||||
ets_isr_unmask(FLASH_INT_MASK);
|
||||
return rc == 0;
|
||||
}
|
||||
--
|
||||
@@ -22,11 +22,14 @@
|
||||
|
||||
[common]
|
||||
build_flags = -D BUILD_GIT='"${env.TRAVIS_TAG}"'
|
||||
lib_deps = ""
|
||||
|
||||
|
||||
#normal version with stable plugins, 1024k version
|
||||
[env:normal_ESP8266_1024]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
board_flash_mode = dout
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
upload_speed=460800
|
||||
@@ -35,6 +38,7 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld
|
||||
|
||||
[env:normal_ESP8266_1024_DOUT]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
board_flash_mode = dout
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
@@ -45,6 +49,7 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld
|
||||
#normal version with stable plugins, 4096k version
|
||||
[env:normal_ESP8266_4096]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
upload_speed=460800
|
||||
@@ -54,6 +59,8 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.4m1m.ld
|
||||
#normal version with stable plugins, 4096k version for esp8285
|
||||
[env:normal_ESP8285_1024]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
board_flash_mode = dout
|
||||
framework = arduino
|
||||
board = esp8285
|
||||
upload_speed=460800
|
||||
@@ -64,6 +71,8 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -DESP8285
|
||||
#version with additional plugins (and dependend code) that are in test-stadium 1024k
|
||||
[env:test_ESP8266_1024]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
board_flash_mode = dout
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
upload_speed=460800
|
||||
@@ -72,14 +81,25 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD
|
||||
#version with additional plugins (and dependend code) that are in test-stadium 4096k
|
||||
[env:test_ESP8266_4096]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
upload_speed=460800
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.4m1m.ld -D PLUGIN_BUILD_TESTING
|
||||
|
||||
[env:test_ESP8266_4096_VCC]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
upload_speed=460800
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.4m1m.ld -D PLUGIN_BUILD_TESTING -D FEATURE_ADC_VCC=true
|
||||
|
||||
#version with additional plugins (and dependend code) that are in test-stadium 4096k for esp8285
|
||||
[env:test_ESP8285_1024]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
board_flash_mode = dout
|
||||
framework = arduino
|
||||
board = esp8285
|
||||
upload_speed=460800
|
||||
@@ -89,6 +109,8 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD
|
||||
#version with additional plugins (and dependend code) that is in development (probably broken or incomplete) 1024k
|
||||
[env:dev_ESP8266_1024]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
board_flash_mode = dout
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
upload_speed=460800
|
||||
@@ -97,6 +119,7 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD
|
||||
#version with additional plugins (and dependend code) that is in development (probably broken or incomplete) 4096k
|
||||
[env:dev_ESP8266_4096]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
upload_speed=460800
|
||||
@@ -105,7 +128,31 @@ build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.4m1m.ld -D PLUGIN_BUILD_
|
||||
#version with additional plugins (and dependend code) that is in development (probably broken or incomplete) 4096k for esp8285
|
||||
[env:dev_ESP8285_1024]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
board_flash_mode = dout
|
||||
framework = arduino
|
||||
board = esp8285
|
||||
upload_speed=460800
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD_TESTING -D PLUGIN_BUILD_DEV -DESP8285
|
||||
|
||||
|
||||
|
||||
#special patched version for PUYA flash chips, see https://github.com/letscontrolit/ESPEasy/issues/650
|
||||
[env:dev_ESP8266PUYA_1024]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
board_flash_mode = dout
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
upload_speed=460800
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD_TESTING -D PLUGIN_BUILD_DEV -D FLASH_QUIRK_WRITE_0_TO_1
|
||||
|
||||
#special patched version for PUYA flash chips, see https://github.com/letscontrolit/ESPEasy/issues/650
|
||||
[env:dev_ESP8266PUYA_1024_VCC]
|
||||
platform = espressif8266@1.5.0
|
||||
lib_deps = ${common.lib_deps}
|
||||
board_flash_mode = dout
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
upload_speed=460800
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD_TESTING -D PLUGIN_BUILD_DEV -D FLASH_QUIRK_WRITE_0_TO_1 -D FEATURE_ADC_VCC=true
|
||||
|
||||
+45
-2
@@ -387,10 +387,10 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
portUDP.beginPacket(UDP_IP, port.toInt());
|
||||
#if defined(ESP8266)
|
||||
portUDP.write(message.c_str(), message.length());
|
||||
#endif
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
portUDP.write((uint8_t*)message.c_str(), message.length());
|
||||
#endif
|
||||
#endif
|
||||
portUDP.endPacket();
|
||||
}
|
||||
}
|
||||
@@ -429,6 +429,42 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
}
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
// special commands for Blynk
|
||||
// ****************************************
|
||||
#ifdef CPLUGIN_012
|
||||
//FIXME: this should go to PLUGIN_WRITE in _C012.ino
|
||||
if (strcasecmp_P(Command, PSTR("BlynkGet")) == 0)
|
||||
{
|
||||
byte first_enabled_blynk_controller = firstEnabledBlynkController();
|
||||
if (first_enabled_blynk_controller == -1) {
|
||||
status = F("Controller not enabled");
|
||||
} else {
|
||||
String strLine = Line;
|
||||
strLine = strLine.substring(9);
|
||||
int index = strLine.indexOf(',');
|
||||
if (index > 0)
|
||||
{
|
||||
int index = strLine.lastIndexOf(',');
|
||||
String blynkcommand = strLine.substring(index+1);
|
||||
float value = 0;
|
||||
if (Blynk_get(blynkcommand, first_enabled_blynk_controller, &value))
|
||||
{
|
||||
UserVar[(VARS_PER_TASK * (Par1 - 1)) + Par2 - 1] = value;
|
||||
}
|
||||
else
|
||||
status = F("Error getting data");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Blynk_get(strLine, first_enabled_blynk_controller))
|
||||
{
|
||||
status = F("Error getting data");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// ****************************************
|
||||
// configure settings commands
|
||||
@@ -526,6 +562,13 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
{
|
||||
success = true;
|
||||
ResetFactory();
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
ESP.restart();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Save")) == 0)
|
||||
|
||||
+51
-56
@@ -7,9 +7,6 @@ void sendData(struct EventStruct *event)
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(event->TaskIndex);
|
||||
|
||||
if (Settings.GlobalSync && Settings.TaskDeviceGlobalSync[event->TaskIndex])
|
||||
SendUDPTaskData(0, event->TaskIndex, event->TaskIndex);
|
||||
|
||||
if (Settings.UseValueLogger && Settings.InitSPI && Settings.Pin_sd_cs >= 0)
|
||||
SendValueLogger(event->TaskIndex);
|
||||
|
||||
@@ -62,11 +59,7 @@ void sendData(struct EventStruct *event)
|
||||
boolean validUserVar(struct EventStruct *event) {
|
||||
for (int i = 0; i < VARS_PER_TASK; ++i) {
|
||||
const float f(UserVar[event->BaseVarIndex + i]);
|
||||
if (f == NAN) return false; //("NaN");
|
||||
if (f == INFINITY) return false; //("INFINITY");
|
||||
if (-f == INFINITY)return false; //("-INFINITY");
|
||||
if (isnan(f)) return false; //("isnan");
|
||||
if (isinf(f)) return false; //("isinf");
|
||||
if (!isValidFloat(f)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -120,13 +113,14 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
|
||||
/*********************************************************************************************\
|
||||
* Connect to MQTT message broker
|
||||
\*********************************************************************************************/
|
||||
void MQTTConnect(int controller_idx)
|
||||
bool MQTTConnect(int controller_idx)
|
||||
{
|
||||
if (!WiFiConnected(100)) return;
|
||||
if (MQTTclient.connected())
|
||||
MQTTclient.disconnect();
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(controller_idx, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
if (!ControllerSettings.checkHostReachable(true))
|
||||
return false;
|
||||
if (MQTTclient.connected())
|
||||
MQTTclient.disconnect();
|
||||
if (ControllerSettings.UseDNS) {
|
||||
MQTTclient.setServer(ControllerSettings.getHost().c_str(), ControllerSettings.Port);
|
||||
} else {
|
||||
@@ -137,61 +131,61 @@ void MQTTConnect(int controller_idx)
|
||||
// MQTT needs a unique clientname to subscribe to broker
|
||||
String clientid = F("ESPClient_");
|
||||
clientid += WiFi.macAddress();
|
||||
String subscribeTo = "";
|
||||
|
||||
String LWTTopic = ControllerSettings.Subscribe;
|
||||
LWTTopic.replace(F("/#"), F("/status"));
|
||||
LWTTopic.replace(F("%sysname%"), Settings.Name);
|
||||
parseSystemVariables(LWTTopic, false);
|
||||
LWTTopic += F("/LWT"); // Extend the topic for status updates of connected/disconnected status.
|
||||
|
||||
for (byte x = 1; x < 3; x++)
|
||||
{
|
||||
String log = "";
|
||||
boolean MQTTresult = false;
|
||||
boolean MQTTresult = false;
|
||||
uint8_t willQos = 0;
|
||||
boolean willRetain = true;
|
||||
|
||||
if ((SecuritySettings.ControllerUser[controller_idx] != 0) && (SecuritySettings.ControllerPassword[controller_idx] != 0))
|
||||
MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser[controller_idx], SecuritySettings.ControllerPassword[controller_idx], LWTTopic.c_str(), 0, 0, "Connection Lost");
|
||||
else
|
||||
MQTTresult = MQTTclient.connect(clientid.c_str(), LWTTopic.c_str(), 0, 0, "Connection Lost");
|
||||
yield();
|
||||
|
||||
if (MQTTresult)
|
||||
{
|
||||
MQTTclient_should_reconnect = false;
|
||||
log = F("MQTT : Connected to broker with client ID: ");
|
||||
log += clientid;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
subscribeTo = ControllerSettings.Subscribe;
|
||||
subscribeTo.replace(F("%sysname%"), Settings.Name);
|
||||
MQTTclient.subscribe(subscribeTo.c_str());
|
||||
log = F("Subscribed to: ");
|
||||
log += subscribeTo;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
MQTTclient.publish(LWTTopic.c_str(), "Connected");
|
||||
|
||||
statusLED(true);
|
||||
return; // end loop if succesfull
|
||||
}
|
||||
else
|
||||
{
|
||||
log = F("MQTT : Failed to connect to broker");
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
}
|
||||
|
||||
delay(500);
|
||||
if ((SecuritySettings.ControllerUser[controller_idx] != 0) && (SecuritySettings.ControllerPassword[controller_idx] != 0)) {
|
||||
MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser[controller_idx], SecuritySettings.ControllerPassword[controller_idx],
|
||||
LWTTopic.c_str(), willQos, willRetain, "Connection Lost");
|
||||
} else {
|
||||
MQTTresult = MQTTclient.connect(clientid.c_str(), LWTTopic.c_str(), willQos, willRetain, "Connection Lost");
|
||||
}
|
||||
yield();
|
||||
|
||||
if (!MQTTresult) {
|
||||
addLog(LOG_LEVEL_ERROR, F("MQTT : Failed to connect to broker"));
|
||||
return false;
|
||||
}
|
||||
MQTTclient_should_reconnect = false;
|
||||
String log = F("MQTT : Connected to broker with client ID: ");
|
||||
log += clientid;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
String subscribeTo = ControllerSettings.Subscribe;
|
||||
parseSystemVariables(subscribeTo, false);
|
||||
MQTTclient.subscribe(subscribeTo.c_str());
|
||||
log = F("Subscribed to: ");
|
||||
log += subscribeTo;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
if (MQTTclient.publish(LWTTopic.c_str(), "Connected", 1)) {
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
String event = F("MQTT#Connected");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
statusLED(true);
|
||||
return true; // end loop if succesfull
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Check connection MQTT message broker
|
||||
\*********************************************************************************************/
|
||||
void MQTTCheck(int controller_idx)
|
||||
bool MQTTCheck(int controller_idx)
|
||||
{
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[controller_idx]);
|
||||
if (Protocol[ProtocolIndex].usesMQTT)
|
||||
{
|
||||
if (MQTTclient_should_reconnect || !WiFiConnected(100) || !MQTTclient.connected())
|
||||
if (MQTTclient_should_reconnect || !WiFiConnected(10) || !MQTTclient.connected())
|
||||
{
|
||||
if (MQTTclient_should_reconnect) {
|
||||
addLog(LOG_LEVEL_ERROR, F("MQTT : Intentional reconnect"));
|
||||
@@ -199,11 +193,13 @@ void MQTTCheck(int controller_idx)
|
||||
addLog(LOG_LEVEL_ERROR, F("MQTT : Connection lost"));
|
||||
connectionFailures += 2;
|
||||
}
|
||||
MQTTConnect(controller_idx);
|
||||
}
|
||||
else if (connectionFailures)
|
||||
return MQTTConnect(controller_idx);
|
||||
} else if (connectionFailures) {
|
||||
connectionFailures--;
|
||||
}
|
||||
}
|
||||
// When no MQTT protocol is enabled, all is fine.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +229,6 @@ boolean MQTTpublish(int controller_idx, const char* topic, const char* payload,
|
||||
if (MQTTclient.publish(topic, payload, retained))
|
||||
return true;
|
||||
addLog(LOG_LEVEL_DEBUG, F("MQTT : publish failed"));
|
||||
MQTTConnect(controller_idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -248,7 +243,7 @@ void MQTTStatus(String& status)
|
||||
LoadControllerSettings(enabledMqttController, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
String pubname = ControllerSettings.Subscribe;
|
||||
pubname.replace(F("/#"), F("/status"));
|
||||
pubname.replace(F("%sysname%"), Settings.Name);
|
||||
parseSystemVariables(pubname, false);
|
||||
MQTTpublish(enabledMqttController, pubname.c_str(), status.c_str(),Settings.MQTTRetainFlag);
|
||||
}
|
||||
}
|
||||
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
|
||||
/*********************************************************************************************\
|
||||
Convert bearing in degree to bearing string
|
||||
\*********************************************************************************************/
|
||||
|
||||
String getBearing(int degrees)
|
||||
{
|
||||
const __FlashStringHelper* bearing[] = {
|
||||
F("N"),
|
||||
F("NNE"),
|
||||
F("NE"),
|
||||
F("ENE"),
|
||||
F("E"),
|
||||
F("ESE"),
|
||||
F("SE"),
|
||||
F("SSE"),
|
||||
F("S"),
|
||||
F("SSW"),
|
||||
F("SW"),
|
||||
F("WSW"),
|
||||
F("W"),
|
||||
F("WNW"),
|
||||
F("NW"),
|
||||
F("NNW")
|
||||
};
|
||||
int nr_directions = (int) (sizeof(bearing)/sizeof(bearing[0]));
|
||||
float stepsize = (360.0 / nr_directions);
|
||||
if (degrees < 0) { degrees += 360; } // Allow for bearing -360 .. 359
|
||||
int bearing_idx=int((degrees + (stepsize / 2.0)) / stepsize) % nr_directions;
|
||||
if (bearing_idx < 0)
|
||||
return("");
|
||||
else
|
||||
return(bearing[bearing_idx]);
|
||||
}
|
||||
|
||||
float CelsiusToFahrenheit(float celsius) {
|
||||
return celsius * (9.0 / 5.0) + 32;
|
||||
}
|
||||
|
||||
int m_secToBeaufort(float m_per_sec) {
|
||||
if (m_per_sec < 0.3) return 0;
|
||||
if (m_per_sec < 1.6) return 1;
|
||||
if (m_per_sec < 3.4) return 2;
|
||||
if (m_per_sec < 5.5) return 3;
|
||||
if (m_per_sec < 8.0) return 4;
|
||||
if (m_per_sec < 10.8) return 5;
|
||||
if (m_per_sec < 13.9) return 6;
|
||||
if (m_per_sec < 17.2) return 7;
|
||||
if (m_per_sec < 20.8) return 8;
|
||||
if (m_per_sec < 24.5) return 9;
|
||||
if (m_per_sec < 28.5) return 10;
|
||||
if (m_per_sec < 32.6) return 11;
|
||||
return 12;
|
||||
}
|
||||
|
||||
String centimeterToImperialLength(float cm) {
|
||||
return millimeterToImperialLength(cm * 10.0);
|
||||
}
|
||||
|
||||
String millimeterToImperialLength(float mm) {
|
||||
float inches = mm / 25.4;
|
||||
int feet = inches /12;
|
||||
inches = inches - (feet * 12);
|
||||
String result;
|
||||
result.reserve(10);
|
||||
if (feet != 0) {
|
||||
result += feet;
|
||||
result += '\'';
|
||||
}
|
||||
result += toString(inches,1);
|
||||
result += '"';
|
||||
return result;
|
||||
}
|
||||
|
||||
float minutesToDay(int minutes) {
|
||||
return minutes / 1440.0;
|
||||
}
|
||||
|
||||
String minutesToDayHour(int minutes) {
|
||||
int days = minutes / 1440;
|
||||
int hours = (minutes % 1440) / 60;
|
||||
char TimeString[6]; //5 digits plus the null char
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d%c"), days, 'd', hours, 'h');
|
||||
return TimeString;
|
||||
}
|
||||
|
||||
String minutesToDayHourMinute(int minutes) {
|
||||
int days = minutes / 1440;
|
||||
int hours = (minutes % 1440) / 60;
|
||||
int mins = (minutes % 1440) % 60;
|
||||
char TimeString[20];
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d%c%02d%c"), days, 'd', hours, 'h', mins, 'm');
|
||||
return TimeString;
|
||||
}
|
||||
|
||||
String secondsToDayHourMinuteSecond(int seconds) {
|
||||
int sec = seconds % 60;
|
||||
int minutes = seconds / 60;
|
||||
int days = minutes / 1440;
|
||||
int hours = (minutes % 1440) / 60;
|
||||
int mins = (minutes % 1440) % 60;
|
||||
char TimeString[20];
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d%c%02d%c%02d"), days, 'd', hours, ':', mins, ':', sec);
|
||||
return TimeString;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
In memory convert float to long
|
||||
\*********************************************************************************************/
|
||||
unsigned long float2ul(float f)
|
||||
{
|
||||
unsigned long ul;
|
||||
memcpy(&ul, &f, 4);
|
||||
return ul;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
In memory convert long to float
|
||||
\*********************************************************************************************/
|
||||
float ul2float(unsigned long ul)
|
||||
{
|
||||
float f;
|
||||
memcpy(&f, &ul, 4);
|
||||
return f;
|
||||
}
|
||||
@@ -0,0 +1,985 @@
|
||||
|
||||
#ifndef ESPEASY_GLOBALS_H_
|
||||
#define ESPEASY_GLOBALS_H_
|
||||
// ********************************************************************************
|
||||
// User specific configuration
|
||||
// ********************************************************************************
|
||||
|
||||
// Set default configuration settings if you want (not mandatory)
|
||||
// You can always change these during runtime and save to eeprom
|
||||
// After loading firmware, issue a 'reset' command to load the defaults.
|
||||
|
||||
// --- Basic Config Settings ------------------------------------------------------------------------
|
||||
#define DEFAULT_NAME "ESP_Easy" // Enter your device friendly name
|
||||
#define UNIT 0 // Unit Number
|
||||
#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_KEY "configesp" // Enter network WPA key for AP (config) mode
|
||||
|
||||
// --- Wifi Client Mode -----------------------------------------------------------------------------
|
||||
#define DEFAULT_SSID "ssid" // Enter your Wifi network SSID
|
||||
#define DEFAULT_KEY "wpakey" // Enter your Wifi network WPA key
|
||||
|
||||
#define DEFAULT_USE_STATIC_IP false // (true|false) enabled or disabled static IP
|
||||
#define DEFAULT_IP "192.168.0.50" // Enter your IP address
|
||||
#define DEFAULT_DNS "192.168.0.1" // Enter your DNS
|
||||
#define DEFAULT_GW "192.168.0.1" // Enter your Gateway
|
||||
#define DEFAULT_SUBNET "255.255.255.0" // Enter your Subnet
|
||||
|
||||
#define DEFAULT_WIFI_CONNECTION_TIMEOUT 10000 // minimum timeout in ms for WiFi to be connected.
|
||||
|
||||
// --- Default Controller ------------------------------------------------------------------------------
|
||||
#define DEFAULT_CONTROLLER false // true or false enabled or disabled, set 1st controller defaults
|
||||
// using a default template, you also need to set a DEFAULT PROTOCOL to a suitable MQTT protocol !
|
||||
#define DEFAULT_PUB "sensors/espeasy/%sysname%/%tskname%/%valname%" // Enter your pub
|
||||
#define DEFAULT_SUB "sensors/espeasy/%sysname%/#" // Enter your sub
|
||||
#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
|
||||
// 1 = Domoticz HTTP
|
||||
// 2 = Domoticz MQTT
|
||||
// 3 = Nodo Telnet
|
||||
// 4 = ThingSpeak
|
||||
// 5 = OpenHAB MQTT
|
||||
// 6 = PiDome MQTT
|
||||
// 7 = EmonCMS
|
||||
// 8 = Generic HTTP
|
||||
// 9 = FHEM HTTP
|
||||
|
||||
|
||||
// --- Advanced Settings ---------------------------------------------------------------------------------
|
||||
#define DEFAULT_USE_RULES false // (true|false) Enable Rules?
|
||||
|
||||
#define DEFAULT_MQTT_RETAIN false // (true|false) Retain MQTT messages?
|
||||
#define DEFAULT_MQTT_DELAY 1000 // Time in milliseconds to retain MQTT messages
|
||||
|
||||
#define DEFAULT_USE_NTP false // (true|false) Use NTP Server
|
||||
#define DEFAULT_NTP_HOST "" // NTP Server Hostname
|
||||
#define DEFAULT_TIME_ZONE 0 // Time Offset (in minutes)
|
||||
#define DEFAULT_USE_DST false // (true|false) Use Daily Time Saving
|
||||
|
||||
#define LOG_TO_SERIAL 1
|
||||
#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_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_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
|
||||
|
||||
/*
|
||||
// --- Experimental Advanced Settings (NOT ACTIVES at this time) ------------------------------------
|
||||
#define DEFAULT_USE_GLOBAL_SYNC false // (true|false)
|
||||
#define DEFAULT_SYNC_UDP_PORT 0 //
|
||||
#define DEFAULT_IP_OCTET 0 //
|
||||
#define DEFAULT_WD_IC2_ADDRESS 0 //
|
||||
#define DEFAULT_USE_SSDP false // (true|false)
|
||||
#define DEFAULT_CON_FAIL_THRES 0 //
|
||||
#define DEFAULT_I2C_CLOCK_LIMIT 0 //
|
||||
*/
|
||||
|
||||
|
||||
// Enable FEATURE_ADC_VCC to measure supply voltage using the analog pin
|
||||
// Please note that the TOUT pin has to be disconnected in this mode
|
||||
// Use the "System Info" device to read the VCC value
|
||||
#ifndef FEATURE_ADC_VCC
|
||||
#define FEATURE_ADC_VCC false
|
||||
#endif
|
||||
|
||||
|
||||
//enable Arduino OTA updating.
|
||||
//Note: This adds around 10kb to the firmware size, and 1kb extra ram.
|
||||
// #define FEATURE_ARDUINO_OTA
|
||||
|
||||
//enable mDNS mode (adds about 6kb ram and some bytes IRAM)
|
||||
// #define FEATURE_MDNS
|
||||
|
||||
|
||||
//enable reporting status to ESPEasy developers.
|
||||
//this informs us of crashes and stability issues.
|
||||
// not finished yet!
|
||||
// #define FEATURE_REPORTING
|
||||
|
||||
//Select which plugin sets you want to build.
|
||||
//These are normally automaticly set via the Platformio build environment.
|
||||
//If you use ArduinoIDE you might need to uncomment some of them, depending on your needs
|
||||
//If you dont select any, a version with a minimal number of plugins will be biult for 512k versions.
|
||||
//(512k is NOT finsihed or tested yet as of v2.0.0-dev6)
|
||||
|
||||
//build all the normal stable plugins (on by default)
|
||||
#define PLUGIN_BUILD_NORMAL
|
||||
|
||||
//build all plugins that are in test stadium
|
||||
//#define PLUGIN_BUILD_TESTING
|
||||
|
||||
//build all plugins that still are being developed and are broken or incomplete
|
||||
//#define PLUGIN_BUILD_DEV
|
||||
|
||||
// ********************************************************************************
|
||||
// DO NOT CHANGE ANYTHING BELOW THIS LINE
|
||||
// ********************************************************************************
|
||||
#include "core_version.h"
|
||||
#ifndef ARDUINO_ESP8266_RELEASE_2_3_0
|
||||
#error ESPEasy v2.0 only support Arduino core 2.3.0. (Use the ESPEasy development branch to fix this)
|
||||
#endif
|
||||
|
||||
#define ESP_PROJECT_PID 2016110801L
|
||||
#define VERSION 2 // config file version (not ESPEasy version). increase if you make incompatible changes to config system.
|
||||
#define BUILD 20000 // git version 2.0.0
|
||||
#define BUILD_NOTES " - Mega"
|
||||
|
||||
#ifndef BUILD_GIT
|
||||
#define BUILD_GIT "(custom)"
|
||||
#endif
|
||||
|
||||
#define MAX_FLASHWRITES_PER_DAY 100 // per 24 hour window
|
||||
|
||||
#define NODE_TYPE_ID_ESP_EASY_STD 1
|
||||
#define NODE_TYPE_ID_ESP_EASYM_STD 17
|
||||
#define NODE_TYPE_ID_ESP_EASY32_STD 33
|
||||
#define NODE_TYPE_ID_ARDUINO_EASY_STD 65
|
||||
#define NODE_TYPE_ID_NANO_EASY_STD 81
|
||||
#define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASYM_STD
|
||||
|
||||
#define PLUGIN_INIT_ALL 1
|
||||
#define PLUGIN_INIT 2
|
||||
#define PLUGIN_READ 3
|
||||
#define PLUGIN_ONCE_A_SECOND 4
|
||||
#define PLUGIN_TEN_PER_SECOND 5
|
||||
#define PLUGIN_DEVICE_ADD 6
|
||||
#define PLUGIN_EVENTLIST_ADD 7
|
||||
#define PLUGIN_WEBFORM_SAVE 8
|
||||
#define PLUGIN_WEBFORM_LOAD 9
|
||||
#define PLUGIN_WEBFORM_SHOW_VALUES 10
|
||||
#define PLUGIN_GET_DEVICENAME 11
|
||||
#define PLUGIN_GET_DEVICEVALUENAMES 12
|
||||
#define PLUGIN_WRITE 13
|
||||
#define PLUGIN_EVENT_OUT 14
|
||||
#define PLUGIN_WEBFORM_SHOW_CONFIG 15
|
||||
#define PLUGIN_SERIAL_IN 16
|
||||
#define PLUGIN_UDP_IN 17
|
||||
#define PLUGIN_CLOCK_IN 18
|
||||
#define PLUGIN_TIMER_IN 19
|
||||
#define PLUGIN_FIFTY_PER_SECOND 20
|
||||
#define PLUGIN_SET_CONFIG 21
|
||||
#define PLUGIN_GET_DEVICEGPIONAMES 22
|
||||
#define PLUGIN_EXIT 23
|
||||
#define PLUGIN_GET_CONFIG 24
|
||||
|
||||
#define CPLUGIN_PROTOCOL_ADD 1
|
||||
#define CPLUGIN_PROTOCOL_TEMPLATE 2
|
||||
#define CPLUGIN_PROTOCOL_SEND 3
|
||||
#define CPLUGIN_PROTOCOL_RECV 4
|
||||
#define CPLUGIN_GET_DEVICENAME 5
|
||||
#define CPLUGIN_WEBFORM_SAVE 6
|
||||
#define CPLUGIN_WEBFORM_LOAD 7
|
||||
#define CPLUGIN_GET_PROTOCOL_DISPLAY_NAME 8
|
||||
#define CPLUGIN_TASK_CHANGE_NOTIFICATION 9
|
||||
#define CPLUGIN_INIT 10
|
||||
#define CPLUGIN_UDP_IN 11
|
||||
|
||||
#define CONTROLLER_HOSTNAME 1
|
||||
#define CONTROLLER_IP 2
|
||||
#define CONTROLLER_PORT 3
|
||||
#define CONTROLLER_USER 4
|
||||
#define CONTROLLER_PASS 5
|
||||
#define CONTROLLER_SUBSCRIBE 6
|
||||
#define CONTROLLER_PUBLISH 7
|
||||
|
||||
#define NPLUGIN_PROTOCOL_ADD 1
|
||||
#define NPLUGIN_GET_DEVICENAME 2
|
||||
#define NPLUGIN_WEBFORM_SAVE 3
|
||||
#define NPLUGIN_WEBFORM_LOAD 4
|
||||
#define NPLUGIN_WRITE 5
|
||||
#define NPLUGIN_NOTIFY 6
|
||||
#define NPLUGIN_NOT_FOUND 255
|
||||
|
||||
|
||||
#define LOG_LEVEL_ERROR 1
|
||||
#define LOG_LEVEL_INFO 2
|
||||
#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 CMD_REBOOT 89
|
||||
#define CMD_WIFI_DISCONNECT 135
|
||||
|
||||
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
|
||||
#define DEVICES_MAX 72
|
||||
#else
|
||||
#define DEVICES_MAX 64
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
#define TASKS_MAX 12 // max 12!
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
#define TASKS_MAX 32
|
||||
#endif
|
||||
|
||||
#define CONTROLLER_MAX 3 // max 4!
|
||||
#define NOTIFICATION_MAX 3 // max 4!
|
||||
#define VARS_PER_TASK 4
|
||||
#define PLUGIN_MAX DEVICES_MAX
|
||||
#define PLUGIN_CONFIGVAR_MAX 8
|
||||
#define PLUGIN_CONFIGFLOATVAR_MAX 4
|
||||
#define PLUGIN_CONFIGLONGVAR_MAX 4
|
||||
#define PLUGIN_EXTRACONFIGVAR_MAX 16
|
||||
#define CPLUGIN_MAX 16
|
||||
#define NPLUGIN_MAX 4
|
||||
#define UNIT_MAX 32 // Only relevant for UDP unicast message 'sweeps' and the nodelist.
|
||||
#define RULES_TIMER_MAX 8
|
||||
#define SYSTEM_TIMER_MAX 8
|
||||
#define SYSTEM_CMD_TIMER_MAX 2
|
||||
#define PINSTATE_TABLE_MAX 32
|
||||
#define RULES_MAX_SIZE 2048
|
||||
#define RULES_MAX_NESTING_LEVEL 3
|
||||
#define RULESETS_MAX 4
|
||||
#define RULES_BUFFER_SIZE 64
|
||||
|
||||
#define PIN_MODE_UNDEFINED 0
|
||||
#define PIN_MODE_INPUT 1
|
||||
#define PIN_MODE_OUTPUT 2
|
||||
#define PIN_MODE_PWM 3
|
||||
#define PIN_MODE_SERVO 4
|
||||
|
||||
#define SEARCH_PIN_STATE true
|
||||
#define NO_SEARCH_PIN_STATE false
|
||||
|
||||
#define DEVICE_TYPE_SINGLE 1 // connected through 1 datapin
|
||||
#define DEVICE_TYPE_DUAL 2 // connected through 2 datapins
|
||||
#define DEVICE_TYPE_TRIPLE 3 // connected through 3 datapins
|
||||
#define DEVICE_TYPE_ANALOG 10 // AIN/tout pin
|
||||
#define DEVICE_TYPE_I2C 20 // connected through I2C
|
||||
#define DEVICE_TYPE_DUMMY 99 // Dummy device, has no physical connection
|
||||
|
||||
#define SENSOR_TYPE_SINGLE 1
|
||||
#define SENSOR_TYPE_TEMP_HUM 2
|
||||
#define SENSOR_TYPE_TEMP_BARO 3
|
||||
#define SENSOR_TYPE_TEMP_HUM_BARO 4
|
||||
#define SENSOR_TYPE_DUAL 5
|
||||
#define SENSOR_TYPE_TRIPLE 6
|
||||
#define SENSOR_TYPE_QUAD 7
|
||||
#define SENSOR_TYPE_SWITCH 10
|
||||
#define SENSOR_TYPE_DIMMER 11
|
||||
#define SENSOR_TYPE_LONG 20
|
||||
#define SENSOR_TYPE_WIND 21
|
||||
|
||||
#define VALUE_SOURCE_SYSTEM 1
|
||||
#define VALUE_SOURCE_SERIAL 2
|
||||
#define VALUE_SOURCE_HTTP 3
|
||||
#define VALUE_SOURCE_MQTT 4
|
||||
#define VALUE_SOURCE_UDP 5
|
||||
|
||||
#define BOOT_CAUSE_MANUAL_REBOOT 0
|
||||
#define BOOT_CAUSE_COLD_BOOT 1
|
||||
#define BOOT_CAUSE_DEEP_SLEEP 2
|
||||
#define BOOT_CAUSE_EXT_WD 10
|
||||
|
||||
#define DAT_TASKS_SIZE 2048
|
||||
#define DAT_TASKS_CUSTOM_OFFSET 1024
|
||||
#define DAT_CUSTOM_CONTROLLER_SIZE 1024
|
||||
#define DAT_CONTROLLER_SIZE 1024
|
||||
#define DAT_NOTIFICATION_SIZE 1024
|
||||
|
||||
#define DAT_OFFSET_TASKS 4096 // each task = 2k, (1024 basic + 1024 bytes custom), 12 max
|
||||
#define DAT_OFFSET_CONTROLLER 28672 // each controller = 1k, 4 max
|
||||
#define DAT_OFFSET_CUSTOM_CONTROLLER 32768 // each custom controller config = 1k, 4 max.
|
||||
|
||||
|
||||
/*
|
||||
To modify the stock configuration without changing this repo file :
|
||||
- define USE_CUSTOM_H as a build flags. ie : export PLATFORMIO_BUILD_FLAGS="'-DUSE_CUSTOM_H'"
|
||||
- add a "Custom.h" file in this folder.
|
||||
*/
|
||||
#ifdef USE_CUSTOM_H
|
||||
#include "Custom.h"
|
||||
#endif
|
||||
|
||||
#define FILE_CONFIG "config.dat"
|
||||
#define FILE_SECURITY "security.dat"
|
||||
#define FILE_NOTIFICATION "notification.dat"
|
||||
#define FILE_RULES "rules1.dat"
|
||||
#include "ESPEasyTimeTypes.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266Ping.h>
|
||||
#include <DNSServer.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#ifdef FEATURE_MDNS
|
||||
#include <ESP8266mDNS.h>
|
||||
#endif
|
||||
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <PubSubClient.h>
|
||||
// #include <ArduinoJson.h>
|
||||
// #include <LiquidCrystal_I2C.h>
|
||||
#include <Servo.h>
|
||||
#define FS_NO_GLOBALS
|
||||
#include <FS.h>
|
||||
#include <SD.h>
|
||||
#include <ESP8266HTTPUpdateServer.h>
|
||||
ESP8266HTTPUpdateServer httpUpdater(true);
|
||||
#include <base64.h>
|
||||
#if FEATURE_ADC_VCC
|
||||
ADC_MODE(ADC_VCC);
|
||||
#endif
|
||||
#ifndef LWIP_OPEN_SRC
|
||||
#define LWIP_OPEN_SRC
|
||||
#endif
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "include/UdpContext.h"
|
||||
#include "limits.h"
|
||||
|
||||
extern "C" {
|
||||
#include "user_interface.h"
|
||||
}
|
||||
|
||||
|
||||
#ifdef FEATURE_ARDUINO_OTA
|
||||
#include <ArduinoOTA.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
bool ArduinoOTAtriggered=false;
|
||||
#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;
|
||||
#ifdef FEATURE_MDNS
|
||||
MDNSResponder mdns;
|
||||
#endif
|
||||
|
||||
// MQTT client
|
||||
WiFiClient mqtt;
|
||||
PubSubClient MQTTclient(mqtt);
|
||||
bool MQTTclient_should_reconnect = true;
|
||||
|
||||
// WebServer
|
||||
ESP8266WebServer WebServer(80);
|
||||
|
||||
// udp protocol stuff (syslog, global sync, node info list, ntp time)
|
||||
WiFiUDP portUDP;
|
||||
|
||||
// Forward declarations.
|
||||
bool WiFiConnected(uint32_t timeout_ms);
|
||||
bool hostReachable(const IPAddress& ip);
|
||||
bool hostReachable(const String& hostname);
|
||||
|
||||
extern "C" {
|
||||
#include "spi_flash.h"
|
||||
}
|
||||
extern "C" uint32_t _SPIFFS_start;
|
||||
extern "C" uint32_t _SPIFFS_end;
|
||||
extern "C" uint32_t _SPIFFS_page;
|
||||
extern "C" uint32_t _SPIFFS_block;
|
||||
|
||||
struct SecurityStruct
|
||||
{
|
||||
SecurityStruct() {
|
||||
memset(WifiSSID, 0, sizeof(WifiSSID));
|
||||
memset(WifiKey, 0, sizeof(WifiKey));
|
||||
memset(WifiSSID2, 0, sizeof(WifiSSID2));
|
||||
memset(WifiKey2, 0, sizeof(WifiKey2));
|
||||
memset(WifiAPKey, 0, sizeof(WifiAPKey));
|
||||
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
|
||||
memset(ControllerUser[i], 0, sizeof(ControllerUser[i]));
|
||||
memset(ControllerPassword[i], 0, sizeof(ControllerPassword[i]));
|
||||
}
|
||||
memset(Password, 0, sizeof(Password));
|
||||
}
|
||||
char WifiSSID[32];
|
||||
char WifiKey[64];
|
||||
char WifiSSID2[32];
|
||||
char WifiKey2[64];
|
||||
char WifiAPKey[64];
|
||||
char ControllerUser[CONTROLLER_MAX][26];
|
||||
char ControllerPassword[CONTROLLER_MAX][64];
|
||||
char Password[26];
|
||||
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
|
||||
} SecuritySettings;
|
||||
|
||||
struct SettingsStruct
|
||||
{
|
||||
SettingsStruct() :
|
||||
PID(0), Version(0), Build(0), IP_Octet(0), Unit(0), Delay(0),
|
||||
Pin_i2c_sda(-1), Pin_i2c_scl(-1), Pin_status_led(-1), Pin_sd_cs(-1),
|
||||
UDPPort(0), SyslogLevel(0), SerialLogLevel(0), WebLogLevel(0), SDLogLevel(0),
|
||||
BaudRate(0), MessageDelay(0), deepSleep(0),
|
||||
CustomCSS(false), DST(false), WDI2CAddress(0),
|
||||
UseRules(false), UseSerial(false), UseSSDP(false), UseNTP(false),
|
||||
WireClockStretchLimit(0), ConnectionFailuresThreshold(0),
|
||||
TimeZone(0), MQTTRetainFlag(false), InitSPI(false),
|
||||
Pin_status_led_Inversed(false), deepSleepOnFail(false), UseValueLogger(false),
|
||||
DST_Start(0), DST_End(0)
|
||||
{
|
||||
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
|
||||
Protocol[i] = 0;
|
||||
ControllerEnabled[i] = false;
|
||||
for (byte task = 0; task < TASKS_MAX; ++task) {
|
||||
TaskDeviceID[i][task] = 0;
|
||||
TaskDeviceSendData[i][task] = false;
|
||||
}
|
||||
}
|
||||
for (byte task = 0; task < TASKS_MAX; ++task) {
|
||||
TaskDeviceNumber[task] = 0;
|
||||
OLD_TaskDeviceID[task] = 0;
|
||||
TaskDevicePin1PullUp[task] = false;
|
||||
for (byte cv = 0; cv < PLUGIN_CONFIGVAR_MAX; ++cv) {
|
||||
TaskDevicePluginConfig[task][cv] = 0;
|
||||
}
|
||||
TaskDevicePin1Inversed[task] = false;
|
||||
for (byte cv = 0; cv < PLUGIN_CONFIGFLOATVAR_MAX; ++cv) {
|
||||
TaskDevicePluginConfigFloat[task][cv] = 0.0;
|
||||
}
|
||||
for (byte cv = 0; cv < PLUGIN_CONFIGLONGVAR_MAX; ++cv) {
|
||||
TaskDevicePluginConfigLong[task][cv] = 0;
|
||||
}
|
||||
OLD_TaskDeviceSendData[task] = false;
|
||||
TaskDeviceGlobalSync[task] = false;
|
||||
TaskDeviceDataFeed[task] = 0;
|
||||
TaskDeviceTimer[task] = 0;
|
||||
TaskDeviceEnabled[task] = false;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long PID;
|
||||
int Version;
|
||||
int16_t Build;
|
||||
byte IP[4];
|
||||
byte Gateway[4];
|
||||
byte Subnet[4];
|
||||
byte DNS[4];
|
||||
byte IP_Octet;
|
||||
byte Unit;
|
||||
char Name[26];
|
||||
char NTPHost[64];
|
||||
unsigned long Delay;
|
||||
int8_t Pin_i2c_sda;
|
||||
int8_t Pin_i2c_scl;
|
||||
int8_t Pin_status_led;
|
||||
int8_t Pin_sd_cs;
|
||||
int8_t PinBootStates[17];
|
||||
byte Syslog_IP[4];
|
||||
unsigned int UDPPort;
|
||||
byte SyslogLevel;
|
||||
byte SerialLogLevel;
|
||||
byte WebLogLevel;
|
||||
byte SDLogLevel;
|
||||
unsigned long BaudRate;
|
||||
unsigned long MessageDelay;
|
||||
byte deepSleep;
|
||||
boolean CustomCSS;
|
||||
boolean DST;
|
||||
byte WDI2CAddress;
|
||||
boolean UseRules;
|
||||
boolean UseSerial;
|
||||
boolean UseSSDP;
|
||||
boolean UseNTP;
|
||||
unsigned long WireClockStretchLimit;
|
||||
boolean _GlobalSync; // obsolete!
|
||||
unsigned long ConnectionFailuresThreshold;
|
||||
int16_t TimeZone;
|
||||
boolean MQTTRetainFlag;
|
||||
boolean InitSPI;
|
||||
byte Protocol[CONTROLLER_MAX];
|
||||
byte Notification[NOTIFICATION_MAX]; //notifications, point to a NPLUGIN id
|
||||
byte TaskDeviceNumber[TASKS_MAX];
|
||||
unsigned int OLD_TaskDeviceID[TASKS_MAX];
|
||||
union {
|
||||
struct {
|
||||
int8_t TaskDevicePin1[TASKS_MAX];
|
||||
int8_t TaskDevicePin2[TASKS_MAX];
|
||||
int8_t TaskDevicePin3[TASKS_MAX];
|
||||
byte TaskDevicePort[TASKS_MAX];
|
||||
};
|
||||
int8_t TaskDevicePin[4][TASKS_MAX];
|
||||
};
|
||||
boolean TaskDevicePin1PullUp[TASKS_MAX];
|
||||
int16_t TaskDevicePluginConfig[TASKS_MAX][PLUGIN_CONFIGVAR_MAX];
|
||||
boolean TaskDevicePin1Inversed[TASKS_MAX];
|
||||
float TaskDevicePluginConfigFloat[TASKS_MAX][PLUGIN_CONFIGFLOATVAR_MAX];
|
||||
long TaskDevicePluginConfigLong[TASKS_MAX][PLUGIN_CONFIGLONGVAR_MAX];
|
||||
boolean OLD_TaskDeviceSendData[TASKS_MAX];
|
||||
boolean TaskDeviceGlobalSync[TASKS_MAX];
|
||||
byte TaskDeviceDataFeed[TASKS_MAX];
|
||||
unsigned long TaskDeviceTimer[TASKS_MAX];
|
||||
boolean TaskDeviceEnabled[TASKS_MAX];
|
||||
boolean ControllerEnabled[CONTROLLER_MAX];
|
||||
boolean NotificationEnabled[NOTIFICATION_MAX];
|
||||
unsigned int TaskDeviceID[CONTROLLER_MAX][TASKS_MAX];
|
||||
boolean TaskDeviceSendData[CONTROLLER_MAX][TASKS_MAX];
|
||||
boolean Pin_status_led_Inversed;
|
||||
boolean deepSleepOnFail;
|
||||
boolean UseValueLogger;
|
||||
uint16_t DST_Start;
|
||||
uint16_t DST_End;
|
||||
//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
|
||||
} Settings;
|
||||
|
||||
struct ControllerSettingsStruct
|
||||
{
|
||||
ControllerSettingsStruct() : UseDNS(false), Port(0) {
|
||||
for (byte i = 0; i < 4; ++i) {
|
||||
IP[i] = 0;
|
||||
}
|
||||
memset(HostName, 0, sizeof(HostName));
|
||||
memset(Publish, 0, sizeof(Publish));
|
||||
memset(Subscribe, 0, sizeof(Subscribe));
|
||||
}
|
||||
boolean UseDNS;
|
||||
byte IP[4];
|
||||
unsigned int Port;
|
||||
char HostName[65];
|
||||
char Publish[129];
|
||||
char Subscribe[129];
|
||||
|
||||
IPAddress getIP() const {
|
||||
IPAddress host(IP[0], IP[1], IP[2], IP[3]);
|
||||
return host;
|
||||
}
|
||||
|
||||
String getHost() const {
|
||||
if (UseDNS) {
|
||||
return HostName;
|
||||
}
|
||||
return getIP().toString();
|
||||
}
|
||||
|
||||
void setHostname(const String& controllerhostname) {
|
||||
strncpy(HostName, controllerhostname.c_str(), sizeof(HostName));
|
||||
updateIPcache();
|
||||
}
|
||||
|
||||
boolean checkHostReachable(bool quick) {
|
||||
if (!WiFiConnected(10)) {
|
||||
return false; // Not connected, so no use in wasting time to connect to a host.
|
||||
}
|
||||
if (quick && ipSet()) return true;
|
||||
if (UseDNS) {
|
||||
if (!updateIPcache()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return hostReachable(getIP());
|
||||
}
|
||||
|
||||
boolean connectToHost(WiFiClient &client) {
|
||||
if (!checkHostReachable(true)) {
|
||||
return false; // Host not reachable
|
||||
}
|
||||
byte retry = 2;
|
||||
bool connected = false;
|
||||
while (retry > 0 && !connected) {
|
||||
--retry;
|
||||
connected = client.connect(getIP(), Port);
|
||||
if (connected) return true;
|
||||
if (!checkHostReachable(false))
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int beginPacket(WiFiUDP &client) {
|
||||
if (!checkHostReachable(true)) {
|
||||
return 0; // Host not reachable
|
||||
}
|
||||
byte retry = 2;
|
||||
int connected = 0;
|
||||
while (retry > 0 && !connected) {
|
||||
--retry;
|
||||
connected = client.beginPacket(getIP(), Port);
|
||||
if (connected != 0) return connected;
|
||||
if (!checkHostReachable(false))
|
||||
return false;
|
||||
delay(10);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String getHostPortString() const {
|
||||
String result = getHost();
|
||||
result += ":";
|
||||
result += Port;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
bool ipSet() {
|
||||
for (byte i = 0; i < 4; ++i) {
|
||||
if (IP[i] != 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool updateIPcache() {
|
||||
if (!UseDNS) {
|
||||
return true;
|
||||
}
|
||||
IPAddress tmpIP;
|
||||
if (WiFi.hostByName(HostName, tmpIP)) {
|
||||
for (byte x = 0; x < 4; x++) {
|
||||
IP[x] = tmpIP[x];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct NotificationSettingsStruct
|
||||
{
|
||||
NotificationSettingsStruct() : Port(0), Pin1(0), Pin2(0) {
|
||||
memset(Server, 0, sizeof(Server));
|
||||
memset(Domain, 0, sizeof(Domain));
|
||||
memset(Sender, 0, sizeof(Sender));
|
||||
memset(Receiver, 0, sizeof(Receiver));
|
||||
memset(Subject, 0, sizeof(Subject));
|
||||
memset(Body, 0, sizeof(Body));
|
||||
memset(User, 0, sizeof(User));
|
||||
memset(Pass, 0, sizeof(Pass));
|
||||
}
|
||||
|
||||
char Server[65];
|
||||
unsigned int Port;
|
||||
char Domain[65];
|
||||
char Sender[65];
|
||||
char Receiver[65];
|
||||
char Subject[129];
|
||||
char Body[513];
|
||||
byte Pin1;
|
||||
byte Pin2;
|
||||
char User[49];
|
||||
char Pass[33];
|
||||
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
|
||||
};
|
||||
|
||||
struct ExtraTaskSettingsStruct
|
||||
{
|
||||
ExtraTaskSettingsStruct() : TaskIndex(0) {
|
||||
TaskDeviceName[0] = 0;
|
||||
for (byte i = 0; i < VARS_PER_TASK; ++i) {
|
||||
for (byte j = 0; j < 41; ++j) {
|
||||
TaskDeviceFormula[i][j] = 0;
|
||||
TaskDeviceValueNames[i][j] = 0;
|
||||
TaskDeviceValueDecimals[i] = 0;
|
||||
}
|
||||
}
|
||||
for (byte i = 0; i < PLUGIN_EXTRACONFIGVAR_MAX; ++i) {
|
||||
TaskDevicePluginConfigLong[i] = 0;
|
||||
TaskDevicePluginConfig[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
byte TaskIndex;
|
||||
char TaskDeviceName[41];
|
||||
char TaskDeviceFormula[VARS_PER_TASK][41];
|
||||
char TaskDeviceValueNames[VARS_PER_TASK][41];
|
||||
long TaskDevicePluginConfigLong[PLUGIN_EXTRACONFIGVAR_MAX];
|
||||
byte TaskDeviceValueDecimals[VARS_PER_TASK];
|
||||
int16_t TaskDevicePluginConfig[PLUGIN_EXTRACONFIGVAR_MAX];
|
||||
} ExtraTaskSettings;
|
||||
|
||||
struct EventStruct
|
||||
{
|
||||
EventStruct() :
|
||||
Source(0), TaskIndex(0), ControllerIndex(0), ProtocolIndex(0), NotificationIndex(0),
|
||||
BaseVarIndex(0), idx(0), sensorType(0), Par1(0), Par2(0), Par3(0), Par4(0), Par5(0),
|
||||
OriginTaskIndex(0), Data(NULL) {}
|
||||
byte Source;
|
||||
byte TaskIndex; // index position in TaskSettings array, 0-11
|
||||
byte ControllerIndex; // index position in Settings.Controller, 0-3
|
||||
byte ProtocolIndex; // index position in protocol array, depending on which controller plugins are loaded.
|
||||
byte NotificationIndex; // index position in Settings.Notification, 0-3
|
||||
//Edwin: Not needed, and wasnt used. We can determine the protocol index with getNotificationProtocolIndex(NotificationIndex)
|
||||
// byte NotificationProtocolIndex; // index position in notification array, depending on which controller plugins are loaded.
|
||||
byte BaseVarIndex;
|
||||
int idx;
|
||||
byte sensorType;
|
||||
int Par1;
|
||||
int Par2;
|
||||
int Par3;
|
||||
int Par4;
|
||||
int Par5;
|
||||
byte OriginTaskIndex;
|
||||
String String1;
|
||||
String String2;
|
||||
String String3;
|
||||
byte *Data;
|
||||
};
|
||||
|
||||
#define LOG_STRUCT_MESSAGE_SIZE 128
|
||||
#define LOG_STRUCT_MESSAGE_LINES 20
|
||||
|
||||
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);
|
||||
timeStamp[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void add(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);
|
||||
}
|
||||
|
||||
// Read the next item and append it to the given string.
|
||||
// Returns whether new lines are available.
|
||||
bool get(String& output, const String& lineEnd) {
|
||||
if (!isEmpty()) {
|
||||
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
|
||||
output += formatLine(read_idx, lineEnd);
|
||||
}
|
||||
return !isEmpty();
|
||||
}
|
||||
|
||||
bool get(String& output, const String& lineEnd, int line) {
|
||||
int tmpread((write_idx + 1+line) % LOG_STRUCT_MESSAGE_LINES);
|
||||
if (timeStamp[tmpread] != 0) {
|
||||
output += formatLine(tmpread, lineEnd);
|
||||
}
|
||||
return !isEmpty();
|
||||
}
|
||||
|
||||
bool getAll(String& output, const String& lineEnd) {
|
||||
int tmpread((write_idx + 1) % LOG_STRUCT_MESSAGE_LINES);
|
||||
bool someAdded = false;
|
||||
while (tmpread != write_idx) {
|
||||
if (timeStamp[tmpread] != 0) {
|
||||
output += formatLine(tmpread, lineEnd);
|
||||
someAdded = true;
|
||||
}
|
||||
tmpread = (tmpread + 1)% LOG_STRUCT_MESSAGE_LINES;
|
||||
}
|
||||
return someAdded;
|
||||
}
|
||||
|
||||
bool isEmpty() {
|
||||
return (write_idx == read_idx);
|
||||
}
|
||||
|
||||
private:
|
||||
String formatLine(int index, const String& lineEnd) {
|
||||
String output;
|
||||
output += timeStamp[index];
|
||||
output += " : ";
|
||||
output += Message[index];
|
||||
output += lineEnd;
|
||||
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];
|
||||
|
||||
} Logging;
|
||||
|
||||
struct DeviceStruct
|
||||
{
|
||||
DeviceStruct() :
|
||||
Number(0), Type(0), VType(0), Ports(0),
|
||||
PullUpOption(false), InverseLogicOption(false), FormulaOption(false),
|
||||
ValueCount(0), Custom(false), SendDataOption(false), GlobalSyncOption(false),
|
||||
TimerOption(false), TimerOptional(false), DecimalsOnly(false) {}
|
||||
byte Number;
|
||||
byte Type;
|
||||
byte VType;
|
||||
byte Ports;
|
||||
boolean PullUpOption;
|
||||
boolean InverseLogicOption;
|
||||
boolean FormulaOption;
|
||||
byte ValueCount;
|
||||
boolean Custom;
|
||||
boolean SendDataOption;
|
||||
boolean GlobalSyncOption;
|
||||
boolean TimerOption;
|
||||
boolean TimerOptional;
|
||||
boolean DecimalsOnly;
|
||||
} Device[DEVICES_MAX + 1]; // 1 more because first device is empty device
|
||||
|
||||
struct ProtocolStruct
|
||||
{
|
||||
ProtocolStruct() :
|
||||
Number(0), usesMQTT(false), usesAccount(false), usesPassword(false),
|
||||
defaultPort(0), usesTemplate(false), usesID(false), Custom(false) {}
|
||||
byte Number;
|
||||
boolean usesMQTT;
|
||||
boolean usesAccount;
|
||||
boolean usesPassword;
|
||||
int defaultPort;
|
||||
boolean usesTemplate;
|
||||
boolean usesID;
|
||||
boolean Custom;
|
||||
} Protocol[CPLUGIN_MAX];
|
||||
|
||||
struct NotificationStruct
|
||||
{
|
||||
NotificationStruct() :
|
||||
Number(0), usesMessaging(false), usesGPIO(0) {}
|
||||
byte Number;
|
||||
boolean usesMessaging;
|
||||
byte usesGPIO;
|
||||
} Notification[NPLUGIN_MAX];
|
||||
|
||||
struct NodeStruct
|
||||
{
|
||||
NodeStruct() :
|
||||
age(0), build(0), nodeName(NULL), nodeType(0)
|
||||
{
|
||||
for (byte i = 0; i < 4; ++i) ip[i] = 0;
|
||||
}
|
||||
byte ip[4];
|
||||
byte age;
|
||||
uint16_t build;
|
||||
char* nodeName;
|
||||
byte nodeType;
|
||||
} Nodes[UNIT_MAX];
|
||||
|
||||
struct systemTimerStruct
|
||||
{
|
||||
systemTimerStruct() :
|
||||
timer(0), plugin(0), Par1(0), Par2(0), Par3(0) {}
|
||||
|
||||
unsigned long timer;
|
||||
byte plugin;
|
||||
byte Par1;
|
||||
byte Par2;
|
||||
byte Par3;
|
||||
} systemTimers[SYSTEM_TIMER_MAX];
|
||||
|
||||
struct systemCMDTimerStruct
|
||||
{
|
||||
systemCMDTimerStruct() : timer(0) {}
|
||||
unsigned long timer;
|
||||
String action;
|
||||
} systemCMDTimers[SYSTEM_CMD_TIMER_MAX];
|
||||
|
||||
struct pinStatesStruct
|
||||
{
|
||||
byte plugin;
|
||||
byte index;
|
||||
byte mode;
|
||||
uint16_t value;
|
||||
} pinStates[PINSTATE_TABLE_MAX];
|
||||
|
||||
|
||||
// this offsets are in blocks, bytes = blocks * 4
|
||||
#define RTC_BASE_STRUCT 64
|
||||
#define RTC_BASE_USERVAR 74
|
||||
|
||||
//max 40 bytes: ( 74 - 64 ) * 4
|
||||
struct RTCStruct
|
||||
{
|
||||
byte ID1;
|
||||
byte ID2;
|
||||
boolean unused1;
|
||||
byte factoryResetCounter;
|
||||
byte deepSleepState;
|
||||
byte unused2;
|
||||
byte flashDayCounter;
|
||||
unsigned long flashCounter;
|
||||
unsigned long bootCounter;
|
||||
} RTC;
|
||||
|
||||
|
||||
int deviceCount = -1;
|
||||
int protocolCount = -1;
|
||||
int notificationCount = -1;
|
||||
|
||||
boolean printToWeb = false;
|
||||
String printWebString = "";
|
||||
boolean printToWebJSON = false;
|
||||
|
||||
float UserVar[VARS_PER_TASK * TASKS_MAX];
|
||||
unsigned long RulesTimer[RULES_TIMER_MAX];
|
||||
|
||||
unsigned long timerSensor[TASKS_MAX];
|
||||
unsigned long timer100ms;
|
||||
unsigned long timer20ms;
|
||||
unsigned long timer1s;
|
||||
unsigned long timerwd;
|
||||
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;
|
||||
unsigned long timerAPoff = 0;
|
||||
unsigned long timerAwakeFromDeepSleep = 0;
|
||||
|
||||
#if FEATURE_ADC_VCC
|
||||
float vcc = -1.0;
|
||||
#endif
|
||||
|
||||
boolean WebLoggedIn = false;
|
||||
int WebLoggedInTimer = 300;
|
||||
|
||||
boolean (*Plugin_ptr[PLUGIN_MAX])(byte, struct EventStruct*, String&);
|
||||
byte Plugin_id[PLUGIN_MAX];
|
||||
|
||||
boolean (*CPlugin_ptr[CPLUGIN_MAX])(byte, struct EventStruct*, String&);
|
||||
byte CPlugin_id[CPLUGIN_MAX];
|
||||
|
||||
boolean (*NPlugin_ptr[NPLUGIN_MAX])(byte, struct EventStruct*, String&);
|
||||
byte NPlugin_id[NPLUGIN_MAX];
|
||||
|
||||
String dummyString = "";
|
||||
|
||||
byte lastBootCause = BOOT_CAUSE_MANUAL_REBOOT;
|
||||
|
||||
boolean wifiSetup = false;
|
||||
boolean wifiSetupConnect = false;
|
||||
uint8_t lastBSSID[6] = {0};
|
||||
boolean wifiConnected = false;
|
||||
unsigned long wifi_connect_timer = 0;
|
||||
unsigned int wifi_connect_attempt = 0;
|
||||
uint8_t lastWiFiSettings = 0;
|
||||
|
||||
|
||||
|
||||
unsigned long start = 0;
|
||||
unsigned long elapsed = 0;
|
||||
unsigned long loopCounter = 0;
|
||||
unsigned long loopCounterLast = 0;
|
||||
unsigned long loopCounterMax = 1;
|
||||
|
||||
unsigned long dailyResetCounter = 0;
|
||||
|
||||
String eventBuffer = "";
|
||||
|
||||
uint16_t lowestRAM = 0;
|
||||
String lowestRAMfunction = "";
|
||||
|
||||
bool shouldReboot=false;
|
||||
bool firstLoop=true;
|
||||
|
||||
boolean activeRuleSets[RULESETS_MAX];
|
||||
|
||||
#endif /* ESPEASY_GLOBALS_H_ */
|
||||
+75
-906
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,6 @@
|
||||
#ifndef ESPEASY_TIMETYPES_H_
|
||||
#define ESPEASY_TIMETYPES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct timeStruct {
|
||||
@@ -59,3 +62,8 @@ struct TimeChangeRule {
|
||||
void applyTimeZone(uint32_t curTime = 0);
|
||||
void setTimeZone(const TimeChangeRule& dstStart, const TimeChangeRule& stdStart, uint32_t curTime = 0);
|
||||
uint32_t calcTimeChangeForRule(const TimeChangeRule& r, int yr);
|
||||
String getTimeString(char delimiter, bool show_seconds=true);
|
||||
String getTimeString_ampm(char delimiter, bool show_seconds=true);
|
||||
|
||||
|
||||
#endif /* ESPEASY_TIMETYPES_H_ */
|
||||
|
||||
+500
-594
File diff suppressed because it is too large
Load Diff
+33
-169
@@ -32,35 +32,6 @@ void syslog(const char *message)
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Structs for UDP messaging
|
||||
\*********************************************************************************************/
|
||||
struct infoStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 3;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
byte deviceNumber;
|
||||
char taskName[26];
|
||||
char ValueNames[VARS_PER_TASK][26];
|
||||
};
|
||||
|
||||
struct dataStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 5;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
float Values[VARS_PER_TASK];
|
||||
};
|
||||
|
||||
//TODO: add sysinfoStruct
|
||||
|
||||
/*********************************************************************************************\
|
||||
Check UDP messages (ESPEasy propiertary protocol)
|
||||
\*********************************************************************************************/
|
||||
@@ -97,22 +68,10 @@ void checkUDP()
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packetBuffer[1] > 1 && packetBuffer[1] < 6)
|
||||
{
|
||||
String log = (F("UDP : Sensor msg "));
|
||||
for (byte x = 1; x < 6; x++)
|
||||
{
|
||||
log += " ";
|
||||
log += (int)packetBuffer[x];
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
}
|
||||
|
||||
// binary data!
|
||||
switch (packetBuffer[1])
|
||||
{
|
||||
|
||||
//TODO: use a nice struct for it
|
||||
case 1: // sysinfo message
|
||||
{
|
||||
byte mac[6];
|
||||
@@ -149,70 +108,13 @@ void checkUDP()
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: // sensor info pull request
|
||||
{
|
||||
SendUDPTaskInfo(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: // sensor info
|
||||
{
|
||||
if (Settings.GlobalSync)
|
||||
{
|
||||
struct infoStruct infoReply;
|
||||
memcpy((byte*)&infoReply, (byte*)&packetBuffer, sizeof(infoStruct));
|
||||
|
||||
// to prevent flash wear out (bugs in communication?) we can only write to an empty task
|
||||
// so it will write only once and has to be cleared manually through webgui
|
||||
if (Settings.TaskDeviceNumber[infoReply.destTaskIndex] == 0)
|
||||
{
|
||||
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
|
||||
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed
|
||||
for (byte x=0; x < CONTROLLER_MAX; x++)
|
||||
Settings.TaskDeviceSendData[x][infoReply.destTaskIndex] = false;
|
||||
strcpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy( ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x]);
|
||||
SaveTaskSettings(infoReply.destTaskIndex);
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: // sensor data pull request
|
||||
{
|
||||
SendUDPTaskData(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: // sensor data
|
||||
{
|
||||
if (Settings.GlobalSync)
|
||||
{
|
||||
struct dataStruct dataReply;
|
||||
memcpy((byte*)&dataReply, (byte*)&packetBuffer, sizeof(dataStruct));
|
||||
|
||||
// only if this task has a remote feed, update values
|
||||
if (Settings.TaskDeviceDataFeed[dataReply.destTaskIndex] != 0)
|
||||
{
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
{
|
||||
UserVar[dataReply.destTaskIndex * VARS_PER_TASK + x] = dataReply.Values[x];
|
||||
}
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(dataReply.destTaskIndex);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
struct EventStruct TempEvent;
|
||||
TempEvent.Data = (byte*)packetBuffer;
|
||||
TempEvent.Par1 = remoteIP[3];
|
||||
PluginCall(PLUGIN_UDP_IN, &TempEvent, dummyString);
|
||||
CPluginCall(CPLUGIN_UDP_IN, &TempEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -221,73 +123,6 @@ void checkUDP()
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send task info using UDP message
|
||||
\*********************************************************************************************/
|
||||
void SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
struct infoStruct infoReply;
|
||||
infoReply.sourcelUnit = Settings.Unit;
|
||||
infoReply.sourceTaskIndex = sourceTaskIndex;
|
||||
infoReply.destTaskIndex = destTaskIndex;
|
||||
LoadTaskSettings(infoReply.sourceTaskIndex);
|
||||
infoReply.deviceNumber = Settings.TaskDeviceNumber[infoReply.sourceTaskIndex];
|
||||
strcpy(infoReply.taskName, ExtraTaskSettings.TaskDeviceName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x]);
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
infoReply.destUnit = x;
|
||||
sendUDP(x, (byte*)&infoReply, sizeof(infoStruct));
|
||||
delay(10);
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send task data using UDP message
|
||||
\*********************************************************************************************/
|
||||
void SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
struct dataStruct dataReply;
|
||||
dataReply.sourcelUnit = Settings.Unit;
|
||||
dataReply.sourceTaskIndex = sourceTaskIndex;
|
||||
dataReply.destTaskIndex = destTaskIndex;
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
dataReply.Values[x] = UserVar[dataReply.sourceTaskIndex * VARS_PER_TASK + x];
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
dataReply.destUnit = x;
|
||||
sendUDP(x, (byte*) &dataReply, sizeof(dataStruct));
|
||||
delay(10);
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send event using UDP message
|
||||
\*********************************************************************************************/
|
||||
@@ -739,14 +574,19 @@ void SSDP_update() {
|
||||
}
|
||||
}
|
||||
|
||||
// Check WiFi connection. Maximum timeout 2000 msec.
|
||||
// Check WiFi connection. Maximum timeout 500 msec.
|
||||
bool WiFiConnected(uint32_t timeout_ms) {
|
||||
uint32_t timer = millis() + (timeout_ms > 2000 ? 2000 : timeout_ms);
|
||||
uint32_t min_delay = timeout_ms / 10;
|
||||
uint32_t timer = millis() + (timeout_ms > 500 ? 500 : timeout_ms);
|
||||
uint32_t min_delay = timeout_ms / 20;
|
||||
if (min_delay < 10) {
|
||||
yield(); // Allow at least once time for backgroundtasks
|
||||
min_delay = 10;
|
||||
}
|
||||
if (!wifiConnected) {
|
||||
// Apparently something needs network, perform check to see if it is ready now.
|
||||
if (tryConnectWiFi())
|
||||
checkWifiJustConnected();
|
||||
}
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
if (timeOutReached(timer)) {
|
||||
return false;
|
||||
@@ -755,3 +595,27 @@ bool WiFiConnected(uint32_t timeout_ms) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hostReachable(const IPAddress& ip) {
|
||||
// Only do 1 ping at a time to return early
|
||||
byte retry = 3;
|
||||
while (retry > 0) {
|
||||
if (Ping.ping(ip, 1)) return true;
|
||||
delay(50);
|
||||
--retry;
|
||||
}
|
||||
String log = F("Host unreachable: ");
|
||||
log += ip;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hostReachable(const String& hostname) {
|
||||
IPAddress 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);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,383 @@
|
||||
/********************************************************************************************\
|
||||
Convert a char string to integer
|
||||
\*********************************************************************************************/
|
||||
//FIXME: change original code so it uses String and String.toInt()
|
||||
unsigned long str2int(char *string)
|
||||
{
|
||||
unsigned long temp = atof(string);
|
||||
return temp;
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
Check if valid float and convert string to float.
|
||||
\*********************************************************************************************/
|
||||
bool string2float(const String& string, float& floatvalue) {
|
||||
if (!isFloat(string)) return false;
|
||||
floatvalue = atof(string.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Convert a char string to IP byte array
|
||||
\*********************************************************************************************/
|
||||
boolean str2ip(const String& string, byte* IP) {
|
||||
return str2ip(string.c_str(), IP);
|
||||
}
|
||||
|
||||
boolean str2ip(const char *string, byte* IP)
|
||||
{
|
||||
IPAddress tmpip; // Default constructor => set to 0.0.0.0
|
||||
if (*string == 0 || tmpip.fromString(string)) {
|
||||
// Eiher empty string or a valid IP addres, so copy value.
|
||||
for (byte i = 0; i < 4; ++i)
|
||||
IP[i] = tmpip[i];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call this by first declaring a char array of size 20, like:
|
||||
// char strIP[20];
|
||||
// formatIP(ip, strIP);
|
||||
void formatIP(const IPAddress& ip, char (&strIP)[20]) {
|
||||
sprintf_P(strIP, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
}
|
||||
|
||||
String formatIP(const IPAddress& ip) {
|
||||
char strIP[20];
|
||||
formatIP(ip, strIP);
|
||||
return String(strIP);
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Workaround for removing trailing white space when String() converts a float with 0 decimals
|
||||
\*********************************************************************************************/
|
||||
String toString(float value, byte decimals)
|
||||
{
|
||||
String sValue = String(value, decimals);
|
||||
sValue.trim();
|
||||
return sValue;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
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 log = F("Invalid float value for TaskIndex: ");
|
||||
log += event->TaskIndex;
|
||||
log += F(" varnumber: ");
|
||||
log += rel_index;
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
f = 0;
|
||||
}
|
||||
return toString(f, ExtraTaskSettings.TaskDeviceValueDecimals[rel_index]);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Wrap a string with given pre- and postfix string.
|
||||
\*********************************************************************************************/
|
||||
String wrap_String(const String& string, const String& wrap) {
|
||||
String result;
|
||||
result.reserve(string.length() + 2* wrap.length());
|
||||
result = wrap;
|
||||
result += string;
|
||||
result += wrap;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Format an object value pair for use in JSON.
|
||||
\*********************************************************************************************/
|
||||
String to_json_object_value(const String& object, const String& value) {
|
||||
String result;
|
||||
result.reserve(object.length() + value.length() + 6);
|
||||
result = wrap_String(object, F("\""));
|
||||
result += F(":");
|
||||
if (value.length() == 0 || !isFloat(value)) {
|
||||
result += wrap_String(value, F("\""));
|
||||
} else {
|
||||
result += value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Parse a string and get the xth command or parameter
|
||||
\*********************************************************************************************/
|
||||
String parseString(String& string, byte indexFind)
|
||||
{
|
||||
String tmpString = string;
|
||||
tmpString += ",";
|
||||
tmpString.replace(" ", ",");
|
||||
String locateString = "";
|
||||
byte count = 0;
|
||||
int index = tmpString.indexOf(',');
|
||||
while (index > 0)
|
||||
{
|
||||
count++;
|
||||
locateString = tmpString.substring(0, index);
|
||||
tmpString = tmpString.substring(index + 1);
|
||||
index = tmpString.indexOf(',');
|
||||
if (count == indexFind)
|
||||
{
|
||||
locateString.toLowerCase();
|
||||
return locateString;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Parse a string and get the xth command or parameter
|
||||
\*********************************************************************************************/
|
||||
int getParamStartPos(String& string, byte indexFind)
|
||||
{
|
||||
String tmpString = string;
|
||||
byte count = 0;
|
||||
tmpString.replace(" ", ",");
|
||||
for (unsigned int x = 0; x < tmpString.length(); x++)
|
||||
{
|
||||
if (tmpString.charAt(x) == ',')
|
||||
{
|
||||
count++;
|
||||
if (count == (indexFind - 1))
|
||||
return x + 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//escapes special characters in strings for use in html-forms
|
||||
void htmlEscape(String & html)
|
||||
{
|
||||
html.replace("&", "&");
|
||||
html.replace("\"", """);
|
||||
html.replace("'", "'");
|
||||
html.replace("<", "<");
|
||||
html.replace(">", ">");
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
replace other system variables like %sysname%, %systime%, %ip%
|
||||
\*********************************************************************************************/
|
||||
void parseControllerVariables(String& s, struct EventStruct *event, boolean useURLencode) {
|
||||
parseSystemVariables(s, useURLencode);
|
||||
parseEventVariables(s, event, useURLencode);
|
||||
parseStandardConversions(s, useURLencode);
|
||||
}
|
||||
|
||||
|
||||
void repl(const String& key, const String& val, String& s, boolean useURLencode)
|
||||
{
|
||||
if (useURLencode) {
|
||||
s.replace(key, URLEncode(val.c_str()));
|
||||
} else {
|
||||
s.replace(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
void parseSpecialCharacters(String& s, boolean useURLencode)
|
||||
{
|
||||
bool no_accolades = s.indexOf('{') == -1 || s.indexOf('}') == -1;
|
||||
bool no_html_entity = s.indexOf('&') == -1 || s.indexOf(';') == -1;
|
||||
if (no_accolades && no_html_entity)
|
||||
return; // Nothing to replace
|
||||
|
||||
{
|
||||
// Degree
|
||||
const char degree[3] = {0xc2, 0xb0, 0}; // Unicode degree symbol
|
||||
const char degreeC[4] = {0xe2, 0x84, 0x83, 0}; // Unicode degreeC symbol
|
||||
const char degree_C[4] = {0xc2, 0xb0, 'C', 0}; // Unicode degree symbol + captial C
|
||||
repl(F("{D}"), degree, s, useURLencode);
|
||||
repl(F("°"), degree, s, useURLencode);
|
||||
repl(degreeC, degree_C, s, useURLencode);
|
||||
}
|
||||
{
|
||||
// Angle quotes
|
||||
const char laquo[3] = {0xc2, 0xab, 0}; // Unicode left angle quotes symbol
|
||||
const char raquo[3] = {0xc2, 0xbb, 0}; // Unicode right angle quotes symbol
|
||||
repl(F("{<<}"), laquo, s, useURLencode);
|
||||
repl(F("«"), laquo, s, useURLencode);
|
||||
repl(F("{>>}"), raquo, s, useURLencode);
|
||||
repl(F("»"), raquo, s, useURLencode);
|
||||
}
|
||||
{
|
||||
// Greek letter Mu
|
||||
const char mu[3] = {0xc2, 0xb5, 0}; // Unicode greek letter mu
|
||||
repl(F("{u}"), mu, s, useURLencode);
|
||||
repl(F("µ"), mu, s, useURLencode);
|
||||
}
|
||||
{
|
||||
// Currency
|
||||
const char euro[4] = {0xe2, 0x82, 0xac, 0}; // Unicode euro symbol
|
||||
const char yen[3] = {0xc2, 0xa5, 0}; // Unicode yen symbol
|
||||
const char pound[3] = {0xc2, 0xa3, 0}; // Unicode pound symbol
|
||||
const char cent[3] = {0xc2, 0xa2, 0}; // Unicode cent symbol
|
||||
repl(F("{E}"), euro, s, useURLencode);
|
||||
repl(F("€"), euro, s, useURLencode);
|
||||
repl(F("{Y}"), yen, s, useURLencode);
|
||||
repl(F("¥"), yen, s, useURLencode);
|
||||
repl(F("{P}"), pound, s, useURLencode);
|
||||
repl(F("£"), pound, s, useURLencode);
|
||||
repl(F("{c}"), cent, s, useURLencode);
|
||||
repl(F("¢"), cent, s, useURLencode);
|
||||
}
|
||||
{
|
||||
// Math symbols
|
||||
const char sup1[3] = {0xc2, 0xb9, 0}; // Unicode sup1 symbol
|
||||
const char sup2[3] = {0xc2, 0xb2, 0}; // Unicode sup2 symbol
|
||||
const char sup3[3] = {0xc2, 0xb3, 0}; // Unicode sup3 symbol
|
||||
const char frac14[3] = {0xc2, 0xbc, 0}; // Unicode frac14 symbol
|
||||
const char frac12[3] = {0xc2, 0xbd, 0}; // Unicode frac12 symbol
|
||||
const char frac34[3] = {0xc2, 0xbe, 0}; // Unicode frac34 symbol
|
||||
const char plusmn[3] = {0xc2, 0xb1, 0}; // Unicode plusmn symbol
|
||||
const char times[3] = {0xc3, 0x97, 0}; // Unicode times symbol
|
||||
const char divide[3] = {0xc3, 0xb7, 0}; // Unicode divide symbol
|
||||
repl(F("{^1}"), sup1, s, useURLencode);
|
||||
repl(F("¹"), sup1, s, useURLencode);
|
||||
repl(F("{^2}"), sup2, s, useURLencode);
|
||||
repl(F("²"), sup2, s, useURLencode);
|
||||
repl(F("{^3}"), sup3, s, useURLencode);
|
||||
repl(F("³"), sup3, s, useURLencode);
|
||||
repl(F("{1_4}"), frac14, s, useURLencode);
|
||||
repl(F("¼"), frac14, s, useURLencode);
|
||||
repl(F("{1_2}"), frac12, s, useURLencode);
|
||||
repl(F("½"), frac12, s, useURLencode);
|
||||
repl(F("{3_4}"), frac34, s, useURLencode);
|
||||
repl(F("¾"), frac34, s, useURLencode);
|
||||
repl(F("{+-}"), plusmn, s, useURLencode);
|
||||
repl(F("±"), plusmn, s, useURLencode);
|
||||
repl(F("{x}"), times, s, useURLencode);
|
||||
repl(F("×"), times, s, useURLencode);
|
||||
repl(F("{..}"), divide, s, useURLencode);
|
||||
repl(F("÷"), divide, s, useURLencode);
|
||||
}
|
||||
}
|
||||
|
||||
// Simple macro to create the replacement string only when needed.
|
||||
#define SMART_REPL(T,S) if (s.indexOf(T) != -1) { repl((T), (S), s, useURLencode);}
|
||||
void parseSystemVariables(String& s, boolean useURLencode)
|
||||
{
|
||||
parseSpecialCharacters(s, useURLencode);
|
||||
if (s.indexOf('%') == -1)
|
||||
return; // Nothing to replace
|
||||
|
||||
#if FEATURE_ADC_VCC
|
||||
repl(F("%vcc%"), String(vcc), s, useURLencode);
|
||||
#endif
|
||||
repl(F("%CR%"), F("\r"), s, useURLencode);
|
||||
repl(F("%LF%"), F("\n"), s, useURLencode);
|
||||
SMART_REPL(F("%ip%"),WiFi.localIP().toString())
|
||||
SMART_REPL(F("%rssi%"), String((WiFi.status() == WL_CONNECTED) ? WiFi.RSSI() : 0))
|
||||
SMART_REPL(F("%ssid%"), (WiFi.status() == WL_CONNECTED) ? WiFi.SSID() : F("--"))
|
||||
SMART_REPL(F("%unit%"), String(Settings.Unit))
|
||||
SMART_REPL(F("%mac%"), String(WiFi.macAddress()))
|
||||
#if defined(ESP8266)
|
||||
SMART_REPL(F("%mac_int%"), String(ESP.getChipId())) // Last 24 bit of MAC address as integer, to be used in rules.
|
||||
#endif
|
||||
|
||||
if (s.indexOf(F("%sys")) != -1) {
|
||||
SMART_REPL(F("%sysload%"), String(100 - (100 * loopCounterLast / loopCounterMax)))
|
||||
SMART_REPL(F("%systm_hm%"), getTimeString(':', false))
|
||||
SMART_REPL(F("%systm_hm_am%"), getTimeString_ampm(':', false))
|
||||
SMART_REPL(F("%systime%"), getTimeString(':'))
|
||||
SMART_REPL(F("%systime_am%"), getTimeString_ampm(':'))
|
||||
repl(F("%sysname%"), Settings.Name, s, useURLencode);
|
||||
|
||||
// valueString is being used by the macro.
|
||||
char valueString[5];
|
||||
#define SMART_REPL_TIME(T,F,V) if (s.indexOf(T) != -1) { sprintf_P(valueString, (F), (V)); repl((T),valueString, s, 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("%sysday%"), PSTR("%02d"), day())
|
||||
SMART_REPL_TIME(F("%sysmonth%"),PSTR("%02d"), month())
|
||||
SMART_REPL_TIME(F("%sysyear%"), PSTR("%04d"), year())
|
||||
SMART_REPL_TIME(F("%sysyears%"),PSTR("%02d"), year()%100)
|
||||
SMART_REPL(F("%sysweekday%"), String(weekday()))
|
||||
SMART_REPL(F("%sysweekday_s%"), weekday_str())
|
||||
#undef SMART_REPL_TIME
|
||||
}
|
||||
SMART_REPL(F("%lcltime%"), getDateTimeString('-',':',' '))
|
||||
SMART_REPL(F("%lcltime_am%"), getDateTimeString_ampm('-',':',' '))
|
||||
SMART_REPL(F("%uptime%"), String(wdcounter / 2))
|
||||
|
||||
repl(F("%tskname%"), ExtraTaskSettings.TaskDeviceName, s, useURLencode);
|
||||
if (s.indexOf("%vname") != -1) {
|
||||
repl(F("%vname1%"), ExtraTaskSettings.TaskDeviceValueNames[0], s, useURLencode);
|
||||
repl(F("%vname2%"), ExtraTaskSettings.TaskDeviceValueNames[1], s, useURLencode);
|
||||
repl(F("%vname3%"), ExtraTaskSettings.TaskDeviceValueNames[2], s, useURLencode);
|
||||
repl(F("%vname4%"), ExtraTaskSettings.TaskDeviceValueNames[3], s, useURLencode);
|
||||
}
|
||||
}
|
||||
|
||||
void parseEventVariables(String& s, struct EventStruct *event, boolean useURLencode)
|
||||
{
|
||||
SMART_REPL(F("%id%"), String(event->idx))
|
||||
if (s.indexOf("%val") != -1) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef SMART_REPL
|
||||
|
||||
bool getConvertArgument(const String& marker, const String& s, float& argument, int& startIndex, int& endIndex) {
|
||||
startIndex = s.indexOf(marker);
|
||||
if (startIndex == -1) return false;
|
||||
|
||||
int startIndexArgument = startIndex + marker.length();
|
||||
if (s.charAt(startIndexArgument) != '(') {
|
||||
return false;
|
||||
}
|
||||
++startIndexArgument;
|
||||
endIndex = s.indexOf(')', startIndexArgument);
|
||||
if (endIndex == -1) return false;
|
||||
|
||||
String argumentString = s.substring(startIndexArgument, endIndex);
|
||||
if (argumentString.length() == 0 || !isFloat(argumentString)) return false;
|
||||
|
||||
argument = argumentString.toFloat();
|
||||
++endIndex; // Must also strip ')' from the original string.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse conversions marked with "%conv_marker%(float)"
|
||||
// Must be called last, since all sensor values must be converted, processed, etc.
|
||||
void parseStandardConversions(String& s, boolean useURLencode) {
|
||||
if (s.indexOf(F("%c_")) == -1)
|
||||
return; // Nothing to replace
|
||||
|
||||
float arg = 0.0;
|
||||
int startIndex = 0;
|
||||
int endIndex = 0;
|
||||
// These replacements should be done in a while loop per marker,
|
||||
// since they also replace the numerical parameter.
|
||||
// The marker may occur more than once per string, but with different parameters.
|
||||
#define SMART_CONV(T,FUN) while (getConvertArgument((T), s, arg, startIndex, endIndex)) { repl(s.substring(startIndex, endIndex), (FUN), s, useURLencode); }
|
||||
SMART_CONV(F("%c_w_dir%"), getBearing(arg))
|
||||
SMART_CONV(F("%c_c2f%"), toString(CelsiusToFahrenheit(arg), 1))
|
||||
SMART_CONV(F("%c_ms2Bft%"), String(m_secToBeaufort(arg)))
|
||||
SMART_CONV(F("%c_cm2imp%"), centimeterToImperialLength(arg))
|
||||
SMART_CONV(F("%c_mm2imp%"), millimeterToImperialLength(arg))
|
||||
SMART_CONV(F("%c_m2day%"), toString(minutesToDay(arg), 2))
|
||||
SMART_CONV(F("%c_m2dh%"), minutesToDayHour(arg))
|
||||
SMART_CONV(F("%c_m2dhm%"), minutesToDayHourMinute(arg))
|
||||
SMART_CONV(F("%c_s2dhms%"), secondsToDayHourMinuteSecond(arg))
|
||||
#undef SMART_CONV
|
||||
}
|
||||
+115
-64
@@ -74,6 +74,13 @@ void setTime(unsigned long t) {
|
||||
sysTime = (uint32_t)t;
|
||||
nextSyncTime = (uint32_t)t + syncInterval;
|
||||
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
static bool firstUpdate = true;
|
||||
String event = firstUpdate ? F("Time#Initialized") : F("Time#Set");
|
||||
firstUpdate = false;
|
||||
rulesProcessing(event);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long now() {
|
||||
@@ -89,7 +96,8 @@ unsigned long now() {
|
||||
setTime(t);
|
||||
applyTimeZone(t);
|
||||
} else {
|
||||
nextSyncTime = sysTime + syncInterval;
|
||||
// Unable to sync, retry again in a minute
|
||||
nextSyncTime = sysTime + 60;
|
||||
}
|
||||
}
|
||||
uint32_t localSystime = toLocal(sysTime);
|
||||
@@ -141,11 +149,19 @@ byte second()
|
||||
return tm.Second;
|
||||
}
|
||||
|
||||
// day of week, sunday is day 1
|
||||
int weekday()
|
||||
{
|
||||
return tm.Wday;
|
||||
}
|
||||
|
||||
String weekday_str()
|
||||
{
|
||||
const int wday(weekday() - 1); // here: Count from Sunday = 0
|
||||
const String weekDays = F("SunMonTueWedThuFriSat");
|
||||
return weekDays.substring(wday * 3, wday * 3 + 3);
|
||||
}
|
||||
|
||||
void initTime()
|
||||
{
|
||||
nextSyncTime = 0;
|
||||
@@ -161,9 +177,10 @@ void checkTime()
|
||||
PrevMinutes = tm.Minute;
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
String weekDays = F("AllSunMonTueWedThuFriSat");
|
||||
String event = F("Clock#Time=");
|
||||
event += weekDays.substring(weekday() * 3, weekday() * 3 + 3);
|
||||
String event;
|
||||
event.reserve(21);
|
||||
event = F("Clock#Time=");
|
||||
event += weekday_str();
|
||||
event += ",";
|
||||
if (hour() < 10)
|
||||
event += "0";
|
||||
@@ -183,65 +200,62 @@ unsigned long getNtpTime()
|
||||
if (!Settings.UseNTP || !WiFiConnected(100)) {
|
||||
return 0;
|
||||
}
|
||||
IPAddress timeServerIP;
|
||||
const char* ntpServerName = "pool.ntp.org";
|
||||
// Have to do a lookup eacht time, since the NTP pool always returns another IP
|
||||
if (Settings.NTPHost[0] != 0)
|
||||
WiFi.hostByName(Settings.NTPHost, timeServerIP);
|
||||
else
|
||||
WiFi.hostByName(ntpServerName, timeServerIP);
|
||||
|
||||
if (!hostReachable(timeServerIP))
|
||||
return 0;
|
||||
|
||||
WiFiUDP udp;
|
||||
udp.begin(123);
|
||||
for (byte x = 1; x < 4; x++)
|
||||
{
|
||||
String log = F("NTP : NTP sync request:");
|
||||
log += x;
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
IPAddress timeServerIP;
|
||||
const char* ntpServerName = "pool.ntp.org";
|
||||
String log = F("NTP : NTP send to ");
|
||||
log += timeServerIP.toString();
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
if (Settings.NTPHost[0] != 0)
|
||||
WiFi.hostByName(Settings.NTPHost, timeServerIP);
|
||||
else
|
||||
WiFi.hostByName(ntpServerName, timeServerIP);
|
||||
while (udp.parsePacket() > 0) ; // discard any previously received packets
|
||||
|
||||
log = F("NTP : NTP send to ");
|
||||
log += timeServerIP.toString();
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
memset(packetBuffer, 0, NTP_PACKET_SIZE);
|
||||
packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
packetBuffer[1] = 0; // Stratum, or type of clock
|
||||
packetBuffer[2] = 6; // Polling Interval
|
||||
packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
packetBuffer[12] = 49;
|
||||
packetBuffer[13] = 0x4E;
|
||||
packetBuffer[14] = 49;
|
||||
packetBuffer[15] = 52;
|
||||
udp.beginPacket(timeServerIP, 123); //NTP requests are to port 123
|
||||
udp.write(packetBuffer, NTP_PACKET_SIZE);
|
||||
udp.endPacket();
|
||||
|
||||
while (udp.parsePacket() > 0) ; // discard any previously received packets
|
||||
|
||||
memset(packetBuffer, 0, NTP_PACKET_SIZE);
|
||||
packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
packetBuffer[1] = 0; // Stratum, or type of clock
|
||||
packetBuffer[2] = 6; // Polling Interval
|
||||
packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
packetBuffer[12] = 49;
|
||||
packetBuffer[13] = 0x4E;
|
||||
packetBuffer[14] = 49;
|
||||
packetBuffer[15] = 52;
|
||||
udp.beginPacket(timeServerIP, 123); //NTP requests are to port 123
|
||||
udp.write(packetBuffer, NTP_PACKET_SIZE);
|
||||
udp.endPacket();
|
||||
|
||||
uint32_t beginWait = millis();
|
||||
while (!timeOutReached(beginWait + 1000)) {
|
||||
int size = udp.parsePacket();
|
||||
if (size >= NTP_PACKET_SIZE) {
|
||||
udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
|
||||
unsigned long secsSince1900;
|
||||
// convert four bytes starting at location 40 to a long integer
|
||||
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[43];
|
||||
log = F("NTP : NTP replied: ");
|
||||
log += timePassedSince(beginWait);
|
||||
log += F(" mSec");
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
return secsSince1900 - 2208988800UL;
|
||||
}
|
||||
uint32_t beginWait = millis();
|
||||
while (!timeOutReached(beginWait + 1000)) {
|
||||
int size = udp.parsePacket();
|
||||
if (size >= NTP_PACKET_SIZE) {
|
||||
udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
|
||||
unsigned long secsSince1900;
|
||||
// convert four bytes starting at location 40 to a long integer
|
||||
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[43];
|
||||
log = F("NTP : NTP replied: ");
|
||||
log += timePassedSince(beginWait);
|
||||
log += F(" mSec");
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
return secsSince1900 - 2208988800UL;
|
||||
}
|
||||
log = F("NTP : No reply");
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
}
|
||||
log = F("NTP : No reply");
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -376,16 +390,40 @@ String getDateString()
|
||||
|
||||
// returns the current Time separated by the given delimiter
|
||||
// time format example with ':' delimiter: 23:59:59 (HH:MM:SS)
|
||||
String getTimeString(const timeStruct& ts, char delimiter)
|
||||
String getTimeString(const timeStruct& ts, char delimiter, bool am_pm, bool show_seconds)
|
||||
{
|
||||
char TimeString[20]; //19 digits plus the null char
|
||||
sprintf_P(TimeString, PSTR("%02d%c%02d%c%02d"), ts.Hour, delimiter, ts.Minute, delimiter, ts.Second);
|
||||
if (am_pm) {
|
||||
uint8_t hour(ts.Hour % 12);
|
||||
if (hour == 0) { hour = 12; }
|
||||
const char a_or_p = ts.Hour < 12 ? 'A' : 'P';
|
||||
if (show_seconds) {
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d%c%02d %cM"),
|
||||
hour, delimiter, ts.Minute, delimiter, ts.Second, a_or_p);
|
||||
} else {
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d %cM"),
|
||||
hour, delimiter, ts.Minute, a_or_p);
|
||||
}
|
||||
} else {
|
||||
if (show_seconds) {
|
||||
sprintf_P(TimeString, PSTR("%02d%c%02d%c%02d"),
|
||||
ts.Hour, delimiter, ts.Minute, delimiter, ts.Second);
|
||||
} else {
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d"),
|
||||
ts.Hour, delimiter, ts.Minute);
|
||||
}
|
||||
}
|
||||
return TimeString;
|
||||
}
|
||||
|
||||
String getTimeString(char delimiter)
|
||||
String getTimeString(char delimiter, bool show_seconds /*=true*/)
|
||||
{
|
||||
return getTimeString(tm, delimiter);
|
||||
return getTimeString(tm, delimiter, false, show_seconds);
|
||||
}
|
||||
|
||||
String getTimeString_ampm(char delimiter, bool show_seconds /*=true*/)
|
||||
{
|
||||
return getTimeString(tm, delimiter, true, show_seconds);
|
||||
}
|
||||
|
||||
// returns the current Time without delimiter
|
||||
@@ -395,26 +433,35 @@ String getTimeString()
|
||||
return getTimeString('\0');
|
||||
}
|
||||
|
||||
String getTimeString_ampm()
|
||||
{
|
||||
return getTimeString_ampm('\0');
|
||||
}
|
||||
|
||||
// returns the current Date and Time separated by the given delimiter
|
||||
// if called like this: getDateTimeString('\0', '\0', '\0');
|
||||
// it will give back this: 20161231235959 (YYYYMMDDHHMMSS)
|
||||
String getDateTimeString(const timeStruct& ts, char dateDelimiter, char timeDelimiter, char dateTimeDelimiter)
|
||||
String getDateTimeString(const timeStruct& ts, char dateDelimiter, char timeDelimiter, char dateTimeDelimiter, bool am_pm)
|
||||
{
|
||||
String ret = getDateString(ts, dateDelimiter);
|
||||
if (dateTimeDelimiter != '\0')
|
||||
ret += dateTimeDelimiter;
|
||||
ret += getTimeString(ts, timeDelimiter);
|
||||
ret += getTimeString(ts, timeDelimiter, am_pm, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
String getDateTimeString(char dateDelimiter, char timeDelimiter, char dateTimeDelimiter) {
|
||||
return getDateTimeString(tm, dateDelimiter, timeDelimiter, dateTimeDelimiter);
|
||||
return getDateTimeString(tm, dateDelimiter, timeDelimiter, dateTimeDelimiter, false);
|
||||
}
|
||||
|
||||
String getDateTimeString_ampm(char dateDelimiter, char timeDelimiter, char dateTimeDelimiter) {
|
||||
return getDateTimeString(tm, dateDelimiter, timeDelimiter, dateTimeDelimiter, true);
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
Convert a string like "Sun,12:30" into a 32 bit integer
|
||||
\*********************************************************************************************/
|
||||
unsigned long string2TimeLong(String &str)
|
||||
unsigned long string2TimeLong(const String &str)
|
||||
{
|
||||
// format 0000WWWWAAAABBBBCCCCDDDD
|
||||
// WWWW=weekday, AAAA=hours tens digit, BBBB=hours, CCCC=minutes tens digit DDDD=minutes
|
||||
@@ -423,8 +470,12 @@ unsigned long string2TimeLong(String &str)
|
||||
char TmpStr1[10];
|
||||
int w, x, y;
|
||||
unsigned long a;
|
||||
str.toLowerCase();
|
||||
str.toCharArray(command, 20);
|
||||
{
|
||||
// Within a scope so the tmpString is only used for copy.
|
||||
String tmpString(str);
|
||||
tmpString.toLowerCase();
|
||||
tmpString.toCharArray(command, 20);
|
||||
}
|
||||
unsigned long lngTime = 0;
|
||||
|
||||
if (GetArgv(command, TmpStr1, 1))
|
||||
|
||||
@@ -97,7 +97,7 @@ void logTimeZoneInfo() {
|
||||
if (m_dstLoc != 0) {
|
||||
timeStruct tmp;
|
||||
breakTime(m_dstLoc, tmp);
|
||||
log += getDateTimeString(tmp, '-', ':', ' ');
|
||||
log += getDateTimeString(tmp, '-', ':', ' ', false);
|
||||
}
|
||||
log += F(" offset: ");
|
||||
log += m_dst.offset;
|
||||
@@ -108,7 +108,7 @@ void logTimeZoneInfo() {
|
||||
if (m_stdLoc != 0) {
|
||||
timeStruct tmp;
|
||||
breakTime(m_stdLoc, tmp);
|
||||
log += getDateTimeString(tmp, '-', ':', ' ');
|
||||
log += getDateTimeString(tmp, '-', ':', ' ', false);
|
||||
}
|
||||
log += F(" offset: ");
|
||||
log += m_std.offset;
|
||||
|
||||
+2036
-1368
File diff suppressed because it is too large
Load Diff
+270
-105
@@ -4,7 +4,7 @@
|
||||
String WifiGetAPssid()
|
||||
{
|
||||
String ssid(Settings.Name);
|
||||
ssid+=F("_");
|
||||
ssid+=F("-");
|
||||
ssid+=Settings.Unit;
|
||||
return (ssid);
|
||||
}
|
||||
@@ -27,7 +27,10 @@ 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
|
||||
WiFi.softAP(WifiGetAPssid().c_str(), SecuritySettings.WifiAPKey);
|
||||
|
||||
String softAPSSID=WifiGetAPssid();
|
||||
String pwd = SecuritySettings.WifiAPKey;
|
||||
WiFi.softAP(softAPSSID.c_str(),pwd.c_str());
|
||||
// We start in STA mode
|
||||
WifiAPMode(false);
|
||||
|
||||
@@ -75,10 +78,9 @@ void WifiAPMode(boolean state)
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Configure network and connect to Wifi SSID and SSID2
|
||||
// Set Wifi config
|
||||
//********************************************************************************
|
||||
boolean WifiConnect(byte connectAttempts)
|
||||
{
|
||||
bool prepareWiFi() {
|
||||
String log = "";
|
||||
char hostname[40];
|
||||
strncpy(hostname, WifiGetHostname().c_str(), sizeof(hostname));
|
||||
@@ -98,128 +100,284 @@ boolean WifiConnect(byte connectAttempts)
|
||||
IPAddress dns = Settings.DNS;
|
||||
WiFi.config(ip, gw, subnet, dns);
|
||||
}
|
||||
return selectValidWiFiSettings();
|
||||
}
|
||||
|
||||
//try to connect to one of the access points
|
||||
if (WifiConnectSSID(SecuritySettings.WifiSSID, SecuritySettings.WifiKey, connectAttempts) ||
|
||||
WifiConnectSSID(SecuritySettings.WifiSSID2, SecuritySettings.WifiKey2, connectAttempts))
|
||||
{
|
||||
// fix octet?
|
||||
if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255)
|
||||
{
|
||||
IPAddress ip = WiFi.localIP();
|
||||
IPAddress gw = WiFi.gatewayIP();
|
||||
IPAddress subnet = WiFi.subnetMask();
|
||||
ip[3] = Settings.IP_Octet;
|
||||
log = F("IP : Fixed IP octet:");
|
||||
log += ip;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
WiFi.config(ip, gw, subnet);
|
||||
//********************************************************************************
|
||||
// Configure network and connect to Wifi SSID and SSID2
|
||||
//********************************************************************************
|
||||
boolean WifiConnect(byte connectAttempts)
|
||||
{
|
||||
if (prepareWiFi()) {
|
||||
//try to connect to one of the access points
|
||||
bool connected = WifiConnectAndWait(connectAttempts);
|
||||
if (!connected) {
|
||||
if (selectNextWiFiSettings()) {
|
||||
connected = WifiConnectAndWait(connectAttempts);
|
||||
}
|
||||
}
|
||||
if (connected) {
|
||||
return(true);
|
||||
}
|
||||
|
||||
#ifdef FEATURE_MDNS
|
||||
|
||||
String log = F("WIFI : ");
|
||||
if (MDNS.begin(WifiGetHostname().c_str(), WiFi.localIP())) {
|
||||
|
||||
log += F("mDNS started, with name: ");
|
||||
log += WifiGetHostname();
|
||||
log += F(".local");
|
||||
}
|
||||
else{
|
||||
log += F("mDNS failed");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
#endif
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP!"));
|
||||
|
||||
//everything failed, activate AP mode (will deactivate automaticly after a while if its connected again)
|
||||
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
|
||||
WifiAPMode(true);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Start connect to WiFi and check later to see if connected.
|
||||
//********************************************************************************
|
||||
void WiFiConnectRelaxed() {
|
||||
wifiConnected = false;
|
||||
wifi_connect_attempt = 0;
|
||||
if (prepareWiFi()) {
|
||||
tryConnectWiFi();
|
||||
return;
|
||||
}
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP, no valid WiFi settings!"));
|
||||
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
|
||||
WifiAPMode(true);
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Manage WiFi credentials
|
||||
//********************************************************************************
|
||||
const char* getLastWiFiSettingsSSID() {
|
||||
return lastWiFiSettings == 0 ? SecuritySettings.WifiSSID : SecuritySettings.WifiSSID2;
|
||||
}
|
||||
|
||||
const char* getLastWiFiSettingsPassphrase() {
|
||||
return lastWiFiSettings == 0 ? SecuritySettings.WifiKey : SecuritySettings.WifiKey2;
|
||||
}
|
||||
|
||||
bool anyValidWifiSettings() {
|
||||
if (wifiSettingsValid(SecuritySettings.WifiSSID, SecuritySettings.WifiKey))
|
||||
return true;
|
||||
if (wifiSettingsValid(SecuritySettings.WifiSSID2, SecuritySettings.WifiKey2))
|
||||
return true;
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : No valid WiFi settings!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool selectNextWiFiSettings() {
|
||||
uint8_t tmp = lastWiFiSettings;
|
||||
lastWiFiSettings = (lastWiFiSettings + 1) % 2;
|
||||
if (!wifiSettingsValid(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase())) {
|
||||
// other settings are not correct, switch back.
|
||||
lastWiFiSettings = tmp;
|
||||
return false; // Nothing changed.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool selectValidWiFiSettings() {
|
||||
if (wifiSettingsValid(getLastWiFiSettingsSSID(), getLastWiFiSettingsPassphrase()))
|
||||
return true;
|
||||
return selectNextWiFiSettings();
|
||||
}
|
||||
|
||||
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 (strlen(ssid) > 32) return false;
|
||||
if (strlen(pass) > 64) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wifiConnectTimeoutReached() {
|
||||
if (wifi_connect_attempt == 0) return true;
|
||||
if (wifiSetupConnect) {
|
||||
// Initial setup of WiFi, may take much longer since accesspoint is still active.
|
||||
return timeOutReached(wifi_connect_timer + 20000);
|
||||
}
|
||||
// wait until it connects + add some device specific random offset to prevent
|
||||
// all nodes overloading the accesspoint when turning on at the same time.
|
||||
const unsigned int randomOffset_in_sec = wifi_connect_attempt == 1 ? 0 : 1000 * ((ESP.getChipId() & 0xF));
|
||||
return timeOutReached(wifi_connect_timer + DEFAULT_WIFI_CONNECTION_TIMEOUT + randomOffset_in_sec);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Simply start the WiFi connection sequence
|
||||
//********************************************************************************
|
||||
bool tryConnectWiFi() {
|
||||
if (wifiSetup && !wifiSetupConnect)
|
||||
return false;
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
return(true); //already connected, need to disconnect first
|
||||
if (!wifiConnectTimeoutReached())
|
||||
return true; // timeout not reached yet, thus no need to retry again.
|
||||
if (!anyValidWifiSettings())
|
||||
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 > 6) {
|
||||
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
|
||||
WifiAPMode(true);
|
||||
}
|
||||
String ssid;
|
||||
ssid.reserve(32);
|
||||
String passphrase;
|
||||
passphrase.reserve(64);
|
||||
ssid = getLastWiFiSettingsSSID();
|
||||
passphrase = getLastWiFiSettingsPassphrase();
|
||||
String log = F("WIFI : Connecting ");
|
||||
log += ssid;
|
||||
log += F(" attempt #");
|
||||
log += wifi_connect_attempt;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
wifi_connect_timer = millis();
|
||||
switch (wifi_connect_attempt) {
|
||||
case 0:
|
||||
if (lastBSSID[0] == 0)
|
||||
WiFi.begin(ssid.c_str(), passphrase.c_str());
|
||||
else
|
||||
WiFi.begin(ssid.c_str(), passphrase.c_str(), 0, &lastBSSID[0]);
|
||||
break;
|
||||
default:
|
||||
WiFi.begin(ssid.c_str(), passphrase.c_str());
|
||||
}
|
||||
++wifi_connect_attempt;
|
||||
switch (WiFi.status()) {
|
||||
case WL_NO_SSID_AVAIL: {
|
||||
log = F("WIFI : No SSID found matching: ");
|
||||
log += ssid;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
return false;
|
||||
}
|
||||
case WL_CONNECT_FAILED: {
|
||||
log = F("WIFI : Connection failed to: ");
|
||||
log += ssid;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
return false;
|
||||
}
|
||||
case WL_CONNECTED:
|
||||
checkWifiJustConnected();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true; // Sent
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Connect to Wifi specific SSID
|
||||
//********************************************************************************
|
||||
boolean WifiConnectSSID(char WifiSSID[], char WifiKey[], byte connectAttempts)
|
||||
boolean WifiConnectAndWait(byte connectAttempts)
|
||||
{
|
||||
String log;
|
||||
|
||||
//already connected, need to disconnect first
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
return(true);
|
||||
|
||||
//no ssid specified
|
||||
if ((WifiSSID[0] == 0) || (strcasecmp(WifiSSID, "ssid") == 0))
|
||||
return(false);
|
||||
|
||||
for (byte tryConnect = 1; tryConnect <= connectAttempts; tryConnect++)
|
||||
wifiConnected = false;
|
||||
wifi_connect_attempt = 0;
|
||||
for (byte tryConnect = 0; tryConnect < connectAttempts; tryConnect++)
|
||||
{
|
||||
log = F("WIFI : Connecting ");
|
||||
log += WifiSSID;
|
||||
log += F(" attempt #");
|
||||
log += tryConnect;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
if (tryConnect == 1)
|
||||
WiFi.begin(WifiSSID, WifiKey);
|
||||
else
|
||||
WiFi.begin();
|
||||
|
||||
//wait until it connects
|
||||
for (byte x = 0; x < 200; x++)
|
||||
{
|
||||
if (!WiFiConnected(50))
|
||||
{
|
||||
statusLED(false);
|
||||
// No delay needed, since the WiFi check has a delay
|
||||
}
|
||||
else
|
||||
break;
|
||||
if (tryConnectWiFi()) {
|
||||
do {
|
||||
if (checkWifiJustConnected())
|
||||
return true;
|
||||
delay(50);
|
||||
} while (!wifiConnectTimeoutReached());
|
||||
}
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
{
|
||||
if (Settings.UseNTP) {
|
||||
initTime();
|
||||
}
|
||||
log = F("WIFI : Connected! IP: ");
|
||||
IPAddress ip = WiFi.localIP();
|
||||
char str[20];
|
||||
sprintf_P(str, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
log += str;
|
||||
log += F(" (");
|
||||
log += WifiGetHostname();
|
||||
log += F(")");
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
statusLED(true);
|
||||
return(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// log = F("WIFI : Disconnecting!");
|
||||
// addLog(LOG_LEVEL_INFO, log);
|
||||
// log = F("WIFI : Disconnecting!");
|
||||
// addLog(LOG_LEVEL_INFO, log);
|
||||
#if defined(ESP8266)
|
||||
ETS_UART_INTR_DISABLE();
|
||||
wifi_station_disconnect();
|
||||
ETS_UART_INTR_ENABLE();
|
||||
for (byte x = 0; x < 20; x++)
|
||||
{
|
||||
statusLED(true);
|
||||
delay(50);
|
||||
}
|
||||
#endif
|
||||
for (byte x = 0; x < 20; x++)
|
||||
{
|
||||
statusLED(true);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool checkWifiJustConnected() {
|
||||
if (wifiConnected) return true;
|
||||
delay(1);
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
statusLED(false);
|
||||
return false;
|
||||
}
|
||||
wifiConnected = true;
|
||||
String log = F("WIFI : WiFi connect attempt took: ");
|
||||
log += timePassedSince(wifi_connect_timer);
|
||||
log += F(" ms");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
// fix octet?
|
||||
if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255)
|
||||
{
|
||||
IPAddress ip = WiFi.localIP();
|
||||
IPAddress gw = WiFi.gatewayIP();
|
||||
IPAddress subnet = WiFi.subnetMask();
|
||||
ip[3] = Settings.IP_Octet;
|
||||
log = F("IP : Fixed IP octet:");
|
||||
log += ip;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
WiFi.config(ip, gw, subnet);
|
||||
}
|
||||
|
||||
#ifdef FEATURE_MDNS
|
||||
|
||||
String log = F("WIFI : ");
|
||||
if (MDNS.begin(WifiGetHostname().c_str(), WiFi.localIP())) {
|
||||
|
||||
log += F("mDNS started, with name: ");
|
||||
log += WifiGetHostname();
|
||||
log += F(".local");
|
||||
}
|
||||
else{
|
||||
log += F("mDNS failed");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
#endif
|
||||
|
||||
// First try to get the time, since that may be used in logs
|
||||
if (Settings.UseNTP) {
|
||||
initTime();
|
||||
}
|
||||
uint8_t* curBSSID = WiFi.BSSID();
|
||||
bool changed = false;
|
||||
for (byte i=0; i < 6; ++i) {
|
||||
if (lastBSSID[i] != *(curBSSID + i)) {
|
||||
changed = true;
|
||||
lastBSSID[i] = *(curBSSID + i);
|
||||
}
|
||||
}
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
if (changed) {
|
||||
String event = F("WiFi#ChangedAccesspoint");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
String event = F("WiFi#Connected");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
log = F("WIFI : Connected! IP: ");
|
||||
log += formatIP(WiFi.localIP());
|
||||
log += F(" (");
|
||||
log += WifiGetHostname();
|
||||
log += F(") AP: ");
|
||||
log += WiFi.SSID();
|
||||
log += F(" AP BSSID: ");
|
||||
log += WiFi.BSSIDstr();
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
statusLED(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Disconnect from Wifi AP
|
||||
@@ -227,6 +385,7 @@ boolean WifiConnectSSID(char WifiSSID[], char WifiKey[], byte connectAttempts)
|
||||
void WifiDisconnect()
|
||||
{
|
||||
WiFi.disconnect();
|
||||
wifiConnected = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -268,7 +427,6 @@ void WifiScan()
|
||||
//********************************************************************************
|
||||
void WifiCheck()
|
||||
{
|
||||
|
||||
if(wifiSetup)
|
||||
return;
|
||||
|
||||
@@ -278,8 +436,11 @@ void WifiCheck()
|
||||
//give it time to automaticly reconnect
|
||||
if (NC_Count > 2)
|
||||
{
|
||||
WifiConnect(2);
|
||||
|
||||
if (wifiConnected) {
|
||||
wifi_connect_attempt = 0;
|
||||
wifiConnected = false;
|
||||
WiFiConnectRelaxed();
|
||||
}
|
||||
C_Count=0;
|
||||
NC_Count = 0;
|
||||
}
|
||||
@@ -294,4 +455,8 @@ void WifiCheck()
|
||||
WifiAPMode(false);
|
||||
}
|
||||
}
|
||||
if (!wifiConnected) {
|
||||
if (tryConnectWiFi())
|
||||
checkWifiJustConnected();
|
||||
}
|
||||
}
|
||||
|
||||
+25
-88
@@ -75,64 +75,6 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
switch (event->sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
break;
|
||||
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
|
||||
url += F("&svalue=");
|
||||
url += (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
break;
|
||||
case SENSOR_TYPE_DUAL: // any sensor that uses two simple values
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
url += (";");
|
||||
url += formatUserVar(event, 1);
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 1);
|
||||
url += F(";");
|
||||
url += humStat(UserVar[event->BaseVarIndex + 1]);
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
url += F(";0;0;");
|
||||
url += formatUserVar(event, 1);
|
||||
url += F(";0");
|
||||
break;
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 1);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 2);
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 1);
|
||||
url += F(";");
|
||||
url += humStat(UserVar[event->BaseVarIndex + 1]);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 2);
|
||||
url += F(";0");
|
||||
break;
|
||||
case SENSOR_TYPE_QUAD:
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 1);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 2);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 3);
|
||||
break;
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
url = F("/json.htm?type=command¶m=switchlight&idx=");
|
||||
url += event->idx;
|
||||
@@ -146,28 +88,39 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
url = F("/json.htm?type=command¶m=switchlight&idx=");
|
||||
url += event->idx;
|
||||
url += F("&switchcmd=");
|
||||
if (UserVar[event->BaseVarIndex] == 0)
|
||||
if (UserVar[event->BaseVarIndex] == 0) {
|
||||
url += ("Off");
|
||||
else
|
||||
{
|
||||
} else {
|
||||
url += F("Set%20Level&level=");
|
||||
url += UserVar[event->BaseVarIndex];
|
||||
}
|
||||
break;
|
||||
case (SENSOR_TYPE_WIND):
|
||||
url += F("&svalue="); // WindDir in degrees; WindDir as text; Wind speed average ; Wind speed gust; 0
|
||||
url += formatUserVar(event, 0);
|
||||
url += ";";
|
||||
url += getBearing(UserVar[event->BaseVarIndex]);
|
||||
url += ";";
|
||||
// Domoticz expects the wind speed in (m/s * 10)
|
||||
url += toString((UserVar[event->BaseVarIndex + 1] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[1]);
|
||||
url += ";";
|
||||
url += toString((UserVar[event->BaseVarIndex + 2] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[2]);
|
||||
url += ";0;0";
|
||||
|
||||
case SENSOR_TYPE_SINGLE:
|
||||
case SENSOR_TYPE_LONG:
|
||||
case SENSOR_TYPE_DUAL:
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
case SENSOR_TYPE_QUAD:
|
||||
case SENSOR_TYPE_TEMP_HUM:
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO:
|
||||
case SENSOR_TYPE_WIND:
|
||||
default:
|
||||
url = F("/json.htm?type=command¶m=udevice&idx=");
|
||||
url += event->idx;
|
||||
url += F("&nvalue=0");
|
||||
url += F("&svalue=");
|
||||
url += formatDomoticzSensorType(event);
|
||||
break;
|
||||
}
|
||||
|
||||
// Add WiFi reception quality
|
||||
url += F("&rssi=");
|
||||
url += mapRSSItoDomoticz();
|
||||
#if FEATURE_ADC_VCC
|
||||
url += F("&battery=");
|
||||
url += mapVccToDomoticz();
|
||||
#endif
|
||||
|
||||
// This will send the request to the server
|
||||
String request = F("GET ");
|
||||
@@ -211,19 +164,3 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
int humStat(int hum){
|
||||
int lHumStat;
|
||||
if(hum<30){
|
||||
lHumStat = 2;
|
||||
}else if(hum<40){
|
||||
lHumStat = 0;
|
||||
}else if(hum<59){
|
||||
lHumStat = 1;
|
||||
}else{
|
||||
lHumStat = 3;
|
||||
|
||||
}
|
||||
return lHumStat;
|
||||
}
|
||||
|
||||
+21
-105
@@ -135,104 +135,23 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
if (event->idx != 0)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
if (!ControllerSettings.checkHostReachable(true)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
|
||||
StaticJsonBuffer<200> jsonBuffer;
|
||||
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
|
||||
root[F("idx")] = event->idx;
|
||||
|
||||
String values;
|
||||
// char str[80];
|
||||
root[F("RSSI")] = mapRSSItoDomoticz();
|
||||
#if FEATURE_ADC_VCC
|
||||
root[F("Battery")] = mapVccToDomoticz();
|
||||
#endif
|
||||
|
||||
switch (event->sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
|
||||
root[F("nvalue")] = 0;
|
||||
values = formatUserVar(event, 0);
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
break;
|
||||
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
|
||||
root[F("nvalue")] = 0;
|
||||
values = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
break;
|
||||
case SENSOR_TYPE_DUAL: // any sensor that uses two simple values
|
||||
root[F("nvalue")] = 0;
|
||||
values = formatUserVar(event, 0);
|
||||
values += ";";
|
||||
values += formatUserVar(event, 1);
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_TRIPLE: // any sensor that uses three simple values
|
||||
root[F("nvalue")] = 0;
|
||||
values = formatUserVar(event, 0);
|
||||
values += ";";
|
||||
values += formatUserVar(event, 1);
|
||||
values += ";";
|
||||
values += formatUserVar(event, 2);
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11
|
||||
root[F("nvalue")] = 0;
|
||||
values = formatUserVar(event, 0);
|
||||
values += ";";
|
||||
values += formatUserVar(event, 1);
|
||||
//FIXME: this should be the same as in C001?, instead of 0:
|
||||
// url += humStat(UserVar[event->BaseVarIndex + 1]);
|
||||
values += ";0";
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085
|
||||
root[F("nvalue")] = 0;
|
||||
values = formatUserVar(event, 0);
|
||||
values += ";0;0;";
|
||||
values += formatUserVar(event, 1);
|
||||
values += ";0";
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280
|
||||
root[F("nvalue")] = 0;
|
||||
values = formatUserVar(event, 0);
|
||||
values += ";";
|
||||
values += formatUserVar(event, 1);
|
||||
values += ";0;";
|
||||
values += formatUserVar(event, 2);
|
||||
values += ";0";
|
||||
root[F("svalue")] = values.c_str();
|
||||
// values.toCharArray(str, 80);
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_QUAD:
|
||||
root[F("nvalue")] = 0;
|
||||
values = formatUserVar(event, 0);
|
||||
values += ";";
|
||||
values += formatUserVar(event, 1);
|
||||
values += ";";
|
||||
values += formatUserVar(event, 2);
|
||||
values += ";";
|
||||
values += formatUserVar(event, 3);
|
||||
root[F("svalue")] = values.c_str();
|
||||
// values.toCharArray(str, 80);
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
root[F("command")] = String(F("switchlight"));
|
||||
if (UserVar[event->BaseVarIndex] == 0)
|
||||
@@ -247,22 +166,20 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
else
|
||||
root[F("Set%20Level")] = UserVar[event->BaseVarIndex];
|
||||
break;
|
||||
case SENSOR_TYPE_WIND: // WindDir in degrees; WindDir as text; Wind speed average ; Wind speed gust
|
||||
values = formatUserVar(event, 0);
|
||||
values += ";";
|
||||
values += getBearing(UserVar[event->BaseVarIndex]);
|
||||
values += ";";
|
||||
// Domoticz expects the wind speed in (m/s * 10)
|
||||
values += toString((UserVar[event->BaseVarIndex + 1] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[1]);
|
||||
values += ";";
|
||||
values += toString((UserVar[event->BaseVarIndex + 2] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[2]);
|
||||
values += ";0;0";
|
||||
root[F("svalue")] = values.c_str();
|
||||
// values.toCharArray(str, 80);
|
||||
// root["svalue"] = str;
|
||||
|
||||
case SENSOR_TYPE_SINGLE:
|
||||
case SENSOR_TYPE_LONG:
|
||||
case SENSOR_TYPE_DUAL:
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
case SENSOR_TYPE_QUAD:
|
||||
case SENSOR_TYPE_TEMP_HUM:
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO:
|
||||
case SENSOR_TYPE_WIND:
|
||||
default:
|
||||
root[F("nvalue")] = 0;
|
||||
root[F("svalue")] = formatDomoticzSensorType(event);
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
String json;
|
||||
@@ -272,8 +189,7 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
String pubname = ControllerSettings.Publish;
|
||||
parseSystemVariables(pubname, false);
|
||||
parseEventVariables(pubname, event, false);
|
||||
parseControllerVariables(pubname, event, false);
|
||||
if (!MQTTpublish(event->ControllerIndex, pubname.c_str(), json.c_str(), Settings.MQTTRetainFlag))
|
||||
{
|
||||
connectionFailures++;
|
||||
|
||||
+27
-34
@@ -44,44 +44,38 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
|
||||
// Controller is not enabled.
|
||||
break;
|
||||
} else {
|
||||
// Split topic into array
|
||||
String tmpTopic = event->String1.substring(1);
|
||||
String topicSplit[10];
|
||||
int SlashIndex = tmpTopic.indexOf('/');
|
||||
byte count = 0;
|
||||
while (SlashIndex > 0 && (count < (10 - 1)))
|
||||
{
|
||||
topicSplit[count] = tmpTopic.substring(0, SlashIndex);
|
||||
tmpTopic = tmpTopic.substring(SlashIndex + 1);
|
||||
SlashIndex = tmpTopic.indexOf('/');
|
||||
count++;
|
||||
}
|
||||
topicSplit[count] = tmpTopic;
|
||||
|
||||
String cmd = "";
|
||||
String cmd;
|
||||
struct EventStruct TempEvent;
|
||||
|
||||
if (topicSplit[count] == F("cmd"))
|
||||
{
|
||||
bool validTopic = false;
|
||||
const int lastindex = event->String1.lastIndexOf('/');
|
||||
const String lastPartTopic = event->String1.substring(lastindex + 1);
|
||||
if (lastPartTopic == F("cmd")) {
|
||||
cmd = event->String2;
|
||||
parseCommandString(&TempEvent, cmd);
|
||||
TempEvent.Source = VALUE_SOURCE_MQTT;
|
||||
validTopic = true;
|
||||
} else {
|
||||
if (lastindex > 0) {
|
||||
// Topic has at least one separator
|
||||
if (isFloat(event->String2) && isInt(lastPartTopic)) {
|
||||
int prevLastindex = event->String1.lastIndexOf('/', lastindex - 1);
|
||||
cmd = event->String1.substring(prevLastindex + 1, lastindex);
|
||||
TempEvent.Par1 = lastPartTopic.toInt();
|
||||
TempEvent.Par2 = event->String2.toFloat();
|
||||
TempEvent.Par3 = 0;
|
||||
validTopic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = topicSplit[count - 1];
|
||||
TempEvent.Par1 = topicSplit[count].toInt();
|
||||
TempEvent.Par2 = event->String2.toFloat();
|
||||
TempEvent.Par3 = 0;
|
||||
}
|
||||
// in case of event, store to buffer and return...
|
||||
String command = parseString(cmd, 1);
|
||||
if (command == F("event"))
|
||||
if (validTopic) {
|
||||
// in case of event, store to buffer and return...
|
||||
String command = parseString(cmd, 1);
|
||||
if (command == F("event")) {
|
||||
eventBuffer = cmd.substring(6);
|
||||
else if
|
||||
(PluginCall(PLUGIN_WRITE, &TempEvent, cmd));
|
||||
else
|
||||
remoteConfig(&TempEvent, cmd);
|
||||
} else if (!PluginCall(PLUGIN_WRITE, &TempEvent, cmd)) {
|
||||
remoteConfig(&TempEvent, cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -101,8 +95,7 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
String pubname = ControllerSettings.Publish;
|
||||
parseSystemVariables(pubname, false);
|
||||
parseEventVariables(pubname, event, false);
|
||||
parseControllerVariables(pubname, event, false);
|
||||
|
||||
String value = "";
|
||||
// byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]);
|
||||
|
||||
+1
-2
@@ -89,8 +89,7 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
String pubname = ControllerSettings.Publish;
|
||||
parseSystemVariables(pubname, false);
|
||||
parseEventVariables(pubname, event, false);
|
||||
parseControllerVariables(pubname, event, false);
|
||||
|
||||
String value = "";
|
||||
// byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]);
|
||||
|
||||
+13
-39
@@ -35,6 +35,12 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
const byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
if (valueCount == 0 || valueCount > 3) {
|
||||
addLog(LOG_LEVEL_ERROR, F("emoncms : Unknown sensortype or too many sensor values"));
|
||||
break;
|
||||
}
|
||||
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
|
||||
@@ -59,46 +65,14 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
|
||||
postDataStr += Settings.Unit;
|
||||
postDataStr += F("&json=");
|
||||
|
||||
switch (event->sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
|
||||
case SENSOR_TYPE_SWITCH: // report switch state
|
||||
postDataStr += F("{field");
|
||||
postDataStr += event->idx;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, 0);
|
||||
postDataStr += "}";
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM: // dual value
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
case SENSOR_TYPE_DUAL:
|
||||
postDataStr += F("{field");
|
||||
postDataStr += event->idx;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, 0);
|
||||
postDataStr += F(",field");
|
||||
postDataStr += event->idx + 1;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, 1);
|
||||
postDataStr += "}";
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO:
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
postDataStr += F("{field");
|
||||
postDataStr += event->idx;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, 0);
|
||||
postDataStr += F(",field");
|
||||
postDataStr += event->idx + 1;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, 1);
|
||||
postDataStr += F(",field");
|
||||
postDataStr += event->idx + 2;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, 2);
|
||||
postDataStr += "}";
|
||||
break;
|
||||
for (byte i = 0; i < valueCount; ++i) {
|
||||
postDataStr += (i == 0) ? F("{") : F(",");
|
||||
postDataStr += F("field");
|
||||
postDataStr += event->idx + i;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, i);
|
||||
}
|
||||
postDataStr += "}";
|
||||
postDataStr += F("&apikey=");
|
||||
postDataStr += SecuritySettings.ControllerPassword[event->ControllerIndex]; // "0UDNN17RW6XAS2E5" // api key
|
||||
|
||||
|
||||
+1
-2
@@ -105,8 +105,7 @@ boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned
|
||||
|
||||
String url = "/";
|
||||
url += ControllerSettings.Publish;
|
||||
parseSystemVariables(url, true);
|
||||
parseEventVariables(url, event, true);
|
||||
parseControllerVariables(url, event, true);
|
||||
|
||||
url.replace(F("%valname%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex]));
|
||||
if (longValue)
|
||||
|
||||
+1
-5
@@ -80,11 +80,7 @@ void C010_Send(struct EventStruct *event, byte varIndex, float value, unsigned l
|
||||
|
||||
String msg = "";
|
||||
msg += ControllerSettings.Publish;
|
||||
parseSystemVariables(msg, false);
|
||||
parseEventVariables(msg, event, false);
|
||||
msg.replace(F("%sysname%"), Settings.Name);
|
||||
msg.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName);
|
||||
msg.replace(F("%id%"), String(event->idx));
|
||||
parseControllerVariables(msg, event, false);
|
||||
msg.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[varIndex]);
|
||||
if (longValue)
|
||||
msg.replace(F("%value%"), String(longValue));
|
||||
|
||||
+3
-34
@@ -270,44 +270,13 @@ void ReplaceTokenByValue(String& s, struct EventStruct *event)
|
||||
// %1%%vname1%,Standort=%tskname% Wert=%val1%%/1%%2%%LF%%vname2%,Standort=%tskname% Wert=%val2%%/2%%3%%LF%%vname3%,Standort=%tskname% Wert=%val3%%/3%%4%%LF%%vname4%,Standort=%tskname% Wert=%val4%%/4%
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP before parsing: "));
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, s);
|
||||
|
||||
switch (event->sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE:
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
case SENSOR_TYPE_DIMMER:
|
||||
case SENSOR_TYPE_WIND:
|
||||
case SENSOR_TYPE_LONG:
|
||||
{
|
||||
DeleteNotNeededValues(s,1);
|
||||
break;
|
||||
}
|
||||
case SENSOR_TYPE_DUAL:
|
||||
case SENSOR_TYPE_TEMP_HUM:
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
{
|
||||
DeleteNotNeededValues(s,2);
|
||||
break;
|
||||
}
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO:
|
||||
{
|
||||
DeleteNotNeededValues(s,3);
|
||||
break;
|
||||
}
|
||||
case SENSOR_TYPE_QUAD:
|
||||
{
|
||||
DeleteNotNeededValues(s,4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
const byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
DeleteNotNeededValues(s,valueCount);
|
||||
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP after parsing: "));
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, s);
|
||||
|
||||
//NOTE: cant we just call parseTemplate() for all the standard stuff??
|
||||
parseSystemVariables(s, true);
|
||||
parseEventVariables(s, event, true);
|
||||
parseControllerVariables(s, event, true);
|
||||
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP after replacements: "));
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, s);
|
||||
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 012: Blynk #############################################
|
||||
//#######################################################################################################
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define CPLUGIN_012
|
||||
#define CPLUGIN_ID_012 12
|
||||
#define CPLUGIN_NAME_012 "Blynk HTTP [TESTING]"
|
||||
|
||||
boolean CPlugin_012(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case CPLUGIN_PROTOCOL_ADD:
|
||||
{
|
||||
Protocol[++protocolCount].Number = CPLUGIN_ID_012;
|
||||
Protocol[protocolCount].usesMQTT = false;
|
||||
Protocol[protocolCount].usesAccount = false;
|
||||
Protocol[protocolCount].usesPassword = true;
|
||||
Protocol[protocolCount].defaultPort = 80;
|
||||
Protocol[protocolCount].usesID = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(CPLUGIN_NAME_012);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
String postDataStr = F("");
|
||||
const byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
success = CPlugin_012_send(event, valueCount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
boolean CPlugin_012_send(struct EventStruct *event, int nrValues) {
|
||||
String postDataStr = F("");
|
||||
boolean success = true;
|
||||
for (int i = 0; i < nrValues && success; ++i) {
|
||||
postDataStr = F("update/V") ;
|
||||
postDataStr += event->idx + i;
|
||||
postDataStr += F("?value=");
|
||||
postDataStr += formatUserVar(event, i);
|
||||
success = Blynk_get(postDataStr, event->ControllerIndex);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
boolean Blynk_get(const String& command, byte controllerIndex, float *data )
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(controllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
// Use WiFiClient class to create TCP connections
|
||||
WiFiClient client;
|
||||
if ((SecuritySettings.ControllerPassword[controllerIndex][0] == 0) || !ControllerSettings.connectToHost(client))
|
||||
{
|
||||
connectionFailures++;
|
||||
addLog(LOG_LEVEL_ERROR, F("Blynk : connection failed"));
|
||||
return false;
|
||||
}
|
||||
if (connectionFailures)
|
||||
connectionFailures--;
|
||||
|
||||
// We now create a URI for the request
|
||||
char request[300] = {0};
|
||||
sprintf_P(request,
|
||||
PSTR("GET /%s/%s HTTP/1.1\r\n Host: %s \r\n Connection: close\r\n\r\n"),
|
||||
SecuritySettings.ControllerPassword[controllerIndex],
|
||||
command.c_str(),
|
||||
ControllerSettings.getHost().c_str());
|
||||
addLog(LOG_LEVEL_DEBUG, request);
|
||||
client.print(request);
|
||||
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client.available() && !timeOutReached(timer))
|
||||
yield();
|
||||
|
||||
boolean success = false;
|
||||
char log[80] = {0};
|
||||
|
||||
// Read all the lines of the reply from server and log them
|
||||
while (client.available()) {
|
||||
String line;
|
||||
safeReadStringUntil(client, line, '\n');
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, line);
|
||||
// success ?
|
||||
if (line.substring(0, 15) == "HTTP/1.1 200 OK") {
|
||||
strcpy_P(log, PSTR("HTTP : Success"));
|
||||
success = true;
|
||||
}
|
||||
else if (line.substring(0, 24) == "HTTP/1.1 400 Bad Request") {
|
||||
strcpy_P(log, PSTR("HTTP : Unauthorized"));
|
||||
}
|
||||
else if (line.substring(0, 25) == "HTTP/1.1 401 Unauthorized") {
|
||||
strcpy_P(log, PSTR("HTTP : Unauthorized"));
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
// data only
|
||||
if (data && line.startsWith("["))
|
||||
{
|
||||
String strValue = line;
|
||||
byte pos = strValue.indexOf('"',2);
|
||||
strValue = strValue.substring(2, pos);
|
||||
strValue.trim();
|
||||
float value = strValue.toFloat();
|
||||
*data = value;
|
||||
success = true;
|
||||
|
||||
char value_char[5] = {0};
|
||||
strValue.toCharArray(value_char, 5);
|
||||
sprintf_P(log, PSTR("Blynk get - %s => %s"),command.c_str(), value_char );
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
}
|
||||
yield();
|
||||
}
|
||||
strcpy_P(log, PSTR("HTTP : closing connection"));
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
client.flush();
|
||||
client.stop();
|
||||
|
||||
// important - backgroudtasks - free mem
|
||||
timer = millis() + Settings.MessageDelay;
|
||||
while (!timeOutReached(timer))
|
||||
backgroundtasks();
|
||||
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 013: ESPEasy P2P network ################################
|
||||
//#######################################################################################################
|
||||
|
||||
#define CPLUGIN_013
|
||||
#define CPLUGIN_ID_013 13
|
||||
#define CPLUGIN_NAME_013 "ESPEasy P2P Networking"
|
||||
|
||||
WiFiUDP C013_portUDP;
|
||||
|
||||
struct infoStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 3;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
byte deviceNumber;
|
||||
char taskName[26];
|
||||
char ValueNames[VARS_PER_TASK][26];
|
||||
};
|
||||
|
||||
struct dataStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 5;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
float Values[VARS_PER_TASK];
|
||||
};
|
||||
|
||||
|
||||
boolean CPlugin_013(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case CPLUGIN_PROTOCOL_ADD:
|
||||
{
|
||||
Protocol[++protocolCount].Number = CPLUGIN_ID_013;
|
||||
Protocol[protocolCount].usesMQTT = false;
|
||||
Protocol[protocolCount].usesTemplate = false;
|
||||
Protocol[protocolCount].usesAccount = false;
|
||||
Protocol[protocolCount].usesPassword = false;
|
||||
Protocol[protocolCount].defaultPort = 65501;
|
||||
Protocol[protocolCount].usesID = false;
|
||||
Protocol[protocolCount].Custom = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(CPLUGIN_NAME_013);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_TEMPLATE:
|
||||
{
|
||||
event->String1 = "";
|
||||
event->String2 = "";
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_INIT:
|
||||
{
|
||||
//C013_portUDP.begin(Settings.UDPPort);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_TASK_CHANGE_NOTIFICATION:
|
||||
{
|
||||
C013_SendUDPTaskInfo(0, event->TaskIndex, event->TaskIndex);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
C013_Send(event, 0, UserVar[event->BaseVarIndex], 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_UDP_IN:
|
||||
{
|
||||
C013_Receive(event);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Generic UDP message
|
||||
//********************************************************************************
|
||||
void C013_Send(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
statusLED(true);
|
||||
C013_SendUDPTaskData(0, event->TaskIndex, event->TaskIndex);
|
||||
}
|
||||
|
||||
void C013_SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
struct infoStruct infoReply;
|
||||
infoReply.sourcelUnit = Settings.Unit;
|
||||
infoReply.sourceTaskIndex = sourceTaskIndex;
|
||||
infoReply.destTaskIndex = destTaskIndex;
|
||||
LoadTaskSettings(infoReply.sourceTaskIndex);
|
||||
infoReply.deviceNumber = Settings.TaskDeviceNumber[infoReply.sourceTaskIndex];
|
||||
strcpy(infoReply.taskName, ExtraTaskSettings.TaskDeviceName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x]);
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
if (x != Settings.Unit){
|
||||
infoReply.destUnit = x;
|
||||
C013_sendUDP(x, (byte*)&infoReply, sizeof(infoStruct));
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void C013_SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
struct dataStruct dataReply;
|
||||
dataReply.sourcelUnit = Settings.Unit;
|
||||
dataReply.sourceTaskIndex = sourceTaskIndex;
|
||||
dataReply.destTaskIndex = destTaskIndex;
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
dataReply.Values[x] = UserVar[dataReply.sourceTaskIndex * VARS_PER_TASK + x];
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
if (x != Settings.Unit){
|
||||
dataReply.destUnit = x;
|
||||
C013_sendUDP(x, (byte*) &dataReply, sizeof(dataStruct));
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send UDP message (unit 255=broadcast)
|
||||
\*********************************************************************************************/
|
||||
void C013_sendUDP(byte unit, byte* data, byte size)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
if (unit != 255)
|
||||
if (Nodes[unit].ip[0] == 0)
|
||||
return;
|
||||
String log = "C013 : Send UDP message to ";
|
||||
log += unit;
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
statusLED(true);
|
||||
|
||||
IPAddress remoteNodeIP;
|
||||
if (unit == 255)
|
||||
remoteNodeIP = {255, 255, 255, 255};
|
||||
else
|
||||
remoteNodeIP = Nodes[unit].ip;
|
||||
C013_portUDP.beginPacket(remoteNodeIP, Settings.UDPPort);
|
||||
C013_portUDP.write(data, size);
|
||||
C013_portUDP.endPacket();
|
||||
}
|
||||
|
||||
void C013_Receive(struct EventStruct *event) {
|
||||
|
||||
if (event->Data[1] > 1 && event->Data[1] < 6)
|
||||
{
|
||||
String log = (F("C013 : msg "));
|
||||
for (byte x = 1; x < 6; x++)
|
||||
{
|
||||
log += " ";
|
||||
log += (int)event->Data[x];
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
}
|
||||
|
||||
switch (event->Data[1]) {
|
||||
case 2: // sensor info pull request
|
||||
{
|
||||
//SendUDPTaskInfo(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: // sensor info
|
||||
{
|
||||
struct infoStruct infoReply;
|
||||
memcpy((byte*)&infoReply, (byte*)event->Data, sizeof(infoStruct));
|
||||
|
||||
// to prevent flash wear out (bugs in communication?) we can only write to an empty task
|
||||
// so it will write only once and has to be cleared manually through webgui
|
||||
if (Settings.TaskDeviceNumber[infoReply.destTaskIndex] == 0)
|
||||
{
|
||||
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
|
||||
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed
|
||||
for (byte x = 0; x < CONTROLLER_MAX; x++)
|
||||
Settings.TaskDeviceSendData[x][infoReply.destTaskIndex] = false;
|
||||
strcpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy( ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x]);
|
||||
SaveTaskSettings(infoReply.destTaskIndex);
|
||||
SaveSettings();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: // sensor data pull request
|
||||
{
|
||||
//SendUDPTaskData(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: // sensor data
|
||||
{
|
||||
struct dataStruct dataReply;
|
||||
memcpy((byte*)&dataReply, (byte*)event->Data, sizeof(dataStruct));
|
||||
|
||||
// only if this task has a remote feed, update values
|
||||
if (Settings.TaskDeviceDataFeed[dataReply.destTaskIndex] != 0)
|
||||
{
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
{
|
||||
UserVar[dataReply.destTaskIndex * VARS_PER_TASK + x] = dataReply.Values[x];
|
||||
}
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(dataReply.destTaskIndex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
// HUM_STAT can be one of:
|
||||
// 0=Normal
|
||||
// 1=Comfortable
|
||||
// 2=Dry
|
||||
// 3=Wet
|
||||
String humStatDomoticz(struct EventStruct *event, byte rel_index){
|
||||
const int hum = UserVar[event->BaseVarIndex + rel_index];
|
||||
if (hum < 30) { return formatUserVarDomoticz(2); }
|
||||
if (hum < 40) { return formatUserVarDomoticz(0); }
|
||||
if (hum < 59) { return formatUserVarDomoticz(1); }
|
||||
return formatUserVarDomoticz(3);
|
||||
}
|
||||
|
||||
int mapRSSItoDomoticz() {
|
||||
long rssi = WiFi.RSSI();
|
||||
if (-50 < rssi) { return 10; }
|
||||
if (rssi <= -98) { return 0; }
|
||||
rssi = rssi + 97; // Range 0..47 => 1..9
|
||||
return (rssi / 5) + 1;
|
||||
}
|
||||
|
||||
int mapVccToDomoticz() {
|
||||
#if FEATURE_ADC_VCC
|
||||
// Voltage range from 2.6V .. 3.6V => 0..100%
|
||||
if (vcc < 2.6) return 0;
|
||||
return (vcc - 2.6) * 100;
|
||||
#else
|
||||
return 255;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Format including trailing semi colon
|
||||
String formatUserVarDomoticz(struct EventStruct *event, byte rel_index) {
|
||||
String text = formatUserVar(event, rel_index);
|
||||
text += F(";");
|
||||
return text;
|
||||
}
|
||||
|
||||
String formatUserVarDomoticz(int value) {
|
||||
String text;
|
||||
text += value;
|
||||
text.trim();
|
||||
text += F(";");
|
||||
return text;
|
||||
}
|
||||
|
||||
String formatDomoticzSensorType(struct EventStruct *event) {
|
||||
String values;
|
||||
switch (event->sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
|
||||
values = formatUserVarDomoticz(event, 0);
|
||||
break;
|
||||
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
|
||||
values = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
break;
|
||||
case SENSOR_TYPE_DUAL: // any sensor that uses two simple values
|
||||
values = formatUserVarDomoticz(event, 0);
|
||||
values += formatUserVarDomoticz(event, 1);
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM:
|
||||
// temp + hum + hum_stat, used for DHT11
|
||||
// http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Temperature.2Fhumidity
|
||||
values = formatUserVarDomoticz(event, 0); // TEMP = Temperature
|
||||
values += formatUserVarDomoticz(event, 1); // HUM = Humidity
|
||||
values += humStatDomoticz(event, 1); // HUM_STAT = Humidity status
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO:
|
||||
// temp + hum + hum_stat + bar + bar_fore, used for BME280
|
||||
// http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Temperature.2Fhumidity.2Fbarometer
|
||||
values = formatUserVarDomoticz(event, 0); // TEMP = Temperature
|
||||
values += formatUserVarDomoticz(event, 1); // HUM = Humidity
|
||||
values += humStatDomoticz(event, 1); // HUM_STAT = Humidity status
|
||||
values += formatUserVarDomoticz(event, 2); // BAR = Barometric pressure
|
||||
values += formatUserVarDomoticz(0); // BAR_FOR = Barometer forecast
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
// temp + hum + hum_stat + bar + bar_fore, used for BMP085
|
||||
// http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Temperature.2Fbarometer
|
||||
values = formatUserVarDomoticz(event, 0); // TEMP = Temperature
|
||||
values += formatUserVarDomoticz(event, 1); // BAR = Barometric pressure
|
||||
values += formatUserVarDomoticz(0); // BAR_FOR = Barometer forecast
|
||||
values += formatUserVarDomoticz(0); // ALTITUDE= Not used at the moment, can be 0
|
||||
break;
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
values = formatUserVarDomoticz(event, 0);
|
||||
values += formatUserVarDomoticz(event, 1);
|
||||
values += formatUserVarDomoticz(event, 2);
|
||||
break;
|
||||
case SENSOR_TYPE_QUAD:
|
||||
values = formatUserVarDomoticz(event, 0);
|
||||
values += formatUserVarDomoticz(event, 1);
|
||||
values += formatUserVarDomoticz(event, 2);
|
||||
values += formatUserVarDomoticz(event, 3);
|
||||
break;
|
||||
case SENSOR_TYPE_WIND:
|
||||
// WindDir in degrees; WindDir as text; Wind speed average ; Wind speed gust; 0
|
||||
// http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Wind
|
||||
values = formatUserVarDomoticz(event, 0); // WB = Wind bearing (0-359)
|
||||
values += getBearing(UserVar[event->BaseVarIndex]); // WD = Wind direction (S, SW, NNW, etc.)
|
||||
values += ";"; // Needed after getBearing
|
||||
// Domoticz expects the wind speed in (m/s * 10)
|
||||
values += toString((UserVar[event->BaseVarIndex + 1] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[1]);
|
||||
values += ";"; // WS = 10 * Wind speed [m/s]
|
||||
values += toString((UserVar[event->BaseVarIndex + 2] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[2]);
|
||||
values += ";"; // WG = 10 * Gust [m/s]
|
||||
values += formatUserVarDomoticz(0); // Temperature
|
||||
values += formatUserVarDomoticz(0); // Temperature Windchill
|
||||
break;
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
case SENSOR_TYPE_DIMMER:
|
||||
// Too specific for HTTP/MQTT
|
||||
break;
|
||||
default:
|
||||
{
|
||||
String log = F("Domoticz Controller: Not yet implemented sensor type: ");
|
||||
log += event->sensorType;
|
||||
log += F(" idx: ");
|
||||
log += event->idx;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Now strip trailing semi colon.
|
||||
int index_last_char = values.length() -1;
|
||||
if (index_last_char > 0 && values.charAt(index_last_char) == ';') {
|
||||
values.setCharAt(index_last_char, ' ');
|
||||
}
|
||||
values.trim();
|
||||
{
|
||||
String log = F(" Domoticz: Sensortype: ");
|
||||
log += event->sensorType;
|
||||
log += F(" idx: ");
|
||||
log += event->idx;
|
||||
log += F(" values: ");
|
||||
log += values;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*********************************************************************************************\
|
||||
Get value count from sensor type
|
||||
\*********************************************************************************************/
|
||||
|
||||
byte getValueCountFromSensorType(byte sensorType)
|
||||
{
|
||||
switch (sensorType)
|
||||
{
|
||||
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)
|
||||
return 1;
|
||||
case SENSOR_TYPE_TEMP_HUM:
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
case SENSOR_TYPE_DUAL:
|
||||
return 2;
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO:
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
case SENSOR_TYPE_WIND:
|
||||
return 3;
|
||||
case SENSOR_TYPE_QUAD:
|
||||
return 4;
|
||||
}
|
||||
addLog(LOG_LEVEL_ERROR, F("getValueCountFromSensorType: Unknown sensortype"));
|
||||
return 0;
|
||||
}
|
||||
+99
-83
@@ -4,7 +4,7 @@
|
||||
|
||||
#define PLUGIN_005
|
||||
#define PLUGIN_ID_005 5
|
||||
#define PLUGIN_NAME_005 "Environment - DHT11/12/22"
|
||||
#define PLUGIN_NAME_005 "Environment - DHT11/12/22 SONOFF2301/7021"
|
||||
#define PLUGIN_VALUENAME1_005 "Temperature"
|
||||
#define PLUGIN_VALUENAME2_005 "Humidity"
|
||||
|
||||
@@ -47,10 +47,10 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
const String options[] = { F("DHT 11"), F("DHT 22"), F("DHT 12") };
|
||||
int indices[] = { 11, 22, 12 };
|
||||
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"), 3, options, indices, Settings.TaskDevicePluginConfig[event->TaskIndex][0] );
|
||||
addFormSelector(string, F("DHT Type"), F("plugin_005_dhttype"), 5, options, indices, Settings.TaskDevicePluginConfig[event->TaskIndex][0] );
|
||||
|
||||
success = true;
|
||||
break;
|
||||
@@ -67,96 +67,91 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
byte dht_dat[5];
|
||||
byte dht_in;
|
||||
byte i;
|
||||
// byte Retry = 0;
|
||||
boolean error = false;
|
||||
|
||||
byte Par3 = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
Plugin_005_DHT_Pin = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
|
||||
pinMode(Plugin_005_DHT_Pin, OUTPUT);
|
||||
// DHT start condition, pull-down i/o pin for 18ms
|
||||
digitalWrite(Plugin_005_DHT_Pin, LOW); // Pull low
|
||||
delay(18);
|
||||
digitalWrite(Plugin_005_DHT_Pin, HIGH); // Pull high
|
||||
delayMicroseconds(20); // was 40
|
||||
if(Par3 == 11 || Par3 == 22 || Par3 == 12) delay(18);
|
||||
else if (Par3 == 23 ) delayMicroseconds(900);
|
||||
else if (Par3 == 70 ) delayMicroseconds(500);
|
||||
pinMode(Plugin_005_DHT_Pin, INPUT); // change pin to input
|
||||
delayMicroseconds(10);
|
||||
delayMicroseconds(50);
|
||||
|
||||
dht_in = digitalRead(Plugin_005_DHT_Pin);
|
||||
if (!dht_in)
|
||||
error = waitState(0);
|
||||
if(error)
|
||||
{ logError(event, F("DHT : no Reading !"));
|
||||
break;
|
||||
}
|
||||
error = waitState(1);
|
||||
if(error)
|
||||
{ logError(event, F("DHT : no Reading !"));
|
||||
break;
|
||||
}
|
||||
noInterrupts();
|
||||
error = waitState(0);
|
||||
if(error)
|
||||
{ logError(event, F("DHT : no Reading !"));
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
delayMicroseconds(80);
|
||||
dht_in = digitalRead(Plugin_005_DHT_Pin);
|
||||
if (dht_in)
|
||||
{
|
||||
delayMicroseconds(80); // now ready for data reception
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
byte data = Plugin_005_read_dht_dat();
|
||||
if (data != -1)
|
||||
dht_dat[i] = data;
|
||||
else
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F("DHT : protocol timeout!"));
|
||||
error = true;
|
||||
}
|
||||
byte data = Plugin_005_read_dht_dat();
|
||||
if(data == -1)
|
||||
{ logError(event, "DHT : protocol timeout!");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!error)
|
||||
{
|
||||
dht_dat[i] = data;
|
||||
}
|
||||
interrupts();
|
||||
|
||||
// Checksum calculation is a Rollover Checksum by design!
|
||||
byte dht_check_sum = dht_dat[0] + dht_dat[1] + dht_dat[2] + dht_dat[3]; // check check_sum
|
||||
|
||||
if (dht_dat[4] == dht_check_sum)
|
||||
{
|
||||
float temperature = NAN;
|
||||
float humidity = NAN;
|
||||
|
||||
if (Par3 == 11)
|
||||
{
|
||||
temperature = float(dht_dat[2]); // Temperature
|
||||
humidity = float(dht_dat[0]); // Humidity
|
||||
}
|
||||
else if (Par3 == 12)
|
||||
{
|
||||
temperature = float(dht_dat[2]*10 + (dht_dat[3] & 0x7f)) / 10.0; // Temperature
|
||||
if (dht_dat[3] & 0x80) { temperature = -temperature; } // Negative temperature
|
||||
humidity = float(dht_dat[0]*10+dht_dat[1]) / 10.0; // Humidity
|
||||
}
|
||||
|
||||
if (Par3 == 22)
|
||||
{
|
||||
if (dht_dat[2] & 0x80) // negative temperature
|
||||
temperature = -0.1 * word(dht_dat[2] & 0x7F, dht_dat[3]);
|
||||
else
|
||||
temperature = 0.1 * word(dht_dat[2], dht_dat[3]);
|
||||
humidity = word(dht_dat[0], dht_dat[1]) * 0.1; // Humidity
|
||||
}
|
||||
if (temperature != NAN || humidity != NAN) // According to negated original if, maybe use && instead?
|
||||
{
|
||||
UserVar[event->BaseVarIndex] = temperature;
|
||||
UserVar[event->BaseVarIndex + 1] = humidity;
|
||||
String log = F("DHT : Temperature: ");
|
||||
log += UserVar[event->BaseVarIndex];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
log = F("DHT : Humidity: ");
|
||||
log += UserVar[event->BaseVarIndex + 1];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
}
|
||||
} // checksum
|
||||
} // error
|
||||
} // dht
|
||||
} // !dht
|
||||
if(!success)
|
||||
byte dht_check_sum = (dht_dat[0] + dht_dat[1] + dht_dat[2] + dht_dat[3]) & 0xFF; // check check_sum
|
||||
if (dht_dat[4] != dht_check_sum)
|
||||
{
|
||||
addLog(LOG_LEVEL_INFO, F("DHT : No reading!"));
|
||||
UserVar[event->BaseVarIndex] = NAN;
|
||||
UserVar[event->BaseVarIndex + 1] = NAN;
|
||||
logError(event, "DHT : checksum error!");
|
||||
break;
|
||||
}
|
||||
|
||||
float temperature = NAN;
|
||||
float humidity = NAN;
|
||||
if (Par3 == 11)
|
||||
{
|
||||
temperature = float(dht_dat[2]); // Temperature
|
||||
humidity = float(dht_dat[0]); // Humidity
|
||||
}
|
||||
else if (Par3 == 12)
|
||||
{
|
||||
temperature = float(dht_dat[2]*10 + (dht_dat[3] & 0x7f)) / 10.0; // Temperature
|
||||
if (dht_dat[3] & 0x80) { temperature = -temperature; } // Negative temperature
|
||||
humidity = float(dht_dat[0]*10+dht_dat[1]) / 10.0; // Humidity
|
||||
}
|
||||
else if (Par3 == 22 || Par3 == 23 || Par3 == 70)
|
||||
{
|
||||
if (dht_dat[2] & 0x80) // negative temperature
|
||||
temperature = -0.1 * word(dht_dat[2] & 0x7F, dht_dat[3]);
|
||||
else
|
||||
temperature = 0.1 * word(dht_dat[2], dht_dat[3]);
|
||||
humidity = 0.1 * word(dht_dat[0], dht_dat[1]); // Humidity
|
||||
}
|
||||
|
||||
if (temperature == NAN || humidity == NAN)
|
||||
{ logError(event, "DHT : invalid NAN reading !");
|
||||
break;
|
||||
}
|
||||
|
||||
UserVar[event->BaseVarIndex] = temperature;
|
||||
UserVar[event->BaseVarIndex + 1] = humidity;
|
||||
String log = F("DHT : Temperature: ");
|
||||
log += UserVar[event->BaseVarIndex];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
log = F("DHT : Humidity: ");
|
||||
log += UserVar[event->BaseVarIndex + 1];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -164,6 +159,31 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* DHT sub to log an error
|
||||
\*********************************************************************************************/
|
||||
void logError(struct EventStruct *event, String text)
|
||||
{
|
||||
addLog(LOG_LEVEL_INFO, text);
|
||||
UserVar[event->BaseVarIndex] = NAN;
|
||||
UserVar[event->BaseVarIndex + 1] = NAN;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* DHT sub to wait until a pin is in a certiin state
|
||||
\*********************************************************************************************/
|
||||
boolean waitState(int state)
|
||||
{
|
||||
byte counter = 0;
|
||||
while (( digitalRead(Plugin_005_DHT_Pin) != state) && (counter < 100))
|
||||
{
|
||||
delayMicroseconds(1);
|
||||
counter++;
|
||||
}
|
||||
if( counter < 100) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* DHT sub to get an 8 bit value from the receiving bitstream
|
||||
\*********************************************************************************************/
|
||||
@@ -172,7 +192,6 @@ int Plugin_005_read_dht_dat(void)
|
||||
byte i = 0;
|
||||
byte result = 0;
|
||||
byte counter = 0;
|
||||
//noInterrupts();
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
while ((!digitalRead(Plugin_005_DHT_Pin)) && (counter < 100))
|
||||
@@ -182,10 +201,9 @@ int Plugin_005_read_dht_dat(void)
|
||||
}
|
||||
if (counter >= 100)
|
||||
{
|
||||
//interrupts();
|
||||
return -1;
|
||||
}
|
||||
delayMicroseconds(30);
|
||||
delayMicroseconds(35); // was 30
|
||||
if (digitalRead(Plugin_005_DHT_Pin))
|
||||
result |= (1 << (7 - i));
|
||||
counter = 0;
|
||||
@@ -196,10 +214,8 @@ int Plugin_005_read_dht_dat(void)
|
||||
}
|
||||
if (counter >= 100)
|
||||
{
|
||||
//interrupts();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
//interrupts();
|
||||
return result;
|
||||
}
|
||||
|
||||
+28
-18
@@ -7,6 +7,7 @@
|
||||
// DS Temp:[Dallas1#Temperature#R]
|
||||
// Lux:[Lux#Lux#R]
|
||||
// Baro:[Baro#Pressure#R]
|
||||
// Pump:[Pump#on#O] -> ON/OFF
|
||||
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
|
||||
@@ -202,7 +203,7 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
|
||||
String tmpString = deviceTemplate[x];
|
||||
if (lcd && tmpString.length())
|
||||
{
|
||||
String newString = parseTemplate(tmpString, col);
|
||||
String newString = P012_parseTemplate(tmpString, col);
|
||||
lcd->setCursor(0, x);
|
||||
lcd->print(newString);
|
||||
}
|
||||
@@ -225,7 +226,22 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
|
||||
if (argIndex)
|
||||
tmpString = tmpString.substring(0, argIndex);
|
||||
|
||||
if (lcd && tmpString.equalsIgnoreCase(F("LCD")))
|
||||
if (lcd && tmpString.equalsIgnoreCase(F("LCDCMD")))
|
||||
{
|
||||
success = true;
|
||||
argIndex = string.lastIndexOf(',');
|
||||
tmpString = string.substring(argIndex + 1);
|
||||
if (tmpString.equalsIgnoreCase(F("Off"))){
|
||||
lcd->noBacklight();
|
||||
}
|
||||
else if (tmpString.equalsIgnoreCase(F("On"))){
|
||||
lcd->backlight();
|
||||
}
|
||||
else if (tmpString.equalsIgnoreCase(F("Clear"))){
|
||||
lcd->clear();
|
||||
}
|
||||
}
|
||||
else if (lcd && tmpString.equalsIgnoreCase(F("LCD")))
|
||||
{
|
||||
success = true;
|
||||
argIndex = string.lastIndexOf(',');
|
||||
@@ -280,25 +296,19 @@ boolean Plugin_012(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (lcd && tmpString.equalsIgnoreCase(F("LCDCMD")))
|
||||
{
|
||||
success = true;
|
||||
argIndex = string.lastIndexOf(',');
|
||||
tmpString = string.substring(argIndex + 1);
|
||||
if (tmpString.equalsIgnoreCase(F("Off"))){
|
||||
lcd->noBacklight();
|
||||
}
|
||||
else if (tmpString.equalsIgnoreCase(F("On"))){
|
||||
lcd->backlight();
|
||||
}
|
||||
else if (tmpString.equalsIgnoreCase(F("Clear"))){
|
||||
lcd->clear();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// Perform some specific changes for LCD display
|
||||
// https://www.letscontrolit.com/forum/viewtopic.php?t=2368
|
||||
String P012_parseTemplate(String &tmpString, byte lineSize) {
|
||||
String result = parseTemplate(tmpString, lineSize);
|
||||
const char degree[3] = {0xc2, 0xb0, 0}; // Unicode degree symbol
|
||||
const char degree_lcd[2] = {0xdf, 0}; // P012_LCD degree symbol
|
||||
result.replace(degree, degree_lcd);
|
||||
return result;
|
||||
}
|
||||
|
||||
+8
-8
@@ -184,13 +184,6 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
|
||||
int argIndex = tmpString.indexOf(',');
|
||||
if (argIndex)
|
||||
tmpString = tmpString.substring(0, argIndex);
|
||||
if (tmpString.equalsIgnoreCase(F("OLED")))
|
||||
{
|
||||
success = true;
|
||||
argIndex = string.lastIndexOf(',');
|
||||
tmpString = string.substring(argIndex + 1);
|
||||
Plugin_023_sendStrXY(tmpString.c_str(), event->Par1 - 1, event->Par2 - 1);
|
||||
}
|
||||
if (tmpString.equalsIgnoreCase(F("OLEDCMD")))
|
||||
{
|
||||
success = true;
|
||||
@@ -203,9 +196,16 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
|
||||
else if (tmpString.equalsIgnoreCase(F("Clear")))
|
||||
Plugin_023_clear_display();
|
||||
}
|
||||
else if (tmpString.equalsIgnoreCase(F("OLED")))
|
||||
{
|
||||
success = true;
|
||||
argIndex = string.lastIndexOf(',');
|
||||
tmpString = string.substring(argIndex + 1);
|
||||
String newString = P023_parseTemplate(tmpString, 16);
|
||||
Plugin_023_sendStrXY(newString.c_str(), event->Par1 - 1, event->Par2 - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
+7
-7
@@ -199,13 +199,13 @@ boolean Plugin_035(byte function, struct EventStruct *event, String& string)
|
||||
if (GetArgv(command, TmpStr1, 3)) IrCode = strtoul(TmpStr1, NULL, 16); //(long) TmpStr1
|
||||
if (GetArgv(command, TmpStr1, 4)) IrBits = str2int(TmpStr1);
|
||||
|
||||
if (IrType.equalsIgnoreCase("NEC")) Plugin_035_irSender->sendNEC(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase("JVC")) Plugin_035_irSender->sendJVC(IrCode, IrBits, 2);
|
||||
if (IrType.equalsIgnoreCase("RC5")) Plugin_035_irSender->sendRC5(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase("RC6")) Plugin_035_irSender->sendRC6(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase("SAMSUNG")) Plugin_035_irSender->sendSAMSUNG(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase("SONY")) Plugin_035_irSender->sendSony(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase("PANASONIC")) Plugin_035_irSender->sendPanasonic(IrBits, IrCode);
|
||||
if (IrType.equalsIgnoreCase(F("NEC"))) Plugin_035_irSender->sendNEC(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase(F("JVC"))) Plugin_035_irSender->sendJVC(IrCode, IrBits, 2);
|
||||
if (IrType.equalsIgnoreCase(F("RC5"))) Plugin_035_irSender->sendRC5(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase(F("RC6"))) Plugin_035_irSender->sendRC6(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase(F("SAMSUNG"))) Plugin_035_irSender->sendSAMSUNG(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase(F("SONY"))) Plugin_035_irSender->sendSony(IrCode, IrBits);
|
||||
if (IrType.equalsIgnoreCase(F("PANASONIC"))) Plugin_035_irSender->sendPanasonic(IrBits, IrCode);
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_INFO, F("IRTX :IR Code Sent"));
|
||||
|
||||
@@ -225,7 +225,7 @@ boolean Plugin_036(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
// Display the device name, logo, time and wifi
|
||||
display_header();
|
||||
// display_logo();
|
||||
display_logo();
|
||||
display->display();
|
||||
|
||||
// Set up the display timer
|
||||
@@ -503,8 +503,14 @@ void display_title(String& title) {
|
||||
}
|
||||
|
||||
void display_logo() {
|
||||
// draw an xbm image.
|
||||
display->drawXbm(34, 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(ArialMT_Plain_16);
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(0, 14, 128, 64);
|
||||
display->setColor(WHITE);
|
||||
display->drawString(65, 15, F("ESP"));
|
||||
display->drawString(65, 34, F("Easy"));
|
||||
display->drawXbm(24, 14, espeasy_logo_width, espeasy_logo_height, espeasy_logo_bits);
|
||||
}
|
||||
|
||||
// Draw the frame position
|
||||
|
||||
@@ -166,13 +166,11 @@ boolean Plugin_037(byte function, struct EventStruct *event, String& string)
|
||||
// This is a private option only used by the MQTT 037 callback function
|
||||
|
||||
// Get the payload and check it out
|
||||
|
||||
String Payload = event->String2;
|
||||
float floatPayload = string2float(Payload);
|
||||
|
||||
LoadTaskSettings(event->TaskIndex);
|
||||
|
||||
if (floatPayload == -999) {
|
||||
String Payload = event->String2;
|
||||
float floatPayload;
|
||||
if (!string2float(Payload, floatPayload)) {
|
||||
String log = F("IMPT : Bad Import MQTT Command ");
|
||||
log += event->String1;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
@@ -450,41 +448,3 @@ boolean MQTTCheckSubscription_037(String Topic, String Subscription) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ***************************************************************************
|
||||
// Convert String to float - returns -999 in case of error
|
||||
float string2float(String myString) {
|
||||
int i, len;
|
||||
float value;
|
||||
len = myString.length();
|
||||
char tmp[(len + 1)]; // one extra for the zero termination
|
||||
byte start = 0;
|
||||
// Look for decimal point - they can be anywhere but no more than one of them!
|
||||
int dotIndex = myString.indexOf('.');
|
||||
//Serial.println(dotIndex);
|
||||
|
||||
if (dotIndex != -1)
|
||||
{
|
||||
int dotIndex2 = (myString.substring(dotIndex + 1)).indexOf('.');
|
||||
//Serial.println(dotIndex2);
|
||||
if (dotIndex2 != -1)return -999.00; // Give error if there is more than one dot
|
||||
}
|
||||
|
||||
if (myString.charAt(0) == '-') {
|
||||
tmp[0] = '-';
|
||||
start = 1; //allow a minus in front of string
|
||||
}
|
||||
|
||||
for (i = start; i < len; i++)
|
||||
{
|
||||
tmp[i] = myString.charAt(i);
|
||||
if (!isdigit(tmp[i]))
|
||||
{
|
||||
if (tmp[i] != '.')return -999;
|
||||
}
|
||||
}
|
||||
|
||||
tmp[i] = 0;
|
||||
value = atof(tmp);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -102,18 +102,17 @@ boolean Plugin_048(byte function, struct EventStruct *event, String& string) {
|
||||
String tmpString = string;
|
||||
|
||||
String cmd = parseString(tmpString, 1);
|
||||
String param1 = parseString(tmpString, 2);
|
||||
String param2 = parseString(tmpString, 3);
|
||||
String param3 = parseString(tmpString, 4);
|
||||
String param4 = parseString(tmpString, 5);
|
||||
String param5 = parseString(tmpString, 6);
|
||||
|
||||
|
||||
// Commands:
|
||||
// MotorShieldCMD,<DCMotor>,<Motornumber>,<Forward/Backward/Release>,<Speed>
|
||||
|
||||
if (cmd.equalsIgnoreCase(F("MotorShieldCMD")))
|
||||
{
|
||||
String param1 = parseString(tmpString, 2);
|
||||
String param2 = parseString(tmpString, 3);
|
||||
String param3 = parseString(tmpString, 4);
|
||||
String param4 = parseString(tmpString, 5);
|
||||
String param5 = parseString(tmpString, 6);
|
||||
|
||||
// Create the motor shield object with the default I2C address
|
||||
AFMS = Adafruit_MotorShield(Plugin_048_MotorShield_address);
|
||||
|
||||
+3
-3
@@ -22,8 +22,8 @@ boolean Plugin_049_init = false;
|
||||
boolean Plugin_049_ABC_Disable = false;
|
||||
boolean Plugin_049_ABC_MustApply = false;
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial *Plugin_049_SoftSerial;
|
||||
#include <ESPeasySoftwareSerial.h>
|
||||
ESPeasySoftwareSerial *Plugin_049_SoftSerial;
|
||||
|
||||
// 9-bytes CMD PPM read command
|
||||
byte mhzCmdReadPPM[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
|
||||
@@ -111,7 +111,7 @@ boolean Plugin_049(byte function, struct EventStruct *event, String& string)
|
||||
// No guarantee the correct state is active on the sensor after reboot.
|
||||
Plugin_049_ABC_MustApply = true;
|
||||
}
|
||||
Plugin_049_SoftSerial = new SoftwareSerial(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex]);
|
||||
Plugin_049_SoftSerial = new ESPeasySoftwareSerial(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex]);
|
||||
Plugin_049_SoftSerial->begin(9600);
|
||||
addLog(LOG_LEVEL_INFO, F("MHZ19: Init OK "));
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
boolean Plugin_052_init = false;
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial *Plugin_052_SoftSerial;
|
||||
#include <ESPeasySoftwareSerial.h>
|
||||
ESPeasySoftwareSerial *Plugin_052_SoftSerial;
|
||||
|
||||
boolean Plugin_052(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
@@ -130,7 +130,7 @@ boolean Plugin_052(byte function, struct EventStruct *event, String& string)
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
Plugin_052_init = true;
|
||||
Plugin_052_SoftSerial = new SoftwareSerial(Settings.TaskDevicePin1[event->TaskIndex],
|
||||
Plugin_052_SoftSerial = new ESPeasySoftwareSerial(Settings.TaskDevicePin1[event->TaskIndex],
|
||||
Settings.TaskDevicePin2[event->TaskIndex]);
|
||||
|
||||
/*
|
||||
|
||||
+108
-83
@@ -10,7 +10,7 @@
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
#include <ESPeasySoftwareSerial.h>
|
||||
|
||||
#define PLUGIN_053
|
||||
#define PLUGIN_ID_053 53
|
||||
@@ -22,7 +22,7 @@
|
||||
#define PMSx003_SIG2 0X4d
|
||||
#define PMSx003_SIZE 32
|
||||
|
||||
SoftwareSerial *swSerial = NULL;
|
||||
ESPeasySoftwareSerial *swSerial = NULL;
|
||||
boolean Plugin_053_init = false;
|
||||
boolean values_received = false;
|
||||
|
||||
@@ -66,42 +66,108 @@ void SerialRead16(uint16_t* value, uint16_t* checksum)
|
||||
#endif
|
||||
}
|
||||
|
||||
void SerialFlush() {
|
||||
if (swSerial != NULL) {
|
||||
swSerial->flush();
|
||||
} else {
|
||||
Serial.flush();
|
||||
}
|
||||
}
|
||||
|
||||
boolean PacketAvailable(void)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
if (swSerial != NULL) // Software serial
|
||||
{
|
||||
// When there is enough data in the buffer, search through the buffer to
|
||||
// find header (buffer may be out of sync)
|
||||
while (swSerial->available() >= PMSx003_SIZE)
|
||||
{
|
||||
if (swSerial->read() == PMSx003_SIG1 && swSerial->read() == PMSx003_SIG2)
|
||||
{
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
if (!swSerial->available()) return false;
|
||||
while ((swSerial->peek() != PMSx003_SIG1) && swSerial->available()) {
|
||||
swSerial->read(); // Read until the buffer starts with the first byte of a message, or buffer empty.
|
||||
}
|
||||
if (swSerial->available() < PMSx003_SIZE) return false; // Not enough yet for a complete packet
|
||||
}
|
||||
else // Hardware serial
|
||||
{
|
||||
// When there is enough data in the buffer, search through the buffer to
|
||||
// find header (buffer may be out of sync)
|
||||
while (Serial.available() >= PMSx003_SIZE)
|
||||
{
|
||||
if (Serial.read() == PMSx003_SIG1 && Serial.read() == PMSx003_SIG2)
|
||||
{
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
if (!Serial.available()) return false;
|
||||
while ((Serial.peek() != PMSx003_SIG1) && Serial.available()) {
|
||||
Serial.read(); // Read until the buffer starts with the first byte of a message, or buffer empty.
|
||||
}
|
||||
if (Serial.available() < PMSx003_SIZE) return false; // Not enough yet for a complete packet
|
||||
}
|
||||
return success;
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean Plugin_053_process_data(struct EventStruct *event) {
|
||||
String log;
|
||||
uint16_t checksum = 0, checksum2 = 0;
|
||||
uint16_t framelength = 0;
|
||||
uint16 packet_header = 0;
|
||||
SerialRead16(&packet_header, &checksum); // read PMSx003_SIG1 + PMSx003_SIG2
|
||||
if (packet_header != ((PMSx003_SIG1 << 8) | PMSx003_SIG2)) {
|
||||
// Not the start of the packet, stop reading.
|
||||
return false;
|
||||
}
|
||||
|
||||
SerialRead16(&framelength, &checksum);
|
||||
if (framelength != (PMSx003_SIZE - 4))
|
||||
{
|
||||
log = F("PMSx003 : invalid framelength - ");
|
||||
log += framelength;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t data[13]; // byte data_low, data_high;
|
||||
for (int i = 0; i < 13; i++)
|
||||
SerialRead16(&data[i], &checksum);
|
||||
|
||||
log = F("PMSx003 : pm1.0=");
|
||||
log += data[0];
|
||||
log += F(", pm2.5=");
|
||||
log += data[1];
|
||||
log += F(", pm10=");
|
||||
log += data[2];
|
||||
log += F(", pm1.0a=");
|
||||
log += data[3];
|
||||
log += F(", pm2.5a=");
|
||||
log += data[4];
|
||||
log += F(", pm10a=");
|
||||
log += data[5];
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
log = F("PMSx003 : count/0.1L : 0.3um=");
|
||||
log += data[6];
|
||||
log += F(", 0.5um=");
|
||||
log += data[7];
|
||||
log += F(", 1.0um=");
|
||||
log += data[8];
|
||||
log += F(", 2.5um=");
|
||||
log += data[9];
|
||||
log += F(", 5.0um=");
|
||||
log += data[10];
|
||||
log += F(", 10um=");
|
||||
log += data[11];
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
// Compare checksums
|
||||
SerialRead16(&checksum2, NULL);
|
||||
SerialFlush(); // Make sure no data is lost due to full buffer.
|
||||
if (checksum == checksum2)
|
||||
{
|
||||
// Data is checked and good, fill in output
|
||||
UserVar[event->BaseVarIndex] = data[3];
|
||||
UserVar[event->BaseVarIndex + 1] = data[4];
|
||||
UserVar[event->BaseVarIndex + 2] = data[5];
|
||||
values_received = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean Plugin_053(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
String log;
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
@@ -153,12 +219,18 @@ boolean Plugin_053(byte function, struct EventStruct *event, String& string)
|
||||
int txPin = Settings.TaskDevicePin2[event->TaskIndex];
|
||||
int resetPin = Settings.TaskDevicePin3[event->TaskIndex];
|
||||
|
||||
log = F("PMSx003 : config ");
|
||||
String log = F("PMSx003 : config ");
|
||||
log += rxPin;
|
||||
log += txPin;
|
||||
log += resetPin;
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
if (swSerial != NULL) {
|
||||
// Regardless the set pins, the software serial must be deleted.
|
||||
delete swSerial;
|
||||
swSerial = NULL;
|
||||
}
|
||||
|
||||
// Hardware serial is RX on 3 and TX on 1
|
||||
if (rxPin == 3 && txPin == 1)
|
||||
{
|
||||
@@ -171,7 +243,7 @@ boolean Plugin_053(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
log = F("PMSx003: using software serial");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
swSerial = new SoftwareSerial(rxPin, txPin);
|
||||
swSerial = new ESPeasySoftwareSerial(rxPin, txPin, false, 96); // 96 Bytes buffer, enough for up to 3 packets.
|
||||
swSerial->begin(9600);
|
||||
swSerial->flush();
|
||||
}
|
||||
@@ -192,6 +264,17 @@ boolean Plugin_053(byte function, struct EventStruct *event, String& string)
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_EXIT:
|
||||
{
|
||||
if (swSerial)
|
||||
{
|
||||
delete swSerial;
|
||||
swSerial=NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// The update rate from the module is 200ms .. multiple seconds. Practise
|
||||
// shows that we need to read the buffer many times per seconds to stay in
|
||||
// sync.
|
||||
@@ -199,69 +282,11 @@ boolean Plugin_053(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
if (Plugin_053_init)
|
||||
{
|
||||
uint16_t checksum = 0, checksum2 = 0;
|
||||
uint16_t framelength = 0;
|
||||
uint16_t data[13];
|
||||
// byte data_low, data_high;
|
||||
int i = 0;
|
||||
|
||||
// Check if a packet is available in the UART FIFO.
|
||||
// Check if a complete packet is available in the UART FIFO.
|
||||
if (PacketAvailable())
|
||||
{
|
||||
log = F("PMSx003 : Packet available");
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
checksum += PMSx003_SIG1 + PMSx003_SIG2;
|
||||
SerialRead16(&framelength, &checksum);
|
||||
if (framelength != (PMSx003_SIZE - 4))
|
||||
{
|
||||
log = F("PMSx003 : invalid framelength - ");
|
||||
log += framelength;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < 13; i++)
|
||||
SerialRead16(&data[i], &checksum);
|
||||
|
||||
log = F("PMSx003 : pm1.0=");
|
||||
log += data[0];
|
||||
log += F(", pm2.5=");
|
||||
log += data[1];
|
||||
log += F(", pm10=");
|
||||
log += data[2];
|
||||
log += F(", pm1.0a=");
|
||||
log += data[3];
|
||||
log += F(", pm2.5a=");
|
||||
log += data[4];
|
||||
log += F(", pm10a=");
|
||||
log += data[5];
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
log = F("PMSx003 : count/0.1L : 0.3um=");
|
||||
log += data[6];
|
||||
log += F(", 0.5um=");
|
||||
log += data[7];
|
||||
log += F(", 1.0um=");
|
||||
log += data[8];
|
||||
log += F(", 2.5um=");
|
||||
log += data[9];
|
||||
log += F(", 5.0um=");
|
||||
log += data[10];
|
||||
log += F(", 10um=");
|
||||
log += data[11];
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
// Compare checksums
|
||||
SerialRead16(&checksum2, NULL);
|
||||
if (checksum == checksum2)
|
||||
{
|
||||
// Data is checked and good, fill in output
|
||||
UserVar[event->BaseVarIndex] = data[3];
|
||||
UserVar[event->BaseVarIndex + 1] = data[4];
|
||||
UserVar[event->BaseVarIndex + 2] = data[5];
|
||||
values_received = true;
|
||||
success = true;
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, F("PMSx003 : Packet available"));
|
||||
success = Plugin_053_process_data(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
+10
-9
@@ -31,10 +31,10 @@
|
||||
// DMX,5=123,8=44" Set channel 5 to value 123, channel 8 to 44
|
||||
// DMX,OFF" Pitch Black
|
||||
|
||||
// Transeiver:
|
||||
// Transceiver:
|
||||
// SN75176 or MAX485 or LT1785 or ...
|
||||
// Pin 5: GND
|
||||
// Pin 2, 3, 5: +5V
|
||||
// Pin 2, 3, 8: +5V
|
||||
// Pin 4: to ESP D4
|
||||
// Pin 6: DMX+ (hot)
|
||||
// Pin 7: DMX- (cold)
|
||||
@@ -134,8 +134,9 @@ boolean Plugin_054(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
string.toLowerCase();
|
||||
String command = parseString(string, 1);
|
||||
String lowerString=string;
|
||||
lowerString.toLowerCase();
|
||||
String command = parseString(lowerString, 1);
|
||||
|
||||
if (command == F("dmx"))
|
||||
{
|
||||
@@ -146,11 +147,11 @@ boolean Plugin_054(byte function, struct EventStruct *event, String& string)
|
||||
int16_t channel = 1;
|
||||
int16_t value = 0;
|
||||
|
||||
string.replace(" ", " ");
|
||||
string.replace(" =", "=");
|
||||
string.replace("= ", "=");
|
||||
lowerString.replace(" ", " ");
|
||||
lowerString.replace(" =", "=");
|
||||
lowerString.replace("= ", "=");
|
||||
|
||||
param = parseString(string, paramIdx++);
|
||||
param = parseString(lowerString, paramIdx++);
|
||||
if (param.length())
|
||||
{
|
||||
while (param.length())
|
||||
@@ -211,7 +212,7 @@ boolean Plugin_054(byte function, struct EventStruct *event, String& string)
|
||||
channel++;
|
||||
}
|
||||
|
||||
param = parseString(string, paramIdx++);
|
||||
param = parseString(lowerString, paramIdx++);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
+12
-11
@@ -150,13 +150,14 @@ boolean Plugin_057(byte function, struct EventStruct *event, String& string)
|
||||
if (!Plugin_057_M)
|
||||
return false;
|
||||
|
||||
string.toLowerCase();
|
||||
String command = parseString(string, 1);
|
||||
String lowerString=string;
|
||||
lowerString.toLowerCase();
|
||||
String command = parseString(lowerString, 1);
|
||||
|
||||
if (command == F("mprint"))
|
||||
{
|
||||
int paramPos = getParamStartPos(string, 2);
|
||||
String text = string.substring(paramPos);
|
||||
int paramPos = getParamStartPos(lowerString, 2);
|
||||
String text = lowerString.substring(paramPos);
|
||||
byte seg = 0;
|
||||
|
||||
Plugin_057_M->ClearRowBuffer();
|
||||
@@ -171,8 +172,8 @@ boolean Plugin_057(byte function, struct EventStruct *event, String& string)
|
||||
success = true;
|
||||
}
|
||||
else if (command == F("mbr")) {
|
||||
int paramPos = getParamStartPos(string, 2);
|
||||
uint8_t brightness = string.substring(paramPos).toInt();
|
||||
int paramPos = getParamStartPos(lowerString, 2);
|
||||
uint8_t brightness = lowerString.substring(paramPos).toInt();
|
||||
Plugin_057_M->SetBrightness(brightness);
|
||||
success = true;
|
||||
}
|
||||
@@ -185,11 +186,11 @@ boolean Plugin_057(byte function, struct EventStruct *event, String& string)
|
||||
uint8_t seg = 0;
|
||||
uint16_t value = 0;
|
||||
|
||||
string.replace(" ", " ");
|
||||
string.replace(" =", "=");
|
||||
string.replace("= ", "=");
|
||||
lowerString.replace(" ", " ");
|
||||
lowerString.replace(" =", "=");
|
||||
lowerString.replace("= ", "=");
|
||||
|
||||
param = parseString(string, paramIdx++);
|
||||
param = parseString(lowerString, paramIdx++);
|
||||
if (param.length())
|
||||
{
|
||||
while (param.length())
|
||||
@@ -259,7 +260,7 @@ boolean Plugin_057(byte function, struct EventStruct *event, String& string)
|
||||
seg++;
|
||||
}
|
||||
|
||||
param = parseString(string, paramIdx++);
|
||||
param = parseString(lowerString, paramIdx++);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -167,6 +167,26 @@ boolean Plugin_059(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
if (Plugin_059_QE)
|
||||
{
|
||||
String log = "";
|
||||
String command = parseString(string, 1);
|
||||
if (command == F("encwrite"))
|
||||
{
|
||||
if (event->Par1 >= 0)
|
||||
{
|
||||
log = String(F("QEI : ")) + string;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
Plugin_059_QE->write(event->Par1);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -81,11 +81,11 @@ boolean Plugin_060(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
addFormCheckBox(string, F("Calibration Enabled"), F("plugin_060_cal"), CONFIG(3));
|
||||
|
||||
addFormNumericBox(string, F("Point 1"), F("plugin_060_adc1"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][0], 0, 1023);
|
||||
addFormNumericBox(string, F("Point 1"), F("plugin_060_adc1"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][0], 0, 4095);
|
||||
string += F(" ≙ ");
|
||||
addTextBox(string, F("plugin_060_out1"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0], 3), 10);
|
||||
|
||||
addFormNumericBox(string, F("Point 2"), F("plugin_060_adc2"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1], 0, 1023);
|
||||
addFormNumericBox(string, F("Point 2"), F("plugin_060_adc2"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1], 0, 4095);
|
||||
string += F(" ≙ ");
|
||||
addTextBox(string, F("plugin_060_out2"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1], 3), 10);
|
||||
|
||||
|
||||
+11
-10
@@ -5,20 +5,20 @@
|
||||
// ESPEasy Plugin to controls a MP3-player-module DFPlayer-Mini SKU:DFR0299
|
||||
// written by Jochen Krapf (jk@nerd2nerd.org)
|
||||
|
||||
// Important! The module WTV020-SD look similar to the module DFPlayer-Mini but is NOT pin and command compatible!
|
||||
// Important! The module WTV020-SD look similar to the module DFPlayer-Mini but is NOT pin nor command compatible!
|
||||
|
||||
// Commands:
|
||||
// play,<track> Plays the n-th track 1...3000 on SD-card in root folder. The track number is the physical ordenr - not the order displayed in file explorer!
|
||||
// play,<track> Plays the n-th track 1...3000 on SD-card in root folder. The track number is the physical order - not the order displayed in file explorer!
|
||||
// stop Stops actual playing sound
|
||||
// vol,<volume> Set volume level 1...30
|
||||
// eq,<type> Set the equalizer type 0=Normal, 1=Pop, 2=Rock, 3=Jazz, 4=classic, 5=Base
|
||||
|
||||
// Circuit wiring
|
||||
// 1st-GPIO -> ESP TX to module RX [Pin2]
|
||||
// 5V to module VCC [Pin1] (can be more than 100mA) Note: Use a capacitor to denoise VCC
|
||||
// 5 V to module VCC [Pin1] (can be more than 100 mA) Note: Use a blocking capacitor to stabilise VCC
|
||||
// GND to module GND [Pin7+Pin10]
|
||||
// Speaker to module SPK_1 and SPK_2 [Pin6,Pin8] (not to GND!) Note: If speaker has to low impedance, use a resistor (like 33 Ohm) in line to speaker
|
||||
// (optional) module BUSY [Pin16] to LED driver (3.3V on idle, 0V on playing)
|
||||
// (optional) module BUSY [Pin16] to LED driver (3.3 V on idle, 0 V on playing)
|
||||
// All other pins unconnected
|
||||
|
||||
// Note: Notification sounds with Creative Commons Attribution license: https://notificationsounds.com/
|
||||
@@ -33,7 +33,7 @@
|
||||
#define PLUGIN_NAME_065 "Notify - DFPlayer-Mini MP3 [TESTING]"
|
||||
#define PLUGIN_VALUENAME1_065 ""
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
#include <ESPeasySoftwareSerial.h>
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
@@ -42,7 +42,7 @@
|
||||
#define PIN(n) (Settings.TaskDevicePin[n][event->TaskIndex])
|
||||
#endif
|
||||
|
||||
SoftwareSerial* Plugin_065_SoftSerial = NULL;
|
||||
ESPeasySoftwareSerial* Plugin_065_SoftSerial = NULL;
|
||||
|
||||
|
||||
boolean Plugin_065(byte function, struct EventStruct *event, String& string)
|
||||
@@ -106,7 +106,7 @@ boolean Plugin_065(byte function, struct EventStruct *event, String& string)
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
|
||||
Plugin_065_SoftSerial = new SoftwareSerial(-1, PIN(0)); // no RX, only TX
|
||||
Plugin_065_SoftSerial = new ESPeasySoftwareSerial(-1, PIN(0)); // no RX, only TX
|
||||
|
||||
Plugin_065_SoftSerial->begin(9600);
|
||||
|
||||
@@ -121,9 +121,10 @@ boolean Plugin_065(byte function, struct EventStruct *event, String& string)
|
||||
if (!Plugin_065_SoftSerial)
|
||||
break;
|
||||
|
||||
string.toLowerCase();
|
||||
String command = parseString(string, 1);
|
||||
String param = parseString(string, 2);
|
||||
String lowerString=string;
|
||||
lowerString.toLowerCase();
|
||||
String command = parseString(lowerString, 1);
|
||||
String param = parseString(lowerString, 2);
|
||||
|
||||
if (command == F("play"))
|
||||
{
|
||||
|
||||
@@ -266,8 +266,9 @@ boolean Plugin_067(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
string.toLowerCase();
|
||||
String command = parseString(string, 1);
|
||||
String lowerString=string;
|
||||
lowerString.toLowerCase();
|
||||
String command = parseString(lowerString, 1);
|
||||
|
||||
if (command == F("tare"))
|
||||
{
|
||||
|
||||
+8
-8
@@ -87,7 +87,7 @@ void SHT3X::get()
|
||||
#define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n])
|
||||
#endif
|
||||
|
||||
SHT3X* Plugin_068_SHT3x = NULL;
|
||||
SHT3X* Plugin_068_SHT3x[TASKS_MAX] = { NULL, };
|
||||
|
||||
|
||||
//==============================================
|
||||
@@ -148,9 +148,9 @@ boolean Plugin_068(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (Plugin_068_SHT3x)
|
||||
delete Plugin_068_SHT3x;
|
||||
Plugin_068_SHT3x = new SHT3X(CONFIG(0));
|
||||
if (Plugin_068_SHT3x[event->TaskIndex])
|
||||
delete Plugin_068_SHT3x[event->TaskIndex];
|
||||
Plugin_068_SHT3x[event->TaskIndex] = new SHT3X(CONFIG(0));
|
||||
|
||||
success = true;
|
||||
break;
|
||||
@@ -158,12 +158,12 @@ boolean Plugin_068(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
if (!Plugin_068_SHT3x)
|
||||
if (!Plugin_068_SHT3x[event->TaskIndex])
|
||||
return success;
|
||||
|
||||
Plugin_068_SHT3x->get();
|
||||
UserVar[event->BaseVarIndex + 0] = Plugin_068_SHT3x->tmp;
|
||||
UserVar[event->BaseVarIndex + 1] = Plugin_068_SHT3x->hum;
|
||||
Plugin_068_SHT3x[event->TaskIndex]->get();
|
||||
UserVar[event->BaseVarIndex + 0] = Plugin_068_SHT3x[event->TaskIndex]->tmp;
|
||||
UserVar[event->BaseVarIndex + 1] = Plugin_068_SHT3x[event->TaskIndex]->hum;
|
||||
String log = F("SHT3x: Temperature: ");
|
||||
log += UserVar[event->BaseVarIndex + 0];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
@@ -144,11 +144,12 @@ boolean Plugin_070(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
string.toLowerCase();
|
||||
String command = parseString(string, 1);
|
||||
String param1 = parseString(string, 2);
|
||||
String param2 = parseString(string, 3);
|
||||
String param3 = parseString(string, 4);
|
||||
String lowerString=string;
|
||||
lowerString.toLowerCase();
|
||||
String command = parseString(lowerString, 1);
|
||||
String param1 = parseString(lowerString, 2);
|
||||
String param2 = parseString(lowerString, 3);
|
||||
String param3 = parseString(lowerString, 4);
|
||||
|
||||
if (command == F("clock")) {
|
||||
if (param1 != "") {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
#include <ESPeasySoftwareSerial.h>
|
||||
#define PLUGIN_071
|
||||
#define PLUGIN_ID_071 71
|
||||
#define PLUGIN_NAME_071 "Communication - Kamstrup Multical 401 [TESTING]"
|
||||
@@ -76,7 +76,7 @@ boolean Plugin_071(byte function, struct EventStruct *event, String& string)
|
||||
PIN_KAMSER_RX = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
PIN_KAMSER_TX = Settings.TaskDevicePin2[event->TaskIndex];
|
||||
|
||||
SoftwareSerial kamSer(PIN_KAMSER_RX, PIN_KAMSER_TX, false); // Initialize serial
|
||||
ESPeasySoftwareSerial kamSer(PIN_KAMSER_RX, PIN_KAMSER_TX, false); // Initialize serial
|
||||
|
||||
pinMode(PIN_KAMSER_RX,INPUT);
|
||||
pinMode(PIN_KAMSER_TX,OUTPUT);
|
||||
|
||||
@@ -90,9 +90,12 @@ boolean Plugin_072(byte function, struct EventStruct *event, String& string)
|
||||
log = F("HDC1080: Humidity: ");
|
||||
log += UserVar[event->BaseVarIndex + 1];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,788 @@
|
||||
//#######################################################################################################
|
||||
//################### Plugin 073 - 7-segment display plugin TM1637/MAX7219 ######################
|
||||
//#######################################################################################################
|
||||
//
|
||||
// Chips/displays supported:
|
||||
// 0 - TM1637 -- 2 pins - 4 digits and colon in the middle (XX:XX)
|
||||
// 1 - TM1637 -- 2 pins - 4 digits and dot on each digit (X.X.X.X.)
|
||||
// 2 - TM1637 -- 2 pins - 6 digits and dot on each digit (X.X.X.X.X.X.)
|
||||
// 3 - MAX7219/21 -- 3 pins - 8 digits and dot on each digit (X.X.X.X.)
|
||||
//
|
||||
// Plugin can be setup as:
|
||||
// - Manual -- display is manually updated sending commands
|
||||
// "7dn,<number>" (number can be negative or positive, even with decimal)
|
||||
// "7dt,<temperature>" (temperature can be negative or positive and containing decimals)
|
||||
// - Clock-Blink -- display is automatically updated with current time and blinking dot/lines
|
||||
// - Clock-NoBlink -- display is automatically updated with current time and steady dot/lines
|
||||
// - Date -- display is automatically updated with current date
|
||||
//
|
||||
// Generic commands:
|
||||
// - "7don" -- turn ON the display
|
||||
// - "7doff" -- turn OFF the display
|
||||
// - "7db,<0-15> -- set brightness to specific value between 0 and 15
|
||||
//
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define PLUGIN_073
|
||||
#define PLUGIN_ID_073 73
|
||||
#define PLUGIN_NAME_073 "Display - 7-segment display [TESTING]"
|
||||
#define PLUGIN_073_DEBUG false //activate extra log info in the debug
|
||||
|
||||
//---------------------------------------------------
|
||||
// Class used by plugin
|
||||
//---------------------------------------------------
|
||||
class p073_7dgt
|
||||
{
|
||||
public:
|
||||
uint8_t pin1, pin2, pin3;
|
||||
byte type;
|
||||
byte output;
|
||||
byte brightness;
|
||||
boolean timesep;
|
||||
};
|
||||
p073_7dgt *Plugin_073_7dgt = NULL;
|
||||
//---------------------------------------------------
|
||||
|
||||
uint8_t p073_showbuffer[8];
|
||||
byte p073_spidata[2];
|
||||
byte p073_dotpos;
|
||||
bool p073_shift;
|
||||
|
||||
#define TM1637_POWER_ON B10001000
|
||||
#define TM1637_POWER_OFF B10000000
|
||||
#define TM1637_CLOCKDELAY 40
|
||||
#define TM1637_4DIGIT 4
|
||||
#define TM1637_6DIGIT 2
|
||||
|
||||
// each char table is specific for each display and maps all numbers/symbols needed:
|
||||
// - pos 0-9 - Numbers from 0 to 9
|
||||
// - pos 10 - Space " "
|
||||
// - pos 11 - minus symbol "-"
|
||||
// - pos 12 - degree symbol "°"
|
||||
const byte CharTableTM1637 [13] = {B00111111,B00000110,B01011011,B01001111,B01100110,B01101101,B01111101,B00000111,B01111111,B01101111,B00000000,B01000000,B01100011};
|
||||
const byte CharTableMAX7219 [13] = {B01111110,B00110000,B01101101,B01111001,B00110011,B01011011,B01011111,B01110000,B01111111,B01111011,B00000000,B00000001,B01100011};
|
||||
|
||||
boolean Plugin_073(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case PLUGIN_DEVICE_ADD:
|
||||
{
|
||||
Device[++deviceCount].Number = PLUGIN_ID_073;
|
||||
Device[deviceCount].Type = DEVICE_TYPE_TRIPLE;
|
||||
Device[deviceCount].VType = SENSOR_TYPE_SWITCH;
|
||||
Device[deviceCount].Ports = 0;
|
||||
Device[deviceCount].PullUpOption = false;
|
||||
Device[deviceCount].InverseLogicOption = false;
|
||||
Device[deviceCount].FormulaOption = false;
|
||||
Device[deviceCount].ValueCount = 0;
|
||||
Device[deviceCount].SendDataOption = false;
|
||||
Device[deviceCount].TimerOption = false;
|
||||
Device[deviceCount].TimerOptional = false;
|
||||
Device[deviceCount].GlobalSyncOption = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(PLUGIN_NAME_073);
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
addFormNote(string, F("TM1637: 1st=CLK-Pin, 2nd=DIO-Pin"));
|
||||
addFormNote(string, F("MAX7219: 1st=DIN-Pin, 2nd=CLK-Pin, 3rd=CS-Pin"));
|
||||
String displtype[5] = { F("TM1637 - 4 digit (colon)"), F("TM1637 - 4 digit (dots)"), F("TM1637 - 6 digit"), F("MAX7219 - 8 digit")};
|
||||
addFormSelector(string, F("Display Type"), F("plugin_073_displtype"), 4, displtype, NULL, Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
|
||||
String displout[4] = { F("Manual"), F("Clock - Blink"), F("Clock - No Blink"), F("Date") };
|
||||
addFormSelector(string, F("Display Output"), F("plugin_073_displout"), 4, displout, NULL, Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
|
||||
addFormNumericBox(string, F("Brightness"), F("plugin_073_brightness"), Settings.TaskDevicePluginConfig[event->TaskIndex][2], 0, 15);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SAVE:
|
||||
{
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_073_displtype"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_073_displout"));
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_073_brightness"));
|
||||
if (Plugin_073_7dgt) {
|
||||
Plugin_073_7dgt->pin1 = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
Plugin_073_7dgt->pin2 = Settings.TaskDevicePin2[event->TaskIndex];
|
||||
Plugin_073_7dgt->pin3 = Settings.TaskDevicePin3[event->TaskIndex];
|
||||
Plugin_073_7dgt->type = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
Plugin_073_7dgt->output = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
|
||||
Plugin_073_7dgt->brightness = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
|
||||
Plugin_073_7dgt->timesep = true;
|
||||
switch (Settings.TaskDevicePluginConfig[event->TaskIndex][0])
|
||||
{
|
||||
case 0: // set brightness of TM1637
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
int tm1637_bright = Settings.TaskDevicePluginConfig[event->TaskIndex][2] / 2;
|
||||
tm1637_SetPowerBrightness(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex], tm1637_bright, true);
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 0)
|
||||
tm1637_ClearDisplay(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex]);
|
||||
break;
|
||||
}
|
||||
case 3: // set brightness of MAX7219
|
||||
{
|
||||
max7219_SetPowerBrightness(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex], Settings.TaskDevicePin3[event->TaskIndex], Settings.TaskDevicePluginConfig[event->TaskIndex][2], true);
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 0)
|
||||
max7219_ClearDisplay(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex], Settings.TaskDevicePin3[event->TaskIndex]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
if (!Plugin_073_7dgt) {
|
||||
Plugin_073_7dgt = new p073_7dgt;
|
||||
Plugin_073_7dgt->pin1 = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
Plugin_073_7dgt->pin2 = Settings.TaskDevicePin2[event->TaskIndex];
|
||||
Plugin_073_7dgt->pin3 = Settings.TaskDevicePin3[event->TaskIndex];
|
||||
Plugin_073_7dgt->type = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
Plugin_073_7dgt->output = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
|
||||
Plugin_073_7dgt->brightness = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
|
||||
switch (Settings.TaskDevicePluginConfig[event->TaskIndex][0])
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
tm1637_InitDisplay(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex]);
|
||||
int tm1637_bright = Settings.TaskDevicePluginConfig[event->TaskIndex][2] / 2;
|
||||
tm1637_SetPowerBrightness(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex], tm1637_bright, true);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
max7219_InitDisplay(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex], Settings.TaskDevicePin3[event->TaskIndex]);
|
||||
max7219_SetPowerBrightness(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex], Settings.TaskDevicePin3[event->TaskIndex], Settings.TaskDevicePluginConfig[event->TaskIndex][2], true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WRITE:
|
||||
{
|
||||
if (!Plugin_073_7dgt)
|
||||
break;
|
||||
|
||||
String tmpString = string;
|
||||
int argIndex = tmpString.indexOf(',');
|
||||
if (argIndex)
|
||||
tmpString = tmpString.substring(0, argIndex);
|
||||
|
||||
String tmpStr = string;
|
||||
int comma1 = tmpStr.indexOf(',');
|
||||
|
||||
if (tmpString.equalsIgnoreCase(F("7dn"))) {
|
||||
if (Plugin_073_7dgt->output != 0)
|
||||
break;
|
||||
String log = F("7DGT : Show Number=");
|
||||
log += event->Par1;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
switch (Plugin_073_7dgt->type)
|
||||
{
|
||||
case 0:
|
||||
if (event->Par1 > -1000 && event->Par1 < 10000)
|
||||
p073_FillBufferWithNumber(String(int(event->Par1)));
|
||||
else
|
||||
p073_FillBufferWithDash();
|
||||
tm1637_ShowBuffer(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, TM1637_4DIGIT);
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
if (event->Par1 > -1000 && event->Par1 < 10000)
|
||||
p073_FillBufferWithNumber(tmpStr.substring(comma1+1).c_str());
|
||||
else
|
||||
p073_FillBufferWithDash();
|
||||
tm1637_ShowBuffer(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, TM1637_4DIGIT);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (event->Par1 > -100000 && event->Par1 < 1000000)
|
||||
p073_FillBufferWithNumber(tmpStr.substring(comma1+1).c_str());
|
||||
else
|
||||
p073_FillBufferWithDash();
|
||||
tm1637_SwapDigitInBuffer(); // only needed for 6-digits displays
|
||||
tm1637_ShowBuffer(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, TM1637_6DIGIT);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
if (comma1 > 0) {
|
||||
if (event->Par1 > -10000000 && event->Par1 < 100000000) {
|
||||
p073_FillBufferWithNumber(tmpStr.substring(comma1+1).c_str());
|
||||
}
|
||||
else
|
||||
p073_FillBufferWithDash();
|
||||
max7219_ShowBuffer(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, Plugin_073_7dgt->pin3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
} else if (tmpString.equalsIgnoreCase(F("7dt"))) {
|
||||
if (Plugin_073_7dgt->output != 0)
|
||||
break;
|
||||
double p073_temptemp = 0;
|
||||
bool p073_tempflagdot = false;
|
||||
if (comma1 > 0)
|
||||
p073_temptemp = atof(tmpStr.substring(comma1+1).c_str());
|
||||
String log = F("7DGT : Show Temperature=");
|
||||
log += p073_temptemp;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
switch (Plugin_073_7dgt->type)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
{
|
||||
if (p073_temptemp > 999 || p073_temptemp < -99.9)
|
||||
p073_FillBufferWithDash();
|
||||
else {
|
||||
if (p073_temptemp < 100 && p073_temptemp > -10) {
|
||||
p073_temptemp = int(p073_temptemp*10);
|
||||
p073_tempflagdot = true;
|
||||
}
|
||||
p073_FillBufferWithTemp(p073_temptemp);
|
||||
if (p073_temptemp == 0 && p073_tempflagdot)
|
||||
p073_showbuffer[5] = 0;
|
||||
}
|
||||
tm1637_ShowTimeTemp4(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, p073_tempflagdot, 4);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (p073_temptemp > 999 || p073_temptemp < -99.9)
|
||||
p073_FillBufferWithDash();
|
||||
else {
|
||||
if (p073_temptemp < 100 && p073_temptemp > -10) {
|
||||
p073_temptemp = int(p073_temptemp*10);
|
||||
p073_tempflagdot = true;
|
||||
}
|
||||
p073_FillBufferWithTemp(p073_temptemp);
|
||||
if (p073_temptemp == 0 && p073_tempflagdot)
|
||||
p073_showbuffer[5] = 0;
|
||||
}
|
||||
tm1637_ShowTemp6(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, p073_tempflagdot);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
p073_temptemp = int(p073_temptemp*10);
|
||||
p073_FillBufferWithTemp(p073_temptemp);
|
||||
if (p073_temptemp == 0)
|
||||
p073_showbuffer[5] = 0;
|
||||
max7219_ShowTemp(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, Plugin_073_7dgt->pin3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
success = true;
|
||||
} else {
|
||||
bool p073_validcmd = false;
|
||||
bool p073_displayon;
|
||||
if (tmpString.equalsIgnoreCase(F("7don"))) {
|
||||
String log = F("7DGT : Display ON");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
p073_displayon = true;
|
||||
p073_validcmd = true;
|
||||
}
|
||||
else if (tmpString.equalsIgnoreCase(F("7doff"))) {
|
||||
String log = F("7DGT : Display OFF");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
p073_displayon = false;
|
||||
p073_validcmd = true;
|
||||
}
|
||||
else if (tmpString.equalsIgnoreCase(F("7db"))) {
|
||||
if (event->Par1 >= 0 && event->Par1 < 16) {
|
||||
String log = F("7DGT : Brightness=");
|
||||
log += event->Par1;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
Plugin_073_7dgt->brightness = event->Par1;
|
||||
p073_displayon = true;
|
||||
p073_validcmd = true;
|
||||
}
|
||||
}
|
||||
if (p073_validcmd) {
|
||||
success = true;
|
||||
switch (Plugin_073_7dgt->type)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
{ int tm1637_bright = Plugin_073_7dgt->brightness / 2;
|
||||
tm1637_SetPowerBrightness(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, tm1637_bright, p073_displayon);
|
||||
break; }
|
||||
case 3:
|
||||
{ max7219_SetPowerBrightness(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, Plugin_073_7dgt->pin3, Plugin_073_7dgt->brightness, p073_displayon);
|
||||
break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_ONCE_A_SECOND:
|
||||
{
|
||||
if (Plugin_073_7dgt->output == 0)
|
||||
break;
|
||||
|
||||
if (Plugin_073_7dgt->output == 1)
|
||||
{ Plugin_073_7dgt->timesep = !Plugin_073_7dgt->timesep; }
|
||||
else
|
||||
{ Plugin_073_7dgt->timesep = true; }
|
||||
|
||||
if (Plugin_073_7dgt->output == 3)
|
||||
p073_FillBufferWithDate();
|
||||
else
|
||||
p073_FillBufferWithTime();
|
||||
|
||||
switch (Plugin_073_7dgt->type)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
{
|
||||
tm1637_ShowTimeTemp4(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, Plugin_073_7dgt->timesep, 0);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 3)
|
||||
tm1637_ShowDate6(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, Plugin_073_7dgt->timesep);
|
||||
else
|
||||
tm1637_ShowTime6(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, Plugin_073_7dgt->timesep);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 3)
|
||||
max7219_ShowDate(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, Plugin_073_7dgt->pin3);
|
||||
else
|
||||
max7219_ShowTime(Plugin_073_7dgt->pin1, Plugin_073_7dgt->pin2, Plugin_073_7dgt->pin3, Plugin_073_7dgt->timesep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void p073_FillBufferWithTime()
|
||||
{
|
||||
memset(p073_showbuffer,0,sizeof(p073_showbuffer));
|
||||
byte sevendgt_hours = hour();
|
||||
byte sevendgt_minutes = minute();
|
||||
byte sevendgt_seconds = second();
|
||||
uint8_t p073_digit1, p073_digit2;
|
||||
p073_digit1 = (uint8_t)(sevendgt_hours / 10);
|
||||
p073_digit2 = sevendgt_hours - p073_digit1*10;
|
||||
p073_showbuffer[0] = p073_digit1; p073_showbuffer[1] = p073_digit2;
|
||||
p073_digit1 = (uint8_t)(sevendgt_minutes / 10);
|
||||
p073_digit2 = sevendgt_minutes - p073_digit1*10;
|
||||
p073_showbuffer[2] = p073_digit1; p073_showbuffer[3] = p073_digit2;
|
||||
p073_digit1 = (uint8_t)(sevendgt_seconds / 10);
|
||||
p073_digit2 = sevendgt_seconds - p073_digit1*10;
|
||||
p073_showbuffer[4] = p073_digit1; p073_showbuffer[5] = p073_digit2;
|
||||
}
|
||||
|
||||
void p073_FillBufferWithDate()
|
||||
{
|
||||
memset(p073_showbuffer,0,sizeof(p073_showbuffer));
|
||||
byte sevendgt_day = day();
|
||||
byte sevendgt_month = month();
|
||||
byte sevendgt_year1 = uint8_t(year()/100);
|
||||
byte sevendgt_year2 = uint8_t(year()-(sevendgt_year1*100));
|
||||
uint8_t p073_digit1, p073_digit2;
|
||||
p073_digit1 = (uint8_t)(sevendgt_day / 10);
|
||||
p073_digit2 = sevendgt_day - p073_digit1*10;
|
||||
p073_showbuffer[0] = p073_digit1; p073_showbuffer[1] = p073_digit2;
|
||||
p073_digit1 = (uint8_t)(sevendgt_month / 10);
|
||||
p073_digit2 = sevendgt_month - p073_digit1*10;
|
||||
p073_showbuffer[2] = p073_digit1; p073_showbuffer[3] = p073_digit2;
|
||||
p073_digit1 = (uint8_t)(sevendgt_year1 / 10);
|
||||
p073_digit2 = sevendgt_year1 - p073_digit1*10;
|
||||
p073_showbuffer[4] = p073_digit1; p073_showbuffer[5] = p073_digit2;
|
||||
p073_digit1 = (uint8_t)(sevendgt_year2 / 10);
|
||||
p073_digit2 = sevendgt_year2 - p073_digit1*10;
|
||||
p073_showbuffer[6] = p073_digit1; p073_showbuffer[7] = p073_digit2;
|
||||
}
|
||||
|
||||
void p073_FillBufferWithNumber(String number)
|
||||
{
|
||||
memset(p073_showbuffer,10,sizeof(p073_showbuffer));
|
||||
byte p073_numlenght = number.length();
|
||||
byte p073_dispdigit;
|
||||
byte p073_index = 7;
|
||||
p073_dotpos = -1; // -1 means no dot to display
|
||||
for (int i=p073_numlenght;i>0;i--) {
|
||||
char p073_tmpchar = number.charAt(i-1);
|
||||
p073_dispdigit = 10; // default is space
|
||||
if (p073_tmpchar > 47 && p073_tmpchar < 58)
|
||||
p073_dispdigit = p073_tmpchar-48;
|
||||
else if (p073_tmpchar == 32) // space
|
||||
p073_dispdigit = 10;
|
||||
else if (p073_tmpchar == 45) // minus
|
||||
p073_dispdigit = 11;
|
||||
if (p073_tmpchar == 46) // dot
|
||||
p073_dotpos = p073_index;
|
||||
else {
|
||||
p073_showbuffer[p073_index] = p073_dispdigit;
|
||||
p073_index--; }
|
||||
}
|
||||
}
|
||||
|
||||
void p073_FillBufferWithTemp(long temperature)
|
||||
{
|
||||
memset(p073_showbuffer,10,sizeof(p073_showbuffer));
|
||||
char p073_digit[8];
|
||||
sprintf(p073_digit, "%7d", static_cast<int>(temperature));
|
||||
int p073_numlenght = strlen(p073_digit);
|
||||
byte p073_dispdigit;
|
||||
for (int i=0;i<p073_numlenght;i++) {
|
||||
if (p073_digit[i] > 47 && p073_digit[i] < 58)
|
||||
p073_dispdigit = p073_digit[i]-48;
|
||||
else if (p073_digit[i] == 32) // space
|
||||
p073_dispdigit = 10;
|
||||
else if (p073_digit[i] == 45) // minus
|
||||
p073_dispdigit = 11;
|
||||
p073_showbuffer[i] = p073_dispdigit;
|
||||
}
|
||||
p073_showbuffer[7] = 12; // degree "°"
|
||||
}
|
||||
|
||||
void p073_FillBufferWithDash() // in case of error show all dashes
|
||||
{
|
||||
memset(p073_showbuffer,11,sizeof(p073_showbuffer));
|
||||
}
|
||||
|
||||
//===================================
|
||||
//---- TM1637 specific functions ----
|
||||
//===================================
|
||||
|
||||
#define CLK_HIGH() digitalWrite(clk_pin, HIGH)
|
||||
#define CLK_LOW() digitalWrite(clk_pin, LOW)
|
||||
#define DIO_HIGH() pinMode(dio_pin, INPUT)
|
||||
#define DIO_LOW() pinMode(dio_pin, OUTPUT)
|
||||
|
||||
void tm1637_i2cStart (uint8_t clk_pin, uint8_t dio_pin)
|
||||
{
|
||||
if (PLUGIN_073_DEBUG) {
|
||||
String log = F("7DGT : Comm Start");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
DIO_HIGH();
|
||||
CLK_HIGH();
|
||||
delayMicroseconds(TM1637_CLOCKDELAY);
|
||||
DIO_LOW();
|
||||
}
|
||||
|
||||
void tm1637_i2cStop (uint8_t clk_pin, uint8_t dio_pin)
|
||||
{
|
||||
if (PLUGIN_073_DEBUG) {
|
||||
String log = F("7DGT : Comm Stop");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
CLK_LOW();
|
||||
delayMicroseconds(TM1637_CLOCKDELAY);
|
||||
DIO_LOW();
|
||||
delayMicroseconds(TM1637_CLOCKDELAY);
|
||||
CLK_HIGH();
|
||||
delayMicroseconds(TM1637_CLOCKDELAY);
|
||||
DIO_HIGH();
|
||||
}
|
||||
|
||||
void tm1637_i2cAck (uint8_t clk_pin, uint8_t dio_pin)
|
||||
{
|
||||
bool dummyAck = false;
|
||||
CLK_LOW();
|
||||
pinMode(dio_pin, INPUT_PULLUP);
|
||||
//DIO_HIGH();
|
||||
delayMicroseconds(TM1637_CLOCKDELAY);
|
||||
//while(digitalRead(dio_pin));
|
||||
dummyAck = digitalRead(dio_pin);
|
||||
if (PLUGIN_073_DEBUG) {
|
||||
String log = F("7DGT : Comm ACK=");
|
||||
if (dummyAck == 0) { log += F("TRUE"); } else { log += F("FALSE"); }
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
CLK_HIGH();
|
||||
delayMicroseconds(TM1637_CLOCKDELAY);
|
||||
CLK_LOW();
|
||||
pinMode(dio_pin, OUTPUT);
|
||||
}
|
||||
|
||||
void tm1637_i2cWrite (uint8_t clk_pin, uint8_t dio_pin, uint8_t bytetoprint)
|
||||
{
|
||||
if (PLUGIN_073_DEBUG) {
|
||||
String log = F("7DGT : WriteByte");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
uint8_t i;
|
||||
for(i=0; i<8; i++)
|
||||
{
|
||||
CLK_LOW();
|
||||
(bytetoprint & B00000001)? DIO_HIGH() : DIO_LOW();
|
||||
delayMicroseconds(TM1637_CLOCKDELAY);
|
||||
bytetoprint = bytetoprint >> 1;
|
||||
CLK_HIGH();
|
||||
delayMicroseconds(TM1637_CLOCKDELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void tm1637_ClearDisplay (uint8_t clk_pin, uint8_t dio_pin)
|
||||
{
|
||||
tm1637_i2cStart(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0xC0); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cStop(clk_pin, dio_pin);
|
||||
}
|
||||
|
||||
void tm1637_SetPowerBrightness (uint8_t clk_pin, uint8_t dio_pin, uint8_t brightlvl, bool poweron)
|
||||
{
|
||||
if (PLUGIN_073_DEBUG) {
|
||||
String log = F("7DGT : Set BRIGHT");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
uint8_t brightvalue = (brightlvl & 0b111);
|
||||
if (poweron)
|
||||
brightvalue = TM1637_POWER_ON | brightvalue;
|
||||
else
|
||||
brightvalue = TM1637_POWER_OFF | brightvalue;
|
||||
tm1637_i2cStart(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, brightvalue);
|
||||
tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cStop(clk_pin, dio_pin);
|
||||
}
|
||||
|
||||
void tm1637_InitDisplay(uint8_t clk_pin, uint8_t dio_pin)
|
||||
{
|
||||
pinMode(clk_pin, OUTPUT);
|
||||
pinMode(dio_pin, OUTPUT);
|
||||
CLK_HIGH();
|
||||
DIO_HIGH();
|
||||
// pinMode(dio_pin, INPUT_PULLUP);
|
||||
// pinMode(clk_pin, OUTPUT);
|
||||
tm1637_i2cStart(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0x40);
|
||||
tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cStop(clk_pin, dio_pin);
|
||||
tm1637_ClearDisplay(clk_pin, dio_pin);
|
||||
}
|
||||
|
||||
void tm1637_ShowTime6(uint8_t clk_pin, uint8_t dio_pin, bool sep)
|
||||
{
|
||||
byte p073_datashowpos1;
|
||||
tm1637_i2cStart(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0xC0); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[2]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
// add bit for colon on second digit if required
|
||||
p073_datashowpos1 = CharTableTM1637[p073_showbuffer[1]];
|
||||
if (sep) p073_datashowpos1 |= 0b10000000;
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, p073_datashowpos1); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[0]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[5]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[4]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
// add bit for colon on fourth digit if required
|
||||
p073_datashowpos1 = CharTableTM1637[p073_showbuffer[3]];
|
||||
if (sep) p073_datashowpos1 |= 0b10000000;
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, p073_datashowpos1); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cStop(clk_pin, dio_pin);
|
||||
}
|
||||
|
||||
void tm1637_ShowDate6(uint8_t clk_pin, uint8_t dio_pin, bool sep)
|
||||
{
|
||||
byte p073_datashowpos1;
|
||||
tm1637_i2cStart(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0xC0); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[2]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
// add bit for colon on second digit if required
|
||||
p073_datashowpos1 = CharTableTM1637[p073_showbuffer[1]];
|
||||
if (sep) p073_datashowpos1 |= 0b10000000;
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, p073_datashowpos1); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[0]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[7]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[6]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
// add bit for colon on fourth digit if required
|
||||
p073_datashowpos1 = CharTableTM1637[p073_showbuffer[3]];
|
||||
if (sep) p073_datashowpos1 |= 0b10000000;
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, p073_datashowpos1); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cStop(clk_pin, dio_pin);
|
||||
}
|
||||
|
||||
void tm1637_ShowTemp6(uint8_t clk_pin, uint8_t dio_pin, bool sep)
|
||||
{
|
||||
tm1637_i2cStart(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0xC0); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
// add bit for colon on second digit if required
|
||||
byte p073_datashowpos1 = CharTableTM1637[p073_showbuffer[5]];
|
||||
if (sep) p073_datashowpos1 |= 0b10000000;
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, p073_datashowpos1); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[4]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[10]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[10]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[7]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[6]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cStop(clk_pin, dio_pin);
|
||||
}
|
||||
|
||||
void tm1637_ShowTimeTemp4(uint8_t clk_pin, uint8_t dio_pin, bool sep, byte bufoffset)
|
||||
{
|
||||
tm1637_i2cStart(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0xC0); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[0+bufoffset]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
// add bit for colon on second digit if required
|
||||
byte p073_datashowpos1 = CharTableTM1637[p073_showbuffer[1+bufoffset]];
|
||||
if (sep) p073_datashowpos1 |= 0b10000000;
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, p073_datashowpos1); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[2+bufoffset]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, CharTableTM1637[p073_showbuffer[3+bufoffset]]); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
tm1637_i2cStop(clk_pin, dio_pin);
|
||||
}
|
||||
|
||||
void tm1637_SwapDigitInBuffer() {
|
||||
uint8_t p073_temp;
|
||||
p073_temp = p073_showbuffer[4]; p073_showbuffer[4] = p073_showbuffer[2]; p073_showbuffer[2] = p073_temp;
|
||||
p073_temp = p073_showbuffer[5]; p073_showbuffer[5] = p073_showbuffer[7]; p073_showbuffer[7] = p073_temp;
|
||||
switch (p073_dotpos)
|
||||
{
|
||||
case 2: { p073_dotpos = 4; break; }
|
||||
case 4: { p073_dotpos = 2; break; }
|
||||
case 5: { p073_dotpos = 7; break; }
|
||||
case 7: { p073_dotpos = 5; break; }
|
||||
}
|
||||
}
|
||||
|
||||
void tm1637_ShowBuffer(uint8_t clk_pin, uint8_t dio_pin, byte digits)
|
||||
{
|
||||
byte p073_datashowpos1;
|
||||
tm1637_i2cStart(clk_pin, dio_pin);
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, 0xC0); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
for(int i=digits;i<8;i++) {
|
||||
p073_datashowpos1 = CharTableTM1637[p073_showbuffer[i]];
|
||||
if (p073_dotpos == i) p073_datashowpos1 |= 0b10000000;
|
||||
tm1637_i2cWrite(clk_pin, dio_pin, p073_datashowpos1); tm1637_i2cAck(clk_pin, dio_pin);
|
||||
}
|
||||
tm1637_i2cStop(clk_pin, dio_pin);
|
||||
}
|
||||
|
||||
//====================================
|
||||
//---- MAX7219 specific functions ----
|
||||
//====================================
|
||||
|
||||
#define OP_DECODEMODE 9
|
||||
#define OP_INTENSITY 10
|
||||
#define OP_SCANLIMIT 11
|
||||
#define OP_SHUTDOWN 12
|
||||
#define OP_DISPLAYTEST 15
|
||||
|
||||
void max7219_spiTransfer (uint8_t din_pin, uint8_t clk_pin, uint8_t cs_pin, volatile byte opcode, volatile byte data)
|
||||
{
|
||||
p073_spidata[0]=(byte)0; p073_spidata[1]=(byte)0;
|
||||
p073_spidata[1]=opcode; p073_spidata[0]=data;
|
||||
digitalWrite(cs_pin,LOW);
|
||||
shiftOut(din_pin,clk_pin,MSBFIRST,p073_spidata[1]);
|
||||
shiftOut(din_pin,clk_pin,MSBFIRST,p073_spidata[0]);
|
||||
digitalWrite(cs_pin,HIGH);
|
||||
}
|
||||
|
||||
void max7219_ClearDisplay (uint8_t din_pin, uint8_t clk_pin, uint8_t cs_pin)
|
||||
{
|
||||
for(int i=0;i<8;i++) {
|
||||
max7219_spiTransfer(din_pin, clk_pin, cs_pin, i+1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void max7219_SetPowerBrightness (uint8_t din_pin, uint8_t clk_pin, uint8_t cs_pin, uint8_t brightlvl, bool poweron)
|
||||
{
|
||||
max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_INTENSITY, brightlvl);
|
||||
if (poweron)
|
||||
max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_SHUTDOWN, 1);
|
||||
else
|
||||
max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_SHUTDOWN, 0);
|
||||
}
|
||||
|
||||
void max7219_SetDigit(uint8_t din_pin, uint8_t clk_pin, uint8_t cs_pin, int dgtpos, byte dgtvalue, boolean showdot)
|
||||
{
|
||||
byte p073_tempvalue;
|
||||
p073_tempvalue = CharTableMAX7219[dgtvalue];
|
||||
if(showdot)
|
||||
p073_tempvalue |= 0b10000000;
|
||||
max7219_spiTransfer(din_pin, clk_pin, cs_pin, dgtpos+1, p073_tempvalue);
|
||||
}
|
||||
|
||||
void max7219_InitDisplay(uint8_t din_pin, uint8_t clk_pin, uint8_t cs_pin)
|
||||
{
|
||||
pinMode(din_pin, OUTPUT);
|
||||
pinMode(clk_pin, OUTPUT);
|
||||
pinMode(cs_pin, OUTPUT);
|
||||
digitalWrite(cs_pin, HIGH);
|
||||
max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_DISPLAYTEST, 0);
|
||||
max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_SCANLIMIT, 7); // scanlimit setup to max at Init
|
||||
max7219_spiTransfer(din_pin, clk_pin, cs_pin, OP_DECODEMODE, 0);
|
||||
max7219_ClearDisplay(din_pin, clk_pin, cs_pin);
|
||||
max7219_SetPowerBrightness(din_pin, clk_pin, cs_pin,0,false);
|
||||
}
|
||||
|
||||
void max7219_ShowTime(uint8_t din_pin, uint8_t clk_pin, uint8_t cs_pin, bool sep)
|
||||
{
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, 0, p073_showbuffer[5], false);
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, 1, p073_showbuffer[4], false);
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, 3, p073_showbuffer[3], false);
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, 4, p073_showbuffer[2], false);
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, 6, p073_showbuffer[1], false);
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, 7, p073_showbuffer[0], false);
|
||||
if (sep) {
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, 2, 11, false);
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, 5, 11, false);
|
||||
}
|
||||
else {
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, 2, 10, false);
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, 5, 10, false);
|
||||
}
|
||||
}
|
||||
|
||||
void max7219_ShowTemp(uint8_t din_pin, uint8_t clk_pin, uint8_t cs_pin)
|
||||
{
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, 0, 10, false);
|
||||
byte dotflags[8] = {false,false,false,false,false,true,false,false};
|
||||
for(int i=1;i<8;i++)
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, i, p073_showbuffer[8-i], dotflags[8-i]);
|
||||
}
|
||||
|
||||
void max7219_ShowDate(uint8_t din_pin, uint8_t clk_pin, uint8_t cs_pin)
|
||||
{
|
||||
byte dotflags[8] = {false,true,false,true,false,false,false,false};
|
||||
for(int i=0;i<8;i++)
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, i, p073_showbuffer[7-i], dotflags[7-i]);
|
||||
}
|
||||
|
||||
void max7219_ShowBuffer(uint8_t din_pin, uint8_t clk_pin, uint8_t cs_pin)
|
||||
{
|
||||
byte dotflags[8] = {false,false,false,false,false,false,false,false};
|
||||
if (p073_dotpos >= 0) dotflags[p073_dotpos] = true;
|
||||
for(int i=0;i<8;i++)
|
||||
max7219_SetDigit(din_pin, clk_pin, cs_pin, i, p073_showbuffer[7-i], dotflags[7-i]);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -133,6 +133,7 @@ void CPluginInit(void)
|
||||
#endif
|
||||
|
||||
CPluginCall(CPLUGIN_PROTOCOL_ADD, 0);
|
||||
CPluginCall(CPLUGIN_INIT, 0);
|
||||
}
|
||||
|
||||
byte CPluginCall(byte Function, struct EventStruct *event)
|
||||
@@ -152,11 +153,32 @@ byte CPluginCall(byte Function, struct EventStruct *event)
|
||||
CPlugin_ptr[x](Function, event, dummyString);
|
||||
return true;
|
||||
break;
|
||||
|
||||
// calls to active plugins
|
||||
case CPLUGIN_INIT:
|
||||
case CPLUGIN_UDP_IN:
|
||||
for (byte x=0; x < CONTROLLER_MAX; x++)
|
||||
if (Settings.Protocol[x] != 0 && Settings.ControllerEnabled[x]) {
|
||||
event->ProtocolIndex = getProtocolIndex(Settings.Protocol[x]);
|
||||
CPlugin_ptr[event->ProtocolIndex](Function, event, dummyString);
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if there is any controller enabled.
|
||||
bool anyControllerEnabled() {
|
||||
for (byte i=0; i < CONTROLLER_MAX; i++) {
|
||||
if (Settings.Protocol[i] != 0 && Settings.ControllerEnabled[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find first enabled controller index with this protocol
|
||||
byte findFirstEnabledControllerWithId(byte cpluginid) {
|
||||
for (byte i=0; i < CONTROLLER_MAX; i++) {
|
||||
|
||||
+7
-7
@@ -5,7 +5,7 @@ nodes=[
|
||||
'port' : '/dev/serial/by-path/pci-0000:00:14.0-usb-0:3.1:1.0-port0',
|
||||
'ip' : '192.168.13.91',
|
||||
'flash_cmd' : 'esptool.py --port {port} -b 1500000 write_flash 0x0 .pioenvs/dev_ESP8266_4096/firmware.bin --flash_size=32m -p',
|
||||
'build_cmd' : 'platformio run --environment dev_ESP8266_4096'
|
||||
'build_cmd' : 'platformio run --environment dev_ESP8266_4096 -s'
|
||||
},
|
||||
|
||||
# node 1
|
||||
@@ -14,16 +14,16 @@ nodes=[
|
||||
'port' : '/dev/serial/by-path/pci-0000:00:14.0-usb-0:3.2:1.0-port0',
|
||||
'ip' : '192.168.13.92',
|
||||
'flash_cmd' : 'esptool.py --port {port} -b 1500000 write_flash 0x0 .pioenvs/dev_ESP8266_4096/firmware.bin --flash_size=32m -p',
|
||||
'build_cmd' : 'platformio run --environment dev_ESP8266_4096'
|
||||
'build_cmd' : 'platformio run --environment dev_ESP8266_4096 -s'
|
||||
},
|
||||
|
||||
# node 2
|
||||
{
|
||||
'type' : 'ESP-01S 1Mb PUYA flash',
|
||||
'port' : '/dev/serial/by-path/pci-0000:00:14.0-usb-0:3.3:1.0-port0',
|
||||
'ip' : '192.168.13.92',
|
||||
'flash_cmd' : 'esptool.py --port {port} -b 1500000 write_flash 0x0 .pioenvs/dev_ESP8266_1024/firmware.bin --flash_size=detect -p',
|
||||
'build_cmd' : 'platformio run --environment dev_ESP8266_1024'
|
||||
'ip' : '192.168.13.93',
|
||||
'flash_cmd' : 'esptool.py --port {port} -b 115200 write_flash 0x0 .pioenvs/dev_ESP8266PUYA_1024/firmware.bin --flash_size=1MB -p',
|
||||
'build_cmd' : 'platformio run --environment dev_ESP8266PUYA_1024 -s'
|
||||
},
|
||||
|
||||
# {
|
||||
@@ -39,10 +39,10 @@ nodes=[
|
||||
|
||||
|
||||
#an mqtt broker that both ESPEasy and the test suite are connecting to
|
||||
mqtt_broker="192.168.13.236"
|
||||
mqtt_broker="192.168.13.159"
|
||||
mqtt_port=1883
|
||||
|
||||
#ip of the server running this script
|
||||
test_server="192.168.13.236"
|
||||
test_server="192.168.13.159"
|
||||
http_port=8080
|
||||
linebased_port=8181
|
||||
|
||||
+17
-12
@@ -29,6 +29,7 @@ class ControllerEmu:
|
||||
self.start_mqtt()
|
||||
self.start_http()
|
||||
self.start_linebased()
|
||||
self.log_enabled=True
|
||||
|
||||
|
||||
def start_mqtt(self):
|
||||
@@ -44,8 +45,9 @@ class ControllerEmu:
|
||||
|
||||
self.mqtt_messages=Queue()
|
||||
def mqtt_on_message(client, userdata, message):
|
||||
logging.getLogger("mqtt").debug("Received message '" + str(message.payload) + "' on topic '"
|
||||
+ message.topic + "' with QoS " + str(message.qos))
|
||||
if self.log_enabled:
|
||||
logging.getLogger("mqtt").debug("Received message '" + str(message.payload) + "' on topic '"
|
||||
+ message.topic + "' with QoS " + str(message.qos))
|
||||
self.mqtt_messages.put(message)
|
||||
|
||||
mqtt_client.on_message=mqtt_on_message
|
||||
@@ -66,12 +68,12 @@ class ControllerEmu:
|
||||
@bottle.post('<filename:path>')
|
||||
@bottle.get('<filename:path>')
|
||||
def urlhandler(filename):
|
||||
logging.getLogger("http").debug(bottle.request.method+" "+str(dict(bottle.request.params)))
|
||||
if self.log_enabled:
|
||||
logging.getLogger("http").debug(bottle.request.method+" "+str(dict(bottle.request.params)))
|
||||
self.http_requests.put(bottle.request.copy())
|
||||
|
||||
|
||||
|
||||
http_thread=threading.Thread(target=bottle.run, kwargs=dict(host='0.0.0.0', port=config.http_port, reloader=False))
|
||||
http_thread=threading.Thread(target=bottle.run, kwargs=dict(host='0.0.0.0', port=config.http_port, reloader=False, quiet=True))
|
||||
http_thread.daemon=True
|
||||
http_thread.start()
|
||||
|
||||
@@ -92,15 +94,18 @@ class ControllerEmu:
|
||||
|
||||
|
||||
def handle_connect(connection, client_address):
|
||||
logging.getLogger("linebased").debug("Connect from "+str(client_address))
|
||||
if self.log_enabled:
|
||||
logging.getLogger("linebased").debug("Connect from "+str(client_address))
|
||||
|
||||
fh = connection.makefile()
|
||||
for line in fh:
|
||||
line=line.rstrip()
|
||||
logging.getLogger("linebased").debug("Recv from "+str(client_address)+" :"+line)
|
||||
if self.log_enabled:
|
||||
logging.getLogger("linebased").debug("Recv from "+str(client_address)+" :"+line)
|
||||
self.linebased_lines.put( ( client_address, line ) )
|
||||
|
||||
logging.getLogger("linebased").debug("Disconnect from "+str(client_address))
|
||||
if self.log_enabled:
|
||||
logging.getLogger("linebased").debug("Disconnect from "+str(client_address))
|
||||
|
||||
def wait_accept():
|
||||
# Create a TCP/IP socket
|
||||
@@ -166,8 +171,8 @@ class ControllerEmu:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_TEMP_HUM and len(svalues)==3:
|
||||
return [svalues[0], svalues[1]]
|
||||
elif sensor_type==SENSOR_TYPE_TEMP_BARO and len(svalues)==5:
|
||||
return [svalues[0], svalues[3]]
|
||||
elif sensor_type==SENSOR_TYPE_TEMP_BARO and len(svalues)==4:
|
||||
return [svalues[0], svalues[1]]
|
||||
elif sensor_type==SENSOR_TYPE_TRIPLE and len(svalues)==3:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_TEMP_HUM_BARO and len(svalues)==5:
|
||||
@@ -221,8 +226,8 @@ class ControllerEmu:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_TEMP_HUM and len(svalues)==3:
|
||||
return [svalues[0], svalues[1]]
|
||||
elif sensor_type==SENSOR_TYPE_TEMP_BARO and len(svalues)==5:
|
||||
return [svalues[0], svalues[3]]
|
||||
elif sensor_type==SENSOR_TYPE_TEMP_BARO and len(svalues)==4:
|
||||
return [svalues[0], svalues[1]]
|
||||
elif sensor_type==SENSOR_TYPE_TRIPLE and len(svalues)==3:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_TEMP_HUM_BARO and len(svalues)==5:
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ Configure node 0, controller 1 as domoticz mqtt:
|
||||
"""
|
||||
return(docs)
|
||||
|
||||
parser = argparse.ArgumentParser(description='ESPEasy testing framework', epilog=get_epilog(), formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser = argparse.ArgumentParser(description='ESPEasy testing CLI', epilog=get_epilog(), formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
|
||||
# parser.add_argument('--url', default='http://localhost:8080/rpc', help='url of rpc server to connect to. default: %(default)s')
|
||||
# parser.add_argument('--user', default=None, help='user to login.')
|
||||
|
||||
@@ -8,5 +8,4 @@ import config
|
||||
|
||||
colorlog.basicConfig(level=logging.DEBUG)
|
||||
|
||||
|
||||
logging.getLogger("requests.packages.urllib3.connectionpool").setLevel(logging.ERROR)
|
||||
|
||||
+15
-2
@@ -13,7 +13,20 @@ import config
|
||||
import shelve
|
||||
import os
|
||||
from espcore import *
|
||||
import argparse
|
||||
import util
|
||||
|
||||
### parse arguments
|
||||
|
||||
parser = argparse.ArgumentParser(description='ESPEasy testing framework', formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.add_argument('--debug', action='store_true', help='enable http debugging output')
|
||||
parser.add_argument('--no-resume', action='store_true', help='dont resume testing from where we left off last time')
|
||||
parser.add_argument('--skip-power', action='store_true', help='skip tests that require powercycling.')
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
if args.debug:
|
||||
util.enable_http_debug()
|
||||
|
||||
|
||||
### create node objects and espeasy objects
|
||||
@@ -22,7 +35,7 @@ node=[]
|
||||
espeasy=[]
|
||||
|
||||
for n in config.nodes:
|
||||
node.append(Node(n, "node"+str(len(node))))
|
||||
node.append(Node(n, "node"+str(len(node)), skip_power=args.skip_power))
|
||||
espeasy.append(EspEasy(node[-1]))
|
||||
|
||||
|
||||
@@ -49,7 +62,7 @@ with shelve.open("test.state") as shelve_db:
|
||||
def step(title=""):
|
||||
def step_dec(test):
|
||||
"""add test step. test can resume from every test-step"""
|
||||
if state['module'] and ( state['module'] != test.__module__ or state['name'] != test.__name__ or state['title'] != title):
|
||||
if not args.no_resume and state['module'] and ( state['module'] != test.__module__ or state['name'] != test.__name__ or state['title'] != title):
|
||||
log.debug("Skipping step "+title+": "+test.__module__ + "." + test.__name__ )
|
||||
else:
|
||||
state['module']=None
|
||||
|
||||
+21
-1
@@ -16,13 +16,14 @@ from espcore import *
|
||||
class Node():
|
||||
|
||||
|
||||
def __init__(self, config, id):
|
||||
def __init__(self, config, id, skip_power=False):
|
||||
self.log=logging.getLogger(id)
|
||||
self.log.debug("{type} has ip {ip}".format(id=id, **config))
|
||||
self._config=config
|
||||
self._id=id
|
||||
self._url="http://{ip}/".format(**self._config)
|
||||
self._serial_initialized=False
|
||||
self._skip_power=True
|
||||
|
||||
def serial_needed(self):
|
||||
"""call this at least once if you need serial stuff"""
|
||||
@@ -63,12 +64,21 @@ class Node():
|
||||
|
||||
def powercycle(self):
|
||||
"""powercycle the device"""
|
||||
if self._skip_power:
|
||||
self.log.warning("Skipping power cycle "+self._id)
|
||||
return False
|
||||
|
||||
|
||||
self.poweroff()
|
||||
self.poweron()
|
||||
return True
|
||||
|
||||
def poweroff(self):
|
||||
"""power off device"""
|
||||
|
||||
if self._skip_power:
|
||||
self.log.warning("Skipping power off "+self._id)
|
||||
return False
|
||||
|
||||
#cant yet be done automaticly unfortunatly
|
||||
self.log.info("Please power off node "+self._id)
|
||||
@@ -84,10 +94,15 @@ class Node():
|
||||
del self._serial
|
||||
|
||||
self.log.debug("Detected power off")
|
||||
return True
|
||||
|
||||
def poweron(self):
|
||||
"""power on device"""
|
||||
|
||||
if self._skip_power:
|
||||
self.log.warning("Skipping power on"+self._id)
|
||||
return False
|
||||
|
||||
self.log.info("Please power on node "+self._id)
|
||||
|
||||
done=False
|
||||
@@ -100,6 +115,7 @@ class Node():
|
||||
time.sleep(0.1)
|
||||
|
||||
self.log.debug("Detected power on")
|
||||
return True
|
||||
|
||||
def pingwifi(self, timeout=60):
|
||||
"""waits until espeasy reponds via wifi"""
|
||||
@@ -144,6 +160,7 @@ class Node():
|
||||
def build(self):
|
||||
"""compile binary"""
|
||||
|
||||
self.log.debug("Building...")
|
||||
subprocess.check_call(self._config['build_cmd'].format(**self._config), shell=True, cwd='..')
|
||||
|
||||
|
||||
@@ -152,6 +169,7 @@ class Node():
|
||||
|
||||
self.serial_needed()
|
||||
|
||||
self.log.debug("Flashing...")
|
||||
subprocess.check_call(self._config['flash_cmd'].format(**self._config), shell=True, cwd='..')
|
||||
|
||||
time.sleep(1)
|
||||
@@ -162,6 +180,7 @@ class Node():
|
||||
def serial(self):
|
||||
"""open serial terminal to esp"""
|
||||
self.serial_needed()
|
||||
self.log.debug("Opening serial terminal")
|
||||
subprocess.check_call("platformio serialports monitor --baud 115200 --port {port} --echo".format(**self._config), shell=True, cwd='..')
|
||||
# print("JA")
|
||||
# term=serial.tools.miniterm.Miniterm(self._serial)
|
||||
@@ -173,6 +192,7 @@ class Node():
|
||||
def erase(self):
|
||||
"""erase flash via serial"""
|
||||
self.serial_needed()
|
||||
self.log.debug("Erasing...")
|
||||
subprocess.check_call("esptool.py --port {port} -b 1500000 erase_flash".format(**self._config), shell=True, cwd='..')
|
||||
|
||||
|
||||
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from esptest import *
|
||||
|
||||
# hardware requirements:
|
||||
# - all nodes
|
||||
|
||||
# tests:
|
||||
# - builds, flashes and resets to factory defaults
|
||||
|
||||
# prevent confusing messages during build
|
||||
controller.log_enabled=False
|
||||
|
||||
# @step()
|
||||
# def clean():
|
||||
# subprocess.check_call("cd ..;platformio run --target clean -s", shell=True)
|
||||
|
||||
@step()
|
||||
def patch():
|
||||
subprocess.check_call("cd ../patches; ./check_puya_patch", shell=True)
|
||||
|
||||
|
||||
@step()
|
||||
def build():
|
||||
for n in node:
|
||||
n.build()
|
||||
|
||||
|
||||
@step()
|
||||
def erase():
|
||||
for n in node:
|
||||
n.erase()
|
||||
|
||||
@step()
|
||||
def flash():
|
||||
for n in node:
|
||||
n.flashserial()
|
||||
|
||||
@step()
|
||||
def wificonfig():
|
||||
for n in node:
|
||||
n.wificonfig()
|
||||
|
||||
controller.log_enabled=True
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
completed()
|
||||
+3
-1
@@ -65,7 +65,9 @@ def test():
|
||||
@step()
|
||||
def powercycle():
|
||||
"""test result on poweron"""
|
||||
node[0].powercycle()
|
||||
if not node[0].powercycle():
|
||||
return
|
||||
|
||||
results=controller.recv_domoticz_mqtt(SENSOR_TYPE_SINGLE,2001)
|
||||
test_in_range(results[0], -5,40)
|
||||
results=controller.recv_domoticz_mqtt(SENSOR_TYPE_SINGLE,2002)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
#runs all test modules
|
||||
|
||||
import glob
|
||||
import importlib
|
||||
import os
|
||||
|
||||
Reference in New Issue
Block a user