mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-28 04:07:47 +00:00
Compare commits
906
Commits
v2.0
...
mega-20180516
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
083310679c | ||
|
|
2758c80af2 | ||
|
|
4a75b1fa6d | ||
|
|
21d30f0ebe | ||
|
|
16463dff85 | ||
|
|
8e5fb85fa8 | ||
|
|
74f059e639 | ||
|
|
045c50f69f | ||
|
|
a122066e36 | ||
|
|
d3bf64fc4f | ||
|
|
74decbd159 | ||
|
|
b00020de89 | ||
|
|
d9848c1911 | ||
|
|
648353b216 | ||
|
|
f729012ee1 | ||
|
|
87176b453a | ||
|
|
a2270bebbf | ||
|
|
305d729015 | ||
|
|
c31fa71988 | ||
|
|
fba4331213 | ||
|
|
972d24118a | ||
|
|
a885cf1f90 | ||
|
|
56d85814b1 | ||
|
|
c760174c78 | ||
|
|
2c43094a87 | ||
|
|
ee99e9e6f4 | ||
|
|
864e402cc2 | ||
|
|
dff51ba54d | ||
|
|
0eea67d176 | ||
|
|
9139baa6cb | ||
|
|
fdf8a40acf | ||
|
|
547f3643ff | ||
|
|
83d0980248 | ||
|
|
0b1f9a81b5 | ||
|
|
0e8b333f48 | ||
|
|
67098c2539 | ||
|
|
700b14b8ff | ||
|
|
9175cd3a17 | ||
|
|
c16f27af1b | ||
|
|
cc60b8a05d | ||
|
|
d7b46b3395 | ||
|
|
701677274f | ||
|
|
ebfffb8d43 | ||
|
|
f5fd624739 | ||
|
|
abdf011a2d | ||
|
|
4ece42bdc9 | ||
|
|
b0961c15a3 | ||
|
|
70a422bdfd | ||
|
|
5449d82639 | ||
|
|
7e5577b30b | ||
|
|
0d95fd12fe | ||
|
|
b7df21a1d5 | ||
|
|
431b94c587 | ||
|
|
53241f2afc | ||
|
|
076c2c04f1 | ||
|
|
10e912f46f | ||
|
|
c90174712b | ||
|
|
1d71d362b9 | ||
|
|
73fbe04981 | ||
|
|
469735b5fd | ||
|
|
cf13024175 | ||
|
|
eaf6488b0c | ||
|
|
4d067f010f | ||
|
|
e6db005dba | ||
|
|
7a03802c15 | ||
|
|
1e2e750b3b | ||
|
|
50a19692b5 | ||
|
|
b6284f2701 | ||
|
|
b3db6621e2 | ||
|
|
2d32fe3e32 | ||
|
|
241f21b87c | ||
|
|
4f18f81522 | ||
|
|
b860f79e77 | ||
|
|
8966e1680b | ||
|
|
01436201a3 | ||
|
|
1ac94bf6db | ||
|
|
ed66a98e08 | ||
|
|
5a0c2e2353 | ||
|
|
06bc63e385 | ||
|
|
d3ebe3ec46 | ||
|
|
2282288030 | ||
|
|
e5766bee46 | ||
|
|
c5bbfd1b4c | ||
|
|
652ce2f809 | ||
|
|
f3fd3900e5 | ||
|
|
07b726d4b1 | ||
|
|
648d960bf5 | ||
|
|
1829a35df2 | ||
|
|
c5bb6700d9 | ||
|
|
3b2dd86280 | ||
|
|
11563469d0 | ||
|
|
fcea12b515 | ||
|
|
2b72ad2088 | ||
|
|
30acf569e7 | ||
|
|
cb71f73b56 | ||
|
|
521ca465e5 | ||
|
|
ca10c834cc | ||
|
|
ef90c84506 | ||
|
|
3c2f539ec3 | ||
|
|
30419c9932 | ||
|
|
a340b4dedc | ||
|
|
69e4d1ec7a | ||
|
|
91570e9df5 | ||
|
|
53e9a8f4a3 | ||
|
|
71c9b772fe | ||
|
|
3ff96a5bec | ||
|
|
32f8edb1ce | ||
|
|
977611b39c | ||
|
|
52979cafba | ||
|
|
b0a1b95f64 | ||
|
|
04f323b902 | ||
|
|
c20656fe77 | ||
|
|
6d3b2d1b18 | ||
|
|
388b8f4feb | ||
|
|
7b6b72b912 | ||
|
|
5e9ad087b9 | ||
|
|
ca5a1bdba1 | ||
|
|
98522d7cfc | ||
|
|
30ab8aef9e | ||
|
|
22593d7116 | ||
|
|
a8f3ad1be2 | ||
|
|
d54a01a3e6 | ||
|
|
226b3f3d54 | ||
|
|
1e4a0858c1 | ||
|
|
379c4fccd1 | ||
|
|
886d46fd4c | ||
|
|
5184cba646 | ||
|
|
b8c4215a27 | ||
|
|
d1b017b287 | ||
|
|
a5421e816c | ||
|
|
d6ca15671d | ||
|
|
24231cdc56 | ||
|
|
30e192f041 | ||
|
|
38472a3d6b | ||
|
|
d54af04a79 | ||
|
|
056e7a7a40 | ||
|
|
f69e476174 | ||
|
|
b368252db8 | ||
|
|
ea3389f792 | ||
|
|
33b8570c33 | ||
|
|
76ff83e3f4 | ||
|
|
92680c5542 | ||
|
|
e568bbed7c | ||
|
|
82bfadd77a | ||
|
|
b636959cc7 | ||
|
|
2a1f6eebe7 | ||
|
|
b7b8ceebcf | ||
|
|
9f6f39053e | ||
|
|
8eed47393f | ||
|
|
cc0c2c0f8b | ||
|
|
0450d8a106 | ||
|
|
e96de4a988 | ||
|
|
28bdc37d24 | ||
|
|
b7ccba979c | ||
|
|
5132a318af | ||
|
|
cfd27b4918 | ||
|
|
feba82188a | ||
|
|
1a3274d2c2 | ||
|
|
0f04456ae6 | ||
|
|
6016e1b1d3 | ||
|
|
39e391ca0e | ||
|
|
8088ed4ed8 | ||
|
|
13bd7ba26b | ||
|
|
3cb90939c4 | ||
|
|
76cddb7c71 | ||
|
|
3d0f871600 | ||
|
|
ffb3ee4039 | ||
|
|
456796a87d | ||
|
|
bf512f9da0 | ||
|
|
d5b8a36acb | ||
|
|
f09642101f | ||
|
|
cb16773128 | ||
|
|
2e55b6304c | ||
|
|
f61586ebbc | ||
|
|
7f385fc74a | ||
|
|
a579c906d5 | ||
|
|
a80f3a5f0b | ||
|
|
7e10fda7e5 | ||
|
|
16a6135f53 | ||
|
|
343ea459ab | ||
|
|
0ddcee1f07 | ||
|
|
07ac4cf8cf | ||
|
|
a864aeab1e | ||
|
|
35a7ab94df | ||
|
|
44755e83b9 | ||
|
|
f93b38624d | ||
|
|
c1cb7d873c | ||
|
|
62d81325b2 | ||
|
|
5bc2af0e4c | ||
|
|
bc5bf7f3f1 | ||
|
|
0b4013b33c | ||
|
|
3c3a11d77b | ||
|
|
5876fb84af | ||
|
|
25ab07a9ba | ||
|
|
e6044bdbf8 | ||
|
|
572f8bcde7 | ||
|
|
c010640aa5 | ||
|
|
e60c0dc5f0 | ||
|
|
4e6e31fdae | ||
|
|
77deb3d8b3 | ||
|
|
3530027864 | ||
|
|
07bfec4234 | ||
|
|
3476792c58 | ||
|
|
45afaf8d3f | ||
|
|
9084a5542b | ||
|
|
4ac330ebf6 | ||
|
|
49a0476487 | ||
|
|
f606d2c55d | ||
|
|
4f9a383d93 | ||
|
|
d4d0ee3b30 | ||
|
|
9705702f4c | ||
|
|
c3e015342c | ||
|
|
209484554e | ||
|
|
27377ab3ed | ||
|
|
7055d24693 | ||
|
|
62e6317a23 | ||
|
|
29f89b687d | ||
|
|
697d20a028 | ||
|
|
e9df0e75b9 | ||
|
|
f23f49931b | ||
|
|
4af29c405b | ||
|
|
d780f1a07f | ||
|
|
f9be283cb7 | ||
|
|
3f1cda7b81 | ||
|
|
2fd226d6bd | ||
|
|
3d1edcf33e | ||
|
|
cc740b46f1 | ||
|
|
e829058c92 | ||
|
|
685438c35d | ||
|
|
f8a4ef389f | ||
|
|
7e9c31131c | ||
|
|
99150c4214 | ||
|
|
ec7e6f80b0 | ||
|
|
dada682ed6 | ||
|
|
ab31b33a2c | ||
|
|
621585901f | ||
|
|
eaaf1fe888 | ||
|
|
41e4705198 | ||
|
|
c35fe3d500 | ||
|
|
e2da8ecbb9 | ||
|
|
3dad26a58a | ||
|
|
ae930a1d36 | ||
|
|
45e980beda | ||
|
|
8723e177df | ||
|
|
8454994023 | ||
|
|
50732aed8a | ||
|
|
f2888951dc | ||
|
|
56ac640986 | ||
|
|
df2d7be30b | ||
|
|
9e06cf4dc7 | ||
|
|
cd27339b8e | ||
|
|
ec38ba1fb7 | ||
|
|
b8fa42925f | ||
|
|
4169ca0ee8 | ||
|
|
578477bf6d | ||
|
|
0803e946b0 | ||
|
|
06001bbc94 | ||
|
|
f171d5b211 | ||
|
|
360b552424 | ||
|
|
d9597febf8 | ||
|
|
6aa21ea6f8 | ||
|
|
b1de652b62 | ||
|
|
5c3bf9e894 | ||
|
|
0acd7b0e70 | ||
|
|
8bbaffdeb0 | ||
|
|
19e86e7df3 | ||
|
|
311d6f01df | ||
|
|
61f47d5ffc | ||
|
|
72f0f95471 | ||
|
|
4e33472d81 | ||
|
|
69c4f970a9 | ||
|
|
28866bd08c | ||
|
|
0f93e3ed3c | ||
|
|
59a82ee17f | ||
|
|
e8af00f99f | ||
|
|
ad4b0f8008 | ||
|
|
ae2a0b5208 | ||
|
|
785266bd39 | ||
|
|
2e63e764b2 | ||
|
|
f7eaecf5d4 | ||
|
|
1bee80d0ec | ||
|
|
504a9aa295 | ||
|
|
059530a6b7 | ||
|
|
5b83c634e9 | ||
|
|
ff7ab3837e | ||
|
|
badad651de | ||
|
|
8a767b77e8 | ||
|
|
072a1a4080 | ||
|
|
394e4b095d | ||
|
|
ae1e62c8c6 | ||
|
|
0efb7823d7 | ||
|
|
3ee7d4d04e | ||
|
|
f2d3a5d222 | ||
|
|
904a5cc612 | ||
|
|
5241f93f5f | ||
|
|
6d33d21f70 | ||
|
|
045e2ef9f4 | ||
|
|
527267de62 | ||
|
|
29c01eeb38 | ||
|
|
1c5a1d3656 | ||
|
|
d6fe76750a | ||
|
|
1889c0f9e5 | ||
|
|
ebc16044e2 | ||
|
|
5695ea8fa8 | ||
|
|
16cc9aaa6b | ||
|
|
7f393af2a0 | ||
|
|
3e22607276 | ||
|
|
4de720382d | ||
|
|
a718572688 | ||
|
|
2d66c9fefa | ||
|
|
de51a130b3 | ||
|
|
a8020c9011 | ||
|
|
a2cbc6d474 | ||
|
|
ea5c99431c | ||
|
|
6f68d87f50 | ||
|
|
4aa9c5e0ba | ||
|
|
7e4666afed | ||
|
|
7651a07efc | ||
|
|
f961a9f331 | ||
|
|
bb49cbdc89 | ||
|
|
7fe1b41ea5 | ||
|
|
358e9f1e24 | ||
|
|
8f77ffc871 | ||
|
|
60faa58894 | ||
|
|
aba095b25d | ||
|
|
617ebe96de | ||
|
|
a1bf42dde1 | ||
|
|
b0b83543eb | ||
|
|
b97be9c718 | ||
|
|
33831b072b | ||
|
|
a5f94298d8 | ||
|
|
d0dc959d31 | ||
|
|
644aa2f65e | ||
|
|
e457fe7597 | ||
|
|
dcd409e9d9 | ||
|
|
c227c13ba2 | ||
|
|
c64566ce49 | ||
|
|
a9366c8f23 | ||
|
|
bbf470c61d | ||
|
|
1c1211c4f3 | ||
|
|
7da0bc4a44 | ||
|
|
91a0c51ff8 | ||
|
|
0aa523a329 | ||
|
|
cac7275eb9 | ||
|
|
109eaf7d25 | ||
|
|
9ba15f2c19 | ||
|
|
1c07d787c5 | ||
|
|
b7ae2ea5fe | ||
|
|
b75bb204e3 | ||
|
|
bfc8006205 | ||
|
|
aab2e4a442 | ||
|
|
abfdfe014e | ||
|
|
f82040d2ef | ||
|
|
56f2cf3121 | ||
|
|
6349f07d1a | ||
|
|
1b44559d3e | ||
|
|
a151e60755 | ||
|
|
ce11c84e74 | ||
|
|
9808bf86c4 | ||
|
|
cfae636e55 | ||
|
|
ebaaf50df6 | ||
|
|
5c0be9e89f | ||
|
|
36468663f7 | ||
|
|
fba32608ee | ||
|
|
06848e50c3 | ||
|
|
879d0d4916 | ||
|
|
d083a58cd7 | ||
|
|
b1e9ff9fdc | ||
|
|
304280f415 | ||
|
|
2c8ca1421f | ||
|
|
3ce0fb9f75 | ||
|
|
8a71d2abd6 | ||
|
|
1b174f4eac | ||
|
|
f1d18c7b41 | ||
|
|
204d4607ba | ||
|
|
51f7ce0cb6 | ||
|
|
8f73deb133 | ||
|
|
1d4147309c | ||
|
|
a68e4c1456 | ||
|
|
2ee51363dd | ||
|
|
172eb37b5b | ||
|
|
68e1d8ea69 | ||
|
|
ac8e8db0e7 | ||
|
|
d72bf9b76c | ||
|
|
6d3f535d16 | ||
|
|
0709763f3a | ||
|
|
538d843643 | ||
|
|
2339ee928c | ||
|
|
9550b951d5 | ||
|
|
0491af8a2f | ||
|
|
806a2757b2 | ||
|
|
3931b71d00 | ||
|
|
af0c3d5f62 | ||
|
|
c7a6ca4555 | ||
|
|
4a01e2eb49 | ||
|
|
d6ff20b35d | ||
|
|
0ada9aa105 | ||
|
|
6b04539571 | ||
|
|
9380ec13dc | ||
|
|
ae946c27c0 | ||
|
|
86cf00759f | ||
|
|
0eb5f55d63 | ||
|
|
f27d2aa7eb | ||
|
|
2d3285aaaf | ||
|
|
5bd2532853 | ||
|
|
765c56ccef | ||
|
|
4c755d83a6 | ||
|
|
1b9e1b92aa | ||
|
|
a4c73cc91e | ||
|
|
736fe2111a | ||
|
|
767b0af733 | ||
|
|
02255180e9 | ||
|
|
c3bde94f7a | ||
|
|
886958d479 | ||
|
|
84cbc19f38 | ||
|
|
178ec9dfa9 | ||
|
|
080be1ad0a | ||
|
|
232ca4f215 | ||
|
|
bfa6eac538 | ||
|
|
0ca06782b9 | ||
|
|
2079b0f28b | ||
|
|
32bf45e817 | ||
|
|
5d41bf9e73 | ||
|
|
dc5a2fd956 | ||
|
|
b20f05305b | ||
|
|
46586e5355 | ||
|
|
7e8a751657 | ||
|
|
7d61e55d34 | ||
|
|
2f663429a3 | ||
|
|
492791a4ac | ||
|
|
52e75ade78 | ||
|
|
525a0ba0a1 | ||
|
|
52c7e5012e | ||
|
|
4dd733eb63 | ||
|
|
02a065d623 | ||
|
|
e774ef5751 | ||
|
|
0afee4fafb | ||
|
|
eba1fb3388 | ||
|
|
b2c866edeb | ||
|
|
3583db3e22 | ||
|
|
5d3f8bf073 | ||
|
|
1a72444b0a | ||
|
|
dd88db1913 | ||
|
|
aab00567fc | ||
|
|
21cb6135dd | ||
|
|
f613bb4572 | ||
|
|
51059f0c18 | ||
|
|
dec6598f49 | ||
|
|
f8f6767bec | ||
|
|
07948c87aa | ||
|
|
5c475b98db | ||
|
|
58fb8dc42b | ||
|
|
cb2b11a41a | ||
|
|
ac4f3c4cd4 | ||
|
|
c651e29d2a | ||
|
|
d7e886a841 | ||
|
|
eec7647782 | ||
|
|
6f9d120ff0 | ||
|
|
28ddc2d9c0 | ||
|
|
cc54354ac3 | ||
|
|
3929390629 | ||
|
|
5f4685337e | ||
|
|
08c158aa9c | ||
|
|
e9d71a8f35 | ||
|
|
3e3173cbb0 | ||
|
|
3a26ebf7b1 | ||
|
|
1685bead52 | ||
|
|
3a2fe35e5c | ||
|
|
29ce7f774f | ||
|
|
cc85327356 | ||
|
|
0851bb655e | ||
|
|
d4bc10d8f1 | ||
|
|
0672f32f4b | ||
|
|
a17f7b679c | ||
|
|
425bd85c83 | ||
|
|
3be005e1ee | ||
|
|
174f9e6e03 | ||
|
|
51a14a174f | ||
|
|
7cb1f453d3 | ||
|
|
23a6caab89 | ||
|
|
6b4300bd46 | ||
|
|
04a9069db0 | ||
|
|
dd636903c8 | ||
|
|
4543a10739 | ||
|
|
940b65e86a | ||
|
|
6344de0649 | ||
|
|
8ccd7c3e8d | ||
|
|
2a48d5033e | ||
|
|
f064da797d | ||
|
|
b0b8edf935 | ||
|
|
7959a5133f | ||
|
|
941fb5c29c | ||
|
|
c43c9ea2b3 | ||
|
|
967103bcad | ||
|
|
efe637ec70 | ||
|
|
00450eb260 | ||
|
|
1c5f8af083 | ||
|
|
fccc31a7c6 | ||
|
|
b84d905a0b | ||
|
|
94aa951cba | ||
|
|
2a23dcd011 | ||
|
|
e7a9ee7eee | ||
|
|
27bac2ca00 | ||
|
|
373f74e9f8 | ||
|
|
1931fe9e53 | ||
|
|
0eab6293dc | ||
|
|
51bd52603f | ||
|
|
47f1fa145a | ||
|
|
605055d95a | ||
|
|
20c23a2935 | ||
|
|
bbfe254232 | ||
|
|
882c888f6d | ||
|
|
0a754f072c | ||
|
|
89df0932c5 | ||
|
|
429fd3e4d0 | ||
|
|
95fb0d6e6c | ||
|
|
8ccbdcadf0 | ||
|
|
433aa6910a | ||
|
|
f135c63d84 | ||
|
|
2ebc733b63 | ||
|
|
21bc1a7814 | ||
|
|
53b8009df6 | ||
|
|
68a8e5982e | ||
|
|
08acfeac97 | ||
|
|
999a561515 | ||
|
|
3ee1a4ed2e | ||
|
|
05801db47c | ||
|
|
7bec632f15 | ||
|
|
3f8fe11b47 | ||
|
|
4b8f1e4c1b | ||
|
|
573fd0f320 | ||
|
|
4fa5203c5b | ||
|
|
9c9617f6ed | ||
|
|
bbbf6c483f | ||
|
|
668909e7b3 | ||
|
|
c642848ef2 | ||
|
|
6eea35aa81 | ||
|
|
738a48213c | ||
|
|
d1c093d109 | ||
|
|
00166a1aad | ||
|
|
589238324b | ||
|
|
6845a03741 | ||
|
|
6a4284f189 | ||
|
|
41c57f1ef9 | ||
|
|
808b40bdba | ||
|
|
58b20615da | ||
|
|
13026b1cc4 | ||
|
|
7f3460e492 | ||
|
|
a222391f81 | ||
|
|
a8165531d5 | ||
|
|
1abd31b421 | ||
|
|
72fe49d905 | ||
|
|
9dd9f3befa | ||
|
|
471d76dbe6 | ||
|
|
8b047490c4 | ||
|
|
455f77d0ed | ||
|
|
836fc4a875 | ||
|
|
873f8474b5 | ||
|
|
c94e5cb903 | ||
|
|
27699f7192 | ||
|
|
2eff001b14 | ||
|
|
bd499c7a94 | ||
|
|
4da1e4fbdd | ||
|
|
1d14770ea7 | ||
|
|
8b7574d298 | ||
|
|
14d87d95f6 | ||
|
|
daecf2017e | ||
|
|
37122bc619 | ||
|
|
5a15288d80 | ||
|
|
869dff12ce | ||
|
|
4208048fc1 | ||
|
|
06a2f47812 | ||
|
|
7b3a71bcc9 | ||
|
|
18e612dea2 | ||
|
|
f99593ed62 | ||
|
|
2f7e96fa5b | ||
|
|
25b4392dd5 | ||
|
|
ad4130a547 | ||
|
|
991384822f | ||
|
|
82ed319e59 | ||
|
|
2e4af86a99 | ||
|
|
b4791d3421 | ||
|
|
885c5394a3 | ||
|
|
e35304e4e7 | ||
|
|
6561d577d4 | ||
|
|
02d8834763 | ||
|
|
e82080dc52 | ||
|
|
cfbf972c1b | ||
|
|
e25ea52edc | ||
|
|
7d8e5e5175 | ||
|
|
3d39dec686 | ||
|
|
ff656593ec | ||
|
|
90b4e3438d | ||
|
|
139f8905d0 | ||
|
|
6c1806fae6 | ||
|
|
e6b581e7ff | ||
|
|
873d639461 | ||
|
|
edb2a6d3f6 | ||
|
|
bff60a2e27 | ||
|
|
61831e5962 | ||
|
|
d105b47d44 | ||
|
|
449568bcc4 | ||
|
|
3144077103 | ||
|
|
8f056be0a8 | ||
|
|
e9cdc5693d | ||
|
|
377c50ec36 | ||
|
|
90a2a799da | ||
|
|
feb419b6ae | ||
|
|
e83d8468b0 | ||
|
|
6eabaaa62d | ||
|
|
b0169b4aa7 | ||
|
|
786ec4714a | ||
|
|
4d749b19fd | ||
|
|
6a66440a5f | ||
|
|
1b23efe48c | ||
|
|
9a9d39763f | ||
|
|
9f94ef073c | ||
|
|
000d2d7c77 | ||
|
|
c1b945e6c1 | ||
|
|
dbbe6b65dd | ||
|
|
4611ef5d87 | ||
|
|
807cc1796d | ||
|
|
4bca2c6361 | ||
|
|
82933ae170 | ||
|
|
503fd3555e | ||
|
|
f31cce4182 | ||
|
|
f36fada375 | ||
|
|
d51bce97f5 | ||
|
|
0368aa4d43 | ||
|
|
3c4aa7564f | ||
|
|
f46b89f1bd | ||
|
|
4e2b78056a | ||
|
|
d94ce17fd4 | ||
|
|
cd2c59ba5b | ||
|
|
b6a6943668 | ||
|
|
e1e894d540 | ||
|
|
d15311e70a | ||
|
|
eef8391ffc | ||
|
|
d47751c31f | ||
|
|
b048d3f1f8 | ||
|
|
f94ab3a04a | ||
|
|
1b9375f83b | ||
|
|
a77798d18f | ||
|
|
ec4dd09968 | ||
|
|
d68a5fb9d4 | ||
|
|
635c149f12 | ||
|
|
57e256a5fa | ||
|
|
7d16ffa4a4 | ||
|
|
856e370ba0 | ||
|
|
4df9e7d065 | ||
|
|
edb3857e04 | ||
|
|
fb1cc219ee | ||
|
|
da7329891d | ||
|
|
7f897bc856 | ||
|
|
0092ba92b5 | ||
|
|
7a4e3d954d | ||
|
|
9dc4fefa0b | ||
|
|
695bb58d64 | ||
|
|
608a7212eb | ||
|
|
4e2a5d3b3d | ||
|
|
a4dcc304a9 | ||
|
|
f0fc20de57 | ||
|
|
537d4cd1e9 | ||
|
|
62422f4924 | ||
|
|
076ce0127b | ||
|
|
226c0a6f83 | ||
|
|
6ffa8d92a6 | ||
|
|
dae2cc2f4a | ||
|
|
d277d22914 | ||
|
|
cbdddf8c06 | ||
|
|
8b5d22a081 | ||
|
|
88fc0a8445 | ||
|
|
ec9187d038 | ||
|
|
99cc6f72af | ||
|
|
3527b69718 | ||
|
|
72ff745eff | ||
|
|
dd9db3b557 | ||
|
|
9c531b30bc | ||
|
|
cd30b81202 | ||
|
|
550881faa5 | ||
|
|
ed45945f21 | ||
|
|
f13abe8922 | ||
|
|
34b0a683a9 | ||
|
|
9ab10437b5 | ||
|
|
b0b7408522 | ||
|
|
b104942db9 | ||
|
|
a694b658b1 | ||
|
|
cb07a0d342 | ||
|
|
1ceaad04ec | ||
|
|
5cbf0c1e38 | ||
|
|
4951f294b9 | ||
|
|
ef0ef092f0 | ||
|
|
46d3ae6a2b | ||
|
|
ef1bf646ab | ||
|
|
f72a48ffc2 | ||
|
|
da54ddda78 | ||
|
|
c24205713d | ||
|
|
52d4cb804e | ||
|
|
ae077de72b | ||
|
|
86fa5ec6ae | ||
|
|
41c9d68422 | ||
|
|
e713da5d79 | ||
|
|
edc261ca2b | ||
|
|
8f4a52a6f1 | ||
|
|
c04b80b2f1 | ||
|
|
cdbc2498c1 | ||
|
|
78997b4329 | ||
|
|
790a946cf6 | ||
|
|
69c5be6489 | ||
|
|
3de400fc91 | ||
|
|
6fae1f79d8 | ||
|
|
1222e04caf | ||
|
|
f38973aad6 | ||
|
|
3032463917 | ||
|
|
f5e84a155e | ||
|
|
bbb97bfc7e | ||
|
|
e747756dd2 | ||
|
|
6df5840db9 | ||
|
|
5f79e4b922 | ||
|
|
e058507b9a | ||
|
|
5c4defdf6e | ||
|
|
e58ea2a3fe | ||
|
|
2b7a61469f | ||
|
|
75f1c6c140 | ||
|
|
e3cd057ad8 | ||
|
|
fec069ba00 | ||
|
|
b2db97e808 | ||
|
|
4e537461f2 | ||
|
|
dc7bb12581 | ||
|
|
0c80cdc119 | ||
|
|
37210031b7 | ||
|
|
d7134e6b87 | ||
|
|
8dc1924059 | ||
|
|
a7b77b6008 | ||
|
|
649305a2dd | ||
|
|
2371b0f315 | ||
|
|
59b7768722 | ||
|
|
baa1df620f | ||
|
|
a310811919 | ||
|
|
e9dd5da690 | ||
|
|
f9c25489d1 | ||
|
|
46ee928b07 | ||
|
|
3af102f2ad | ||
|
|
ca53ec0263 | ||
|
|
5ca7c073f1 | ||
|
|
b320c2a1e2 | ||
|
|
3f68154819 | ||
|
|
7b1c4483bb | ||
|
|
572d9c0714 | ||
|
|
b85010006b | ||
|
|
48643cf87e | ||
|
|
9ea594afeb | ||
|
|
749c8cd931 | ||
|
|
49a783c381 | ||
|
|
c9b81f7ab9 | ||
|
|
eb2dbb5b90 | ||
|
|
91c6e3af61 | ||
|
|
faeb921bcf | ||
|
|
9928f56ad3 | ||
|
|
61d27084c1 | ||
|
|
e5393a9fa4 | ||
|
|
1cbc49021a | ||
|
|
84f389b44e | ||
|
|
765775e22f | ||
|
|
02c97c4513 | ||
|
|
d87cd7eafe | ||
|
|
58bb62cc1a | ||
|
|
201d013230 | ||
|
|
9a77b1727c | ||
|
|
f0d35527df | ||
|
|
9cbaa4d7e7 | ||
|
|
af4ad9fbcb | ||
|
|
8bdfa656de | ||
|
|
952bf68b93 | ||
|
|
13f73c0156 | ||
|
|
b32212b061 | ||
|
|
cae3baf71e | ||
|
|
27db33f1bd | ||
|
|
b96e12f217 | ||
|
|
ad8e229c06 | ||
|
|
0ec7085022 | ||
|
|
913cd67eee | ||
|
|
2586b94e28 | ||
|
|
b811b13483 | ||
|
|
c149888bed | ||
|
|
8aea298854 | ||
|
|
5617fbe0a0 | ||
|
|
6a643da8ee | ||
|
|
ee568a76c1 | ||
|
|
beaf077b06 | ||
|
|
e36a9f163e | ||
|
|
17f0f6637a | ||
|
|
0ec770fc51 | ||
|
|
9da5f465d1 | ||
|
|
5230a4fe4f | ||
|
|
b236887718 | ||
|
|
cbca4c3efa | ||
|
|
a67f92176f | ||
|
|
3922827fad | ||
|
|
4b298d6e31 | ||
|
|
c0c65364e5 | ||
|
|
5f89698308 | ||
|
|
5821377b6c | ||
|
|
a6ea35ef9c | ||
|
|
fe9a579dc3 | ||
|
|
ed7f597b3d | ||
|
|
6700030d7c | ||
|
|
f45c7650de | ||
|
|
a36ee65865 | ||
|
|
dfb5b8a4c5 | ||
|
|
9d3dd49e9d | ||
|
|
0833029c82 | ||
|
|
71cf207bf7 | ||
|
|
3d3a035822 | ||
|
|
af3bf5217d | ||
|
|
11f47f26e6 | ||
|
|
f7b37306aa | ||
|
|
8b3d8f6ad4 | ||
|
|
b5cad22afd | ||
|
|
407dae03ca | ||
|
|
c17e683834 | ||
|
|
311abeabd0 | ||
|
|
04f27e0d03 | ||
|
|
fc5103de8d | ||
|
|
14b6345277 | ||
|
|
9a70037e32 | ||
|
|
8ce1aa0092 | ||
|
|
d2e2522c07 | ||
|
|
4a212302e0 | ||
|
|
993dd7ade3 | ||
|
|
d544fc84e8 | ||
|
|
e6dba4456c | ||
|
|
d2777a9b15 | ||
|
|
c7d12bb798 | ||
|
|
ef912a4484 | ||
|
|
b4debd9559 | ||
|
|
d7277649dd | ||
|
|
33ec7e5240 | ||
|
|
d62b692b3b | ||
|
|
493bfd56b9 | ||
|
|
abbfa24ca6 | ||
|
|
fae1edc859 | ||
|
|
a9a741f775 | ||
|
|
c0d482e4fc | ||
|
|
b5cabdc775 | ||
|
|
c71a43c3a6 | ||
|
|
cd01283ac6 | ||
|
|
7ce1077bd6 | ||
|
|
f9701d1c7b | ||
|
|
e764830113 | ||
|
|
9646457b50 | ||
|
|
7346e55e0d | ||
|
|
ae38a8cb4f | ||
|
|
df46a4a5fc | ||
|
|
7c6797a141 | ||
|
|
83abac8c5e | ||
|
|
5ba6b2f335 | ||
|
|
0d4ba7c6f1 | ||
|
|
a1fc351183 | ||
|
|
33a6c39fc4 | ||
|
|
f853f6ef25 | ||
|
|
7a2d114360 | ||
|
|
0157f387ee | ||
|
|
c23be231e1 | ||
|
|
00f5c36919 | ||
|
|
c960175ec1 | ||
|
|
e456604436 | ||
|
|
ac4657e77f | ||
|
|
3817427e79 | ||
|
|
0200b3c63e | ||
|
|
972a1a5703 | ||
|
|
73c22176b8 | ||
|
|
4db036f350 | ||
|
|
52223f0a20 | ||
|
|
907ad0faf6 | ||
|
|
887e10c947 | ||
|
|
b4c463e452 | ||
|
|
66ba9b1f46 | ||
|
|
7db50811ba | ||
|
|
17d20705ff | ||
|
|
e3bd782a42 | ||
|
|
b073379fff | ||
|
|
b89d8ff946 | ||
|
|
22ad971c8e | ||
|
|
ab06cc3703 | ||
|
|
8a5cc5f2bd | ||
|
|
6919baf23c | ||
|
|
ddedb215c4 | ||
|
|
08d4d817f6 | ||
|
|
e8bdcfbaf2 | ||
|
|
743fb4494e | ||
|
|
0a4bc7fad6 | ||
|
|
49d0b16324 | ||
|
|
de479d6188 | ||
|
|
3fd3e13dc7 | ||
|
|
d7d913d439 | ||
|
|
5c4ae3820b | ||
|
|
38774a20c6 | ||
|
|
9fc58bb4df | ||
|
|
ca936ca42f | ||
|
|
840fb6b647 | ||
|
|
c80b5d6d78 | ||
|
|
40067c514f | ||
|
|
eee55a92d9 | ||
|
|
21398fbf8a | ||
|
|
139ae36d3e |
@@ -26,6 +26,8 @@ Also there are more people on the forum that can help you with support.
|
||||
|
||||
* Incomplete or unstable plugins should have a PLUGIN_BUILD_DEV #ifdef around them. Also add [DEVELOPMENT] to the name.
|
||||
|
||||
* New plugins that seem to be working correctly should have a PLUGIN_BUILD_TESTING around until they are tested enough.
|
||||
* Do not modify any of the variables passed to your PLUGIN_WRITE handler.
|
||||
|
||||
* New plugins that seem to be working correctly should have a PLUGIN_BUILD_TESTING around until they are tested enough. Also add [TESTING] to the name
|
||||
|
||||
* Also see our general guidelines at: https://www.letscontrolit.com/wiki/index.php/ESPEasyDevelopmentGuidelines
|
||||
|
||||
@@ -1,18 +1,44 @@
|
||||
**NOTE: This is not a support forum! For questions and support go here: https://www.letscontrolit.com/forum/viewforum.php?f=1**
|
||||
<!--- If you self compile, please state this and PLEASE try to ONLY REPORT ISSUES WITH OFFICIAL BUILDS! --->
|
||||
<!--- NOTE: This is not a support forum! For questions and support go here: --->
|
||||
<!--- https://www.letscontrolit.com/forum/viewforum.php?f=1 --->
|
||||
<!--- Remove topics that are not applicable to your feature request of issue --->
|
||||
<!--- Remember to have a "to the point" TITLE --->
|
||||
|
||||
### Steps to reproduce
|
||||
How can we trigger this problem?
|
||||
|
||||
Does the problem presist after powering off and on? (just resetting isnt enough sometimes)
|
||||
### Summarize of the problem/feature request
|
||||
<!--- Describe the problem or feature request --->
|
||||
YOUR TEXT GOES HERE
|
||||
|
||||
### Expected behavior
|
||||
Tell us what should happen?
|
||||
<!--- Tell us what should happen? --->
|
||||
YOUR TEXT GOES HERE
|
||||
|
||||
### Actual behavior
|
||||
Tell us what happens instead?
|
||||
<!--- Tell us what happens instead? --->
|
||||
YOUR TEXT GOES HERE
|
||||
|
||||
### Steps to reproduce
|
||||
<!--- How can we trigger this problem? --->
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
<!--- Does the problem persists after powering off and on? (just resetting isn't enough sometimes) --->
|
||||
<!--- Please document if you have restarted the unit and if the problem is then gone etc. etc. --->
|
||||
### System configuration
|
||||
|
||||
<!--- Please add as much information and screenshots as possible --->
|
||||
Hardware:
|
||||
|
||||
Software or git version:
|
||||
<!--- You should also provide links to hardware pages etc where we can find more info --->
|
||||
<!--- If you self compile, please state this and PLEASE try to ONLY REPORT ISSUES WITH OFFICIAL BUILDS! --->
|
||||
ESP Easy version:
|
||||
|
||||
<!--- In order to have a better readablity of your issue then you should place screenshots here --->
|
||||
<!--- Simply drag and drop them onto this template, move the text string below the "ESP Easy settings/screenshots" topic --->
|
||||
ESP Easy settings/screenshots:
|
||||
|
||||
### Rules or log data
|
||||
<!--- place your code/rules between the two ``` rows --->
|
||||
<!--- remove if not applicable! --->
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
+12
@@ -1,7 +1,19 @@
|
||||
## OS Specific Hidden Files ####
|
||||
|
||||
# MacOSX Finder *****
|
||||
.DS_Store
|
||||
|
||||
# Fuse FileSystem ***
|
||||
.fuse_hidden*
|
||||
|
||||
|
||||
## PlatformIO ##################
|
||||
.pioenvs
|
||||
.clang_complete
|
||||
.gcc-flags.json
|
||||
.piolibdeps
|
||||
|
||||
## Project #####################
|
||||
lib/readme.txt
|
||||
src/Custom.h
|
||||
test/output_export.cpp
|
||||
|
||||
+4
-2
@@ -25,13 +25,15 @@ install:
|
||||
- pip install -U platformio
|
||||
|
||||
script:
|
||||
- cppcheck --enable=warning src/*.ino -q --force -I src --include=src/ESPEasy.ino --error-exitcode=1
|
||||
# - cppcheck --enable=warning src/*.ino -q --force -I src --include=src/ESPEasy.ino --error-exitcode=1
|
||||
# - ./memanalyzer.py ~/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-objdump
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run
|
||||
|
||||
# patch platformio core libs for PUYA bug (https://github.com/letscontrolit/ESPEasy/issues/650)
|
||||
- cd patches; ./check_puya_patch; cd ..
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -s --environment dev_ESP8266PUYA_1024
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -s --environment dev_ESP8266PUYA_1024
|
||||
|
||||
|
||||
before_deploy:
|
||||
|
||||
@@ -1,44 +1,39 @@
|
||||
# ESPEasy (v2.0 stable branch)
|
||||
# ESPEasy (development branch)
|
||||
|
||||
Build status: [](https://travis-ci.org/letscontrolit/ESPEasy)
|
||||
Badge | Info |
|
||||
-------|-------|
|
||||
[](https://travis-ci.org/letscontrolit/ESPEasy) | build status |
|
||||
[](https://github.com/letscontrolit/ESPEasy/releases/latest) | latest nightly |
|
||||
|
||||
Introduction and wiki: https://www.letscontrolit.com/wiki/index.php/ESPEasy#Introduction
|
||||
|
||||
**v2.0**
|
||||
:warning:This is the stable branch for the next upcoming ESPeasy release (2.0.0).:warning:
|
||||
**MEGA**
|
||||
:warning:This is the development branch of ESPEasy. All new untested features go into this branch. If you want to do a bugfix, do it on the stable branch, we will merge the fix to the development branch as well.:warning:
|
||||
|
||||
If you're living on the edge and want the latest features and bugs, go to the development branch: https://github.com/letscontrolit/ESPEasy/tree/mega
|
||||
|
||||
If you're a developer: Bug fixes go into this v2.0 branch, we will merge them back to the development branch.
|
||||
Next stable branch: https://github.com/letscontrolit/ESPEasy/tree/v2.0 (bug fixes only, since oct 2017))
|
||||
|
||||
Check here to learn how to use this branch and help us improving ESPEasy: http://www.letscontrolit.com/wiki/index.php/ESPEasy#Source_code_development
|
||||
|
||||
## Versions
|
||||
|
||||
* v2.0-YYYYMMDD: These are the nightly builds. Once a day this is automaticly released whenever there are new changes. (this replaces the manual v2.0-devX release system)
|
||||
* v2.0.0-betaX: as soon as we THINK everything is fixed, we start beta testing.
|
||||
* v2.0.0-rcX: release candidates (almost stable)
|
||||
* v2.0.0: This will be the first stable release. After this we will use more standard numbering. Next bugfix release will probably be 2.0.1.
|
||||
## Automated binary releases
|
||||
|
||||
## Firmware binary releases
|
||||
Every night our build-bot will build a new binary release: https://github.com/letscontrolit/ESPEasy/releases
|
||||
|
||||
Binary development releases are here: https://github.com/letscontrolit/ESPEasy/releases
|
||||
The releases are named something like 'mega-20180102' (last number is the build date)
|
||||
|
||||
Depending on your needs, we release different types of files.
|
||||
|
||||
This uses version v2.0-20181001 as an example.
|
||||
Depending on your needs, we release different types of files:
|
||||
|
||||
Firmware name | Hardware | Included plugins |
|
||||
----------------------------------------------|-------------------------|-----------------------------|
|
||||
ESPEasy_v2.0-20181001_normal_ESP8266_1024.bin | ESP8266 with 1Mb flash | Stable |
|
||||
ESPEasy_v2.0-20181001_test_ESP8266_1024.bin | ESP8266 with 1Mb flash | Stable + Test |
|
||||
ESPEasy_v2.0-20181001_dev_ESP8266_1024.bin | ESP8266 with 1Mb flash | Stable + Test + Development |
|
||||
ESPEasy_v2.0-20181001_normal_ESP8266_4096.bin | ESP8266 with 4Mb flash | Stable |
|
||||
ESPEasy_v2.0-20181001_test_ESP8266_4096.bin | ESP8266 with 4Mb flash | Stable + Test |
|
||||
ESPEasy_v2.0-20181001_dev_ESP8266_4096.bin | ESP8266 with 4Mb flash | Stable + Test + Development |
|
||||
ESPEasy_v2.0-20181001_normal_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stable |
|
||||
ESPEasy_v2.0-20181001_test_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stable + Test |
|
||||
ESPEasy_v2.0-20181001_dev_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stable + Test + Development |
|
||||
ESPEasy_mega-20180102_normal_ESP8266_1024.bin | ESP8266 with 1Mb flash | Stable |
|
||||
ESPEasy_mega-20180102_test_ESP8266_1024.bin | ESP8266 with 1Mb flash | Stable + Test |
|
||||
ESPEasy_mega-20180102_dev_ESP8266_1024.bin | ESP8266 with 1Mb flash | Stable + Test + Development |
|
||||
ESPEasy_mega-20180102_normal_ESP8266_4096.bin | ESP8266 with 4Mb flash | Stable |
|
||||
ESPEasy_mega-20180102_test_ESP8266_4096.bin | ESP8266 with 4Mb flash | Stable + Test |
|
||||
ESPEasy_mega-20180102_dev_ESP8266_4096.bin | ESP8266 with 4Mb flash | Stable + Test + Development |
|
||||
ESPEasy_mega-20180102_normal_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stable |
|
||||
ESPEasy_mega-20180102_test_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stable + Test |
|
||||
ESPEasy_mega-20180102_dev_ESP8285_1024.bin | ESP8285 with 1Mb flash | Stable + Test + Development |
|
||||
|
||||
## More info
|
||||
|
||||
|
||||
+7
-4
@@ -10,7 +10,6 @@ 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\
|
||||
@@ -19,12 +18,16 @@ for ENV in \
|
||||
dev_ESP8266_4096\
|
||||
dev_ESP8285_1024\
|
||||
dev_ESP8266PUYA_1024\
|
||||
dev_ESP8266PUYA_1024_VCC;\
|
||||
dev_ESP8266PUYA_1024_VCC\
|
||||
hard_SONOFF_POW\
|
||||
esp32dev;\
|
||||
do
|
||||
echo
|
||||
echo "### Deploying environment $ENV for version $VERSION"
|
||||
BIN=.pioenvs/$ENV/firmware.bin
|
||||
cp $BIN dist/"ESP_Easy_$VERSION""_$ENV.bin"
|
||||
BIN=.pioenvs/${ENV}/ESP_Easy_${VERSION}_${ENV}.bin
|
||||
cp .pioenvs/${ENV}/firmware.bin $BIN
|
||||
python2 crc2.py $BIN
|
||||
mv $BIN "dist/ESP_Easy_${VERSION}_${ENV}.bin"
|
||||
done
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
|
||||
import sys
|
||||
import binascii
|
||||
import struct
|
||||
import md5
|
||||
import os
|
||||
MD5DUMMY = "MD5_MD5_MD5_MD5_BoundariesOfTheSegmentsGoHere..." #48 chars
|
||||
FILENAMEDUMMY = "ThisIsTheDummyPlaceHolderForTheBinaryFilename64ByteLongFilenames" #64 chars
|
||||
|
||||
MemorySegmentStart,MemorySegmentEnd,MemoryContent=[],[],[]
|
||||
|
||||
##################################################################
|
||||
# this subroutine shows the segments of a part
|
||||
##################################################################
|
||||
def showSegments (fileContent,offset):
|
||||
global MemorySegmentStart, MemorySegmentEnd, MemoryContent
|
||||
header = struct.unpack("ii", fileContent[offset:offset+8])
|
||||
herestr =""
|
||||
herestr2 =""
|
||||
MemorySegmentStart.append(struct.pack("I",header[0]))
|
||||
MemorySegmentEnd.append(struct.pack("I",header[0]+header[1]))
|
||||
MemoryContent.append(fileContent[offset+8:offset+8+header[1]])
|
||||
if fileContent.find( MD5DUMMY, offset+8, offset+8+header[1]) >0 :
|
||||
herestr= " <-- CRC is here."
|
||||
if fileContent.find( FILENAMEDUMMY, offset+8, offset+8+header[1]) >0 :
|
||||
herestr2= " <-- filename is here."
|
||||
print ("SEGMENT "+ str(len(MemorySegmentStart)-1)+ ": memory position: " + hex(header[0])+" to " + hex(header[0]+header[1]) + " length: " + hex(header[1])+herestr+herestr2)
|
||||
#print ("first byte positoin in file: " + hex( offset+8))
|
||||
#print ("last byte postion in file: " + hex(offset+8+header[1]-1))
|
||||
return (8+offset+ header[1]); # return start of next segment
|
||||
|
||||
##################################################################
|
||||
# this subroutine shows the parts of a binary file
|
||||
##################################################################
|
||||
def showParts(fileContent, offset):
|
||||
header = struct.unpack("BBBBi", fileContent[offset:offset+8])
|
||||
print ('\n\nBINARY PART\nSegments: ') + (hex(header[1]))
|
||||
nextpos =offset+8
|
||||
for x in range (0,header[1]):
|
||||
nextpos = showSegments(fileContent,nextpos)
|
||||
nextSegmentOffset = (fileContent.find("\xe9", nextpos))
|
||||
return nextSegmentOffset
|
||||
|
||||
##################################################################
|
||||
# MAIN
|
||||
##################################################################
|
||||
|
||||
#if len(sys.argv) !=2 :
|
||||
# print ("please give a filename")
|
||||
# k=input("press close to exit")
|
||||
# sys.exit(1)
|
||||
FileName = sys.argv[1]#"C:/ArduinoPortable/sketchbooks/build/sketch_jan15a.ino.bin"
|
||||
#FileName = "C:/ArduinoPortable/sketchbooks/build/sketch_jan15a.ino.bin"
|
||||
print( "\n\nReplacing dummy MD5 checksum in .bin file")
|
||||
|
||||
|
||||
|
||||
with open(FileName, mode='rb') as file: # b is important -> binary
|
||||
nextpos =0;
|
||||
fileContent = file.read()
|
||||
while nextpos >=0:
|
||||
nextpos = showParts(fileContent,nextpos)
|
||||
|
||||
startArray,endArray,hashString = "","",""
|
||||
includeStr = "hash includes segments:"
|
||||
# memory sections:
|
||||
# 0: bootloader (not readable)
|
||||
# 1: program memory (SPI flash)
|
||||
# 2: unknown but stable
|
||||
# 3: RAM (initialized by bin file. Can be read but changes as you go :-( )
|
||||
# 4: RAM
|
||||
|
||||
for i in (1,2 ): # use only stable segments, must be 4 in total. We use 2.
|
||||
startArray =startArray + MemorySegmentStart[i]
|
||||
endArray = endArray + MemorySegmentEnd[i]
|
||||
hashString =hashString + MemoryContent[i]
|
||||
with open(FileName+str(i), mode='wb') as file: # b is important -> binary
|
||||
file.write(MemoryContent[i])
|
||||
includeStr = includeStr +" "+ str(i)
|
||||
print (includeStr)
|
||||
# IMPORTANT: pad array with zeros if you use only 3 segments (see above)
|
||||
while len(startArray) < 16 :
|
||||
startArray =startArray + struct.pack("I",0)
|
||||
endArray = endArray + struct.pack("I",0)
|
||||
# debug print (binascii.hexlify(startArray))
|
||||
# debug print (binascii.hexlify(endArray))
|
||||
if (len(endArray) + len (startArray)) != 32 :
|
||||
print("ERROR: please make sure you add / remove padding if you change the semgents.")
|
||||
|
||||
BinaryFileName = "";
|
||||
if fileContent.find( FILENAMEDUMMY) < 0:
|
||||
print("ERROR: FILENAMEDUMMY dummy not found in binary")
|
||||
else:
|
||||
BinaryFileName=os.path.basename(FileName) +"\0"
|
||||
if len(BinaryFileName) >64: # check that filename is <48 chars
|
||||
BinaryFileName=BinaryFileName[0:64] # truncate if necessary. 49th char in ESP is zero already
|
||||
else:
|
||||
BinaryFileName= BinaryFileName.ljust(64,'\0'); # pad with zeros.
|
||||
|
||||
|
||||
if fileContent.find( MD5DUMMY) < 0:
|
||||
print("ERROR: MD5 dummy not found in binary")
|
||||
else:
|
||||
hashString=hashString.replace (MD5DUMMY,"",1)
|
||||
m = md5.new()
|
||||
m.update (hashString) #use segment 1
|
||||
md5hash = m.digest()
|
||||
print("MD5 hash: "+ m.hexdigest())
|
||||
print("\nwriting output file:\n" + FileName)
|
||||
|
||||
fileContent=fileContent.replace(MD5DUMMY,md5hash+startArray+endArray)
|
||||
fileContent=fileContent.replace(FILENAMEDUMMY,BinaryFileName)
|
||||
|
||||
with open(FileName, mode='wb') as file: # b is important -> binary
|
||||
file.write(fileContent)
|
||||
#k=input("press close to exit")
|
||||
Vendored
+1637
-204
File diff suppressed because it is too large
Load Diff
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software< /span>
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and
|
||||
* extended sensor support to include color, voltage and current */
|
||||
|
||||
#ifndef _ADAFRUIT_SENSOR_H
|
||||
#define _ADAFRUIT_SENSOR_H
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#include "Print.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
/* Intentionally modeled after sensors.h in the Android API:
|
||||
* https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h */
|
||||
|
||||
/* Constants */
|
||||
#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH)
|
||||
#define SENSORS_MAGFIELD_EARTH_MAX (60.0F) /**< Maximum magnetic field on Earth's surface */
|
||||
#define SENSORS_MAGFIELD_EARTH_MIN (30.0F) /**< Minimum magnetic field on Earth's surface */
|
||||
#define SENSORS_PRESSURE_SEALEVELHPA (1013.25F) /**< Average sea level pressure is 1013.25 hPa */
|
||||
#define SENSORS_DPS_TO_RADS (0.017453293F) /**< Degrees/s to rad/s multiplier */
|
||||
#define SENSORS_GAUSS_TO_MICROTESLA (100) /**< Gauss to micro-Tesla multiplier */
|
||||
|
||||
/** Sensor types */
|
||||
typedef enum
|
||||
{
|
||||
SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */
|
||||
SENSOR_TYPE_MAGNETIC_FIELD = (2),
|
||||
SENSOR_TYPE_ORIENTATION = (3),
|
||||
SENSOR_TYPE_GYROSCOPE = (4),
|
||||
SENSOR_TYPE_LIGHT = (5),
|
||||
SENSOR_TYPE_PRESSURE = (6),
|
||||
SENSOR_TYPE_PROXIMITY = (8),
|
||||
SENSOR_TYPE_GRAVITY = (9),
|
||||
SENSOR_TYPE_LINEAR_ACCELERATION = (10), /**< Acceleration not including gravity */
|
||||
SENSOR_TYPE_ROTATION_VECTOR = (11),
|
||||
SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
|
||||
SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
|
||||
SENSOR_TYPE_VOLTAGE = (15),
|
||||
SENSOR_TYPE_CURRENT = (16),
|
||||
SENSOR_TYPE_COLOR = (17)
|
||||
} sensors_type_t;
|
||||
|
||||
/** struct sensors_vec_s is used to return a vector in a common format. */
|
||||
typedef struct {
|
||||
union {
|
||||
float v[3];
|
||||
struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
/* Orientation sensors */
|
||||
struct {
|
||||
float roll; /**< Rotation around the longitudinal axis (the plane body, 'X axis'). Roll is positive and increasing when moving downward. -90°<=roll<=90° */
|
||||
float pitch; /**< Rotation around the lateral axis (the wing span, 'Y axis'). Pitch is positive and increasing when moving upwards. -180°<=pitch<=180°) */
|
||||
float heading; /**< Angle between the longitudinal axis (the plane body) and magnetic north, measured clockwise when viewing from the top of the device. 0-359° */
|
||||
};
|
||||
};
|
||||
int8_t status;
|
||||
uint8_t reserved[3];
|
||||
} sensors_vec_t;
|
||||
|
||||
/** struct sensors_color_s is used to return color data in a common format. */
|
||||
typedef struct {
|
||||
union {
|
||||
float c[3];
|
||||
/* RGB color space */
|
||||
struct {
|
||||
float r; /**< Red component */
|
||||
float g; /**< Green component */
|
||||
float b; /**< Blue component */
|
||||
};
|
||||
};
|
||||
uint32_t rgba; /**< 24-bit RGBA value */
|
||||
} sensors_color_t;
|
||||
|
||||
/* Sensor event (36 bytes) */
|
||||
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
|
||||
typedef struct
|
||||
{
|
||||
int32_t version; /**< must be sizeof(struct sensors_event_t) */
|
||||
int32_t sensor_id; /**< unique sensor identifier */
|
||||
int32_t type; /**< sensor type */
|
||||
int32_t reserved0; /**< reserved */
|
||||
int32_t timestamp; /**< time is in milliseconds */
|
||||
union
|
||||
{
|
||||
float data[4];
|
||||
sensors_vec_t acceleration; /**< acceleration values are in meter per second per second (m/s^2) */
|
||||
sensors_vec_t magnetic; /**< magnetic vector values are in micro-Tesla (uT) */
|
||||
sensors_vec_t orientation; /**< orientation values are in degrees */
|
||||
sensors_vec_t gyro; /**< gyroscope values are in rad/s */
|
||||
float temperature; /**< temperature is in degrees centigrade (Celsius) */
|
||||
float distance; /**< distance in centimeters */
|
||||
float light; /**< light in SI lux units */
|
||||
float pressure; /**< pressure in hectopascal (hPa) */
|
||||
float relative_humidity; /**< relative humidity in percent */
|
||||
float current; /**< current in milliamps (mA) */
|
||||
float voltage; /**< voltage in volts (V) */
|
||||
sensors_color_t color; /**< color in RGB component values */
|
||||
};
|
||||
} sensors_event_t;
|
||||
|
||||
/* Sensor details (40 bytes) */
|
||||
/** struct sensor_s is used to describe basic information about a specific sensor. */
|
||||
typedef struct
|
||||
{
|
||||
char name[12]; /**< sensor name */
|
||||
int32_t version; /**< version of the hardware + driver */
|
||||
int32_t sensor_id; /**< unique sensor identifier */
|
||||
int32_t type; /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */
|
||||
float max_value; /**< maximum value of this sensor's value in SI units */
|
||||
float min_value; /**< minimum value of this sensor's value in SI units */
|
||||
float resolution; /**< smallest difference between two values reported by this sensor */
|
||||
int32_t min_delay; /**< min delay in microseconds between events. zero = not a constant rate */
|
||||
} sensor_t;
|
||||
|
||||
class Adafruit_Sensor {
|
||||
public:
|
||||
// Constructor(s)
|
||||
Adafruit_Sensor() {}
|
||||
virtual ~Adafruit_Sensor() {}
|
||||
|
||||
// These must be defined by the subclass
|
||||
virtual void enableAutoRange(bool enabled) {};
|
||||
virtual bool getEvent(sensors_event_t*) = 0;
|
||||
virtual void getSensor(sensor_t*) = 0;
|
||||
|
||||
private:
|
||||
bool _autoRange;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,221 @@
|
||||
# Adafruit Unified Sensor Driver #
|
||||
|
||||
Many small embedded systems exist to collect data from sensors, analyse the data, and either take an appropriate action or send that sensor data to another system for processing.
|
||||
|
||||
One of the many challenges of embedded systems design is the fact that parts you used today may be out of production tomorrow, or system requirements may change and you may need to choose a different sensor down the road.
|
||||
|
||||
Creating new drivers is a relatively easy task, but integrating them into existing systems is both error prone and time consuming since sensors rarely use the exact same units of measurement.
|
||||
|
||||
By reducing all data to a single **sensors\_event\_t** 'type' and settling on specific, **standardised SI units** for each sensor family the same sensor types return values that are comparable with any other similar sensor. This enables you to switch sensor models with very little impact on the rest of the system, which can help mitigate some of the risks and problems of sensor availability and code reuse.
|
||||
|
||||
The unified sensor abstraction layer is also useful for data-logging and data-transmission since you only have one well-known type to log or transmit over the air or wire.
|
||||
|
||||
## Unified Sensor Drivers ##
|
||||
|
||||
The following drivers are based on the Adafruit Unified Sensor Driver:
|
||||
|
||||
**Accelerometers**
|
||||
- [Adafruit\_ADXL345](https://github.com/adafruit/Adafruit_ADXL345)
|
||||
- [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC)
|
||||
- [Adafruit\_MMA8451\_Library](https://github.com/adafruit/Adafruit_MMA8451_Library)
|
||||
|
||||
**Gyroscope**
|
||||
- [Adafruit\_L3GD20\_U](https://github.com/adafruit/Adafruit_L3GD20_U)
|
||||
|
||||
**Light**
|
||||
- [Adafruit\_TSL2561](https://github.com/adafruit/Adafruit_TSL2561)
|
||||
- [Adafruit\_TSL2591\_Library](https://github.com/adafruit/Adafruit_TSL2591_Library)
|
||||
|
||||
**Magnetometers**
|
||||
- [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC)
|
||||
- [Adafruit\_HMC5883\_Unified](https://github.com/adafruit/Adafruit_HMC5883_Unified)
|
||||
|
||||
**Barometric Pressure**
|
||||
- [Adafruit\_BMP085\_Unified](https://github.com/adafruit/Adafruit_BMP085_Unified)
|
||||
- [Adafruit\_BMP183\_Unified\_Library](https://github.com/adafruit/Adafruit_BMP183_Unified_Library)
|
||||
|
||||
**Humidity & Temperature**
|
||||
- [DHT-sensor-library](https://github.com/adafruit/DHT-sensor-library)
|
||||
|
||||
**Orientation**
|
||||
- [Adafruit_BNO055](https://github.com/adafruit/Adafruit_BNO055)
|
||||
|
||||
## How Does it Work? ##
|
||||
|
||||
Any driver that supports the Adafruit unified sensor abstraction layer will implement the Adafruit\_Sensor base class. There are two main typedefs and one enum defined in Adafruit_Sensor.h that are used to 'abstract' away the sensor details and values:
|
||||
|
||||
**Sensor Types (sensors\_type\_t)**
|
||||
|
||||
These pre-defined sensor types are used to properly handle the two related typedefs below, and allows us determine what types of units the sensor uses, etc.
|
||||
|
||||
```
|
||||
/** Sensor types */
|
||||
typedef enum
|
||||
{
|
||||
SENSOR_TYPE_ACCELEROMETER = (1),
|
||||
SENSOR_TYPE_MAGNETIC_FIELD = (2),
|
||||
SENSOR_TYPE_ORIENTATION = (3),
|
||||
SENSOR_TYPE_GYROSCOPE = (4),
|
||||
SENSOR_TYPE_LIGHT = (5),
|
||||
SENSOR_TYPE_PRESSURE = (6),
|
||||
SENSOR_TYPE_PROXIMITY = (8),
|
||||
SENSOR_TYPE_GRAVITY = (9),
|
||||
SENSOR_TYPE_LINEAR_ACCELERATION = (10),
|
||||
SENSOR_TYPE_ROTATION_VECTOR = (11),
|
||||
SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
|
||||
SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
|
||||
SENSOR_TYPE_VOLTAGE = (15),
|
||||
SENSOR_TYPE_CURRENT = (16),
|
||||
SENSOR_TYPE_COLOR = (17)
|
||||
} sensors_type_t;
|
||||
```
|
||||
|
||||
**Sensor Details (sensor\_t)**
|
||||
|
||||
This typedef describes the specific capabilities of this sensor, and allows us to know what sensor we are using beneath the abstraction layer.
|
||||
|
||||
```
|
||||
/* Sensor details (40 bytes) */
|
||||
/** struct sensor_s is used to describe basic information about a specific sensor. */
|
||||
typedef struct
|
||||
{
|
||||
char name[12];
|
||||
int32_t version;
|
||||
int32_t sensor_id;
|
||||
int32_t type;
|
||||
float max_value;
|
||||
float min_value;
|
||||
float resolution;
|
||||
int32_t min_delay;
|
||||
} sensor_t;
|
||||
```
|
||||
|
||||
The individual fields are intended to be used as follows:
|
||||
|
||||
- **name**: The sensor name or ID, up to a maximum of twelve characters (ex. "MPL115A2")
|
||||
- **version**: The version of the sensor HW and the driver to allow us to differentiate versions of the board or driver
|
||||
- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network
|
||||
- **type**: The sensor type, based on **sensors\_type\_t** in sensors.h
|
||||
- **max\_value**: The maximum value that this sensor can return (in the appropriate SI unit)
|
||||
- **min\_value**: The minimum value that this sensor can return (in the appropriate SI unit)
|
||||
- **resolution**: The smallest difference between two values that this sensor can report (in the appropriate SI unit)
|
||||
- **min\_delay**: The minimum delay in microseconds between two sensor events, or '0' if there is no constant sensor rate
|
||||
|
||||
**Sensor Data/Events (sensors\_event\_t)**
|
||||
|
||||
This typedef is used to return sensor data from any sensor supported by the abstraction layer, using standard SI units and scales.
|
||||
|
||||
```
|
||||
/* Sensor event (36 bytes) */
|
||||
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
|
||||
typedef struct
|
||||
{
|
||||
int32_t version;
|
||||
int32_t sensor_id;
|
||||
int32_t type;
|
||||
int32_t reserved0;
|
||||
int32_t timestamp;
|
||||
union
|
||||
{
|
||||
float data[4];
|
||||
sensors_vec_t acceleration;
|
||||
sensors_vec_t magnetic;
|
||||
sensors_vec_t orientation;
|
||||
sensors_vec_t gyro;
|
||||
float temperature;
|
||||
float distance;
|
||||
float light;
|
||||
float pressure;
|
||||
float relative_humidity;
|
||||
float current;
|
||||
float voltage;
|
||||
sensors_color_t color;
|
||||
};
|
||||
} sensors_event_t;
|
||||
```
|
||||
It includes the following fields:
|
||||
|
||||
- **version**: Contain 'sizeof(sensors\_event\_t)' to identify which version of the API we're using in case this changes in the future
|
||||
- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network (must match the sensor\_id value in the corresponding sensor\_t enum above!)
|
||||
- **type**: the sensor type, based on **sensors\_type\_t** in sensors.h
|
||||
- **timestamp**: time in milliseconds when the sensor value was read
|
||||
- **data[4]**: An array of four 32-bit values that allows us to encapsulate any type of sensor data via a simple union (further described below)
|
||||
|
||||
**Required Functions**
|
||||
|
||||
In addition to the two standard types and the sensor type enum, all drivers based on Adafruit_Sensor must also implement the following two functions:
|
||||
|
||||
```
|
||||
bool getEvent(sensors_event_t*);
|
||||
```
|
||||
Calling this function will populate the supplied sensors\_event\_t reference with the latest available sensor data. You should call this function as often as you want to update your data.
|
||||
|
||||
```
|
||||
void getSensor(sensor_t*);
|
||||
```
|
||||
Calling this function will provide some basic information about the sensor (the sensor name, driver version, min and max values, etc.
|
||||
|
||||
**Standardised SI values for sensors\_event\_t**
|
||||
|
||||
A key part of the abstraction layer is the standardisation of values on SI units of a particular scale, which is accomplished via the data[4] union in sensors\_event\_t above. This 16 byte union includes fields for each main sensor type, and uses the following SI units and scales:
|
||||
|
||||
- **acceleration**: values are in **meter per second per second** (m/s^2)
|
||||
- **magnetic**: values are in **micro-Tesla** (uT)
|
||||
- **orientation**: values are in **degrees**
|
||||
- **gyro**: values are in **rad/s**
|
||||
- **temperature**: values in **degrees centigrade** (Celsius)
|
||||
- **distance**: values are in **centimeters**
|
||||
- **light**: values are in **SI lux** units
|
||||
- **pressure**: values are in **hectopascal** (hPa)
|
||||
- **relative\_humidity**: values are in **percent**
|
||||
- **current**: values are in **milliamps** (mA)
|
||||
- **voltage**: values are in **volts** (V)
|
||||
- **color**: values are in 0..1.0 RGB channel luminosity and 32-bit RGBA format
|
||||
|
||||
## The Unified Driver Abstraction Layer in Practice ##
|
||||
|
||||
Using the unified sensor abstraction layer is relatively easy once a compliant driver has been created.
|
||||
|
||||
Every compliant sensor can now be read using a single, well-known 'type' (sensors\_event\_t), and there is a standardised way of interrogating a sensor about its specific capabilities (via sensor\_t).
|
||||
|
||||
An example of reading the [TSL2561](https://github.com/adafruit/Adafruit_TSL2561) light sensor can be seen below:
|
||||
|
||||
```
|
||||
Adafruit_TSL2561 tsl = Adafruit_TSL2561(TSL2561_ADDR_FLOAT, 12345);
|
||||
...
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event;
|
||||
tsl.getEvent(&event);
|
||||
|
||||
/* Display the results (light is measured in lux) */
|
||||
if (event.light)
|
||||
{
|
||||
Serial.print(event.light); Serial.println(" lux");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If event.light = 0 lux the sensor is probably saturated
|
||||
and no reliable data could be generated! */
|
||||
Serial.println("Sensor overload");
|
||||
}
|
||||
```
|
||||
|
||||
Similarly, we can get the basic technical capabilities of this sensor with the following code:
|
||||
|
||||
```
|
||||
sensor_t sensor;
|
||||
|
||||
sensor_t sensor;
|
||||
tsl.getSensor(&sensor);
|
||||
|
||||
/* Display the sensor details */
|
||||
Serial.println("------------------------------------");
|
||||
Serial.print ("Sensor: "); Serial.println(sensor.name);
|
||||
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
|
||||
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
|
||||
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux");
|
||||
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux");
|
||||
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux");
|
||||
Serial.println("------------------------------------");
|
||||
Serial.println("");
|
||||
```
|
||||
@@ -0,0 +1,9 @@
|
||||
name=Adafruit Unified Sensor
|
||||
version=1.0.2
|
||||
author=Adafruit <info@adafruit.com>
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=Required for all Adafruit Unified Sensor based libraries.
|
||||
paragraph=A unified sensor abstraction layer used by many Adafruit sensor libraries.
|
||||
category=Sensors
|
||||
url=https://github.com/adafruit/Adafruit_Sensor
|
||||
architectures=*
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
Thank you for opening an issue on an Adafruit Arduino library repository. To
|
||||
improve the speed of resolution please review the following guidelines and
|
||||
common troubleshooting steps below before creating the issue:
|
||||
|
||||
- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use
|
||||
the forums at http://forums.adafruit.com to ask questions and troubleshoot why
|
||||
something isn't working as expected. In many cases the problem is a common issue
|
||||
that you will more quickly receive help from the forum community. GitHub issues
|
||||
are meant for known defects in the code. If you don't know if there is a defect
|
||||
in the code then start with troubleshooting on the forum first.
|
||||
|
||||
- **If following a tutorial or guide be sure you didn't miss a step.** Carefully
|
||||
check all of the steps and commands to run have been followed. Consult the
|
||||
forum if you're unsure or have questions about steps in a guide/tutorial.
|
||||
|
||||
- **For Arduino projects check these very common issues to ensure they don't apply**:
|
||||
|
||||
- For uploading sketches or communicating with the board make sure you're using
|
||||
a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes
|
||||
very hard to tell the difference between a data and charge cable! Try using the
|
||||
cable with other devices or swapping to another cable to confirm it is not
|
||||
the problem.
|
||||
|
||||
- **Be sure you are supplying adequate power to the board.** Check the specs of
|
||||
your board and plug in an external power supply. In many cases just
|
||||
plugging a board into your computer is not enough to power it and other
|
||||
peripherals.
|
||||
|
||||
- **Double check all soldering joints and connections.** Flakey connections
|
||||
cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints.
|
||||
|
||||
- **Ensure you are using an official Arduino or Adafruit board.** We can't
|
||||
guarantee a clone board will have the same functionality and work as expected
|
||||
with this code and don't support them.
|
||||
|
||||
If you're sure this issue is a defect in the code and checked the steps above
|
||||
please fill in the following fields to provide enough troubleshooting information.
|
||||
You may delete the guideline and text above to just leave the following details:
|
||||
|
||||
- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE**
|
||||
|
||||
- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO
|
||||
VERSION HERE**
|
||||
|
||||
- List the steps to reproduce the problem below (if possible attach a sketch or
|
||||
copy the sketch code in too): **LIST REPRO STEPS BELOW**
|
||||
@@ -0,0 +1,26 @@
|
||||
Thank you for creating a pull request to contribute to Adafruit's GitHub code!
|
||||
Before you open the request please review the following guidelines and tips to
|
||||
help it be more easily integrated:
|
||||
|
||||
- **Describe the scope of your change--i.e. what the change does and what parts
|
||||
of the code were modified.** This will help us understand any risks of integrating
|
||||
the code.
|
||||
|
||||
- **Describe any known limitations with your change.** For example if the change
|
||||
doesn't apply to a supported platform of the library please mention it.
|
||||
|
||||
- **Please run any tests or examples that can exercise your modified code.** We
|
||||
strive to not break users of the code and running tests/examples helps with this
|
||||
process.
|
||||
|
||||
Thank you again for contributing! We will try to test and integrate the change
|
||||
as soon as we can, but be aware we have many GitHub repositories to manage and
|
||||
can't immediately respond to every request. There is no need to bump or check in
|
||||
on a pull request (it will clutter the discussion of the request).
|
||||
|
||||
Also don't be worried if the request is closed or not integrated--sometimes the
|
||||
priorities of Adafruit's GitHub code (education, ease of use) might not match the
|
||||
priorities of the pull request. Don't fret, the open source community thrives on
|
||||
forks and GitHub makes it easy to keep your changes in a forked repo.
|
||||
|
||||
After reviewing the guidelines above you can delete this text from the pull request.
|
||||
@@ -0,0 +1,504 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file Adafruit_TSL2591.cpp
|
||||
@author KT0WN (adafruit.com)
|
||||
|
||||
This is a library for the Adafruit TSL2591 breakout board
|
||||
This library works with the Adafruit TSL2591 breakout
|
||||
----> https://www.adafruit.com/products/1980
|
||||
|
||||
Check out the links above for our tutorials and wiring diagrams
|
||||
These chips use I2C to communicate
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2014 Adafruit Industries
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
#include <pgmspace.h>
|
||||
#else
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
#if defined(__AVR__)
|
||||
#include <util/delay.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Adafruit_TSL2591.h"
|
||||
|
||||
Adafruit_TSL2591::Adafruit_TSL2591(int32_t sensorID)
|
||||
{
|
||||
_initialized = false;
|
||||
_integration = TSL2591_INTEGRATIONTIME_100MS;
|
||||
_gain = TSL2591_GAIN_MED;
|
||||
_sensorID = sensorID;
|
||||
|
||||
// we cant do wire initialization till later, because we havent loaded Wire yet
|
||||
}
|
||||
|
||||
boolean Adafruit_TSL2591::begin(void)
|
||||
{
|
||||
Wire.begin();
|
||||
|
||||
/*
|
||||
for (uint8_t i=0; i<0x20; i++)
|
||||
{
|
||||
uint8_t id = read8(0x12);
|
||||
Serial.print("$"); Serial.print(i, HEX);
|
||||
Serial.print(" = 0x"); Serial.println(read8(i), HEX);
|
||||
}
|
||||
*/
|
||||
|
||||
uint8_t id = read8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_DEVICE_ID);
|
||||
if (id == 0x50 )
|
||||
{
|
||||
// Serial.println("Found Adafruit_TSL2591");
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
|
||||
// Set default integration time and gain
|
||||
setTiming(_integration);
|
||||
setGain(_gain);
|
||||
|
||||
// Note: by default, the device is in power down mode on bootup
|
||||
disable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Adafruit_TSL2591::enable(void)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
if (!begin())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the device by setting the control bit to 0x01
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_ENABLE, TSL2591_ENABLE_POWERON | TSL2591_ENABLE_AEN | TSL2591_ENABLE_AIEN | TSL2591_ENABLE_NPIEN);
|
||||
}
|
||||
|
||||
void Adafruit_TSL2591::disable(void)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
if (!begin())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Disable the device by setting the control bit to 0x00
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_ENABLE, TSL2591_ENABLE_POWEROFF);
|
||||
}
|
||||
|
||||
void Adafruit_TSL2591::setGain(tsl2591Gain_t gain)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
if (!begin())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
enable();
|
||||
_gain = gain;
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, _integration | _gain);
|
||||
disable();
|
||||
}
|
||||
|
||||
tsl2591Gain_t Adafruit_TSL2591::getGain()
|
||||
{
|
||||
return _gain;
|
||||
}
|
||||
|
||||
void Adafruit_TSL2591::setTiming(tsl2591IntegrationTime_t integration)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
if (!begin())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
enable();
|
||||
_integration = integration;
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, _integration | _gain);
|
||||
disable();
|
||||
}
|
||||
|
||||
tsl2591IntegrationTime_t Adafruit_TSL2591::getTiming()
|
||||
{
|
||||
return _integration;
|
||||
}
|
||||
|
||||
float Adafruit_TSL2591::calculateLuxf(uint16_t ch0, uint16_t ch1)
|
||||
{
|
||||
float atime, again;
|
||||
float cpl, lux1, lux2, lux;
|
||||
uint32_t chan0, chan1;
|
||||
|
||||
// Check for overflow conditions first
|
||||
if ((ch0 == 0xFFFF) | (ch1 == 0xFFFF))
|
||||
{
|
||||
// Signal an overflow
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Note: This algorithm is based on preliminary coefficients
|
||||
// provided by AMS and may need to be updated in the future
|
||||
|
||||
switch (_integration)
|
||||
{
|
||||
case TSL2591_INTEGRATIONTIME_100MS :
|
||||
atime = 100.0F;
|
||||
break;
|
||||
case TSL2591_INTEGRATIONTIME_200MS :
|
||||
atime = 200.0F;
|
||||
break;
|
||||
case TSL2591_INTEGRATIONTIME_300MS :
|
||||
atime = 300.0F;
|
||||
break;
|
||||
case TSL2591_INTEGRATIONTIME_400MS :
|
||||
atime = 400.0F;
|
||||
break;
|
||||
case TSL2591_INTEGRATIONTIME_500MS :
|
||||
atime = 500.0F;
|
||||
break;
|
||||
case TSL2591_INTEGRATIONTIME_600MS :
|
||||
atime = 600.0F;
|
||||
break;
|
||||
default: // 100ms
|
||||
atime = 100.0F;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (_gain)
|
||||
{
|
||||
case TSL2591_GAIN_LOW :
|
||||
again = 1.0F;
|
||||
break;
|
||||
case TSL2591_GAIN_MED :
|
||||
again = 25.0F;
|
||||
break;
|
||||
case TSL2591_GAIN_HIGH :
|
||||
again = 428.0F;
|
||||
break;
|
||||
case TSL2591_GAIN_MAX :
|
||||
again = 9876.0F;
|
||||
break;
|
||||
default:
|
||||
again = 1.0F;
|
||||
break;
|
||||
}
|
||||
|
||||
// cpl = (ATIME * AGAIN) / DF
|
||||
cpl = (atime * again) / TSL2591_LUX_DF;
|
||||
|
||||
lux1 = (((float) ch0 - (float) ch1)) * (1.0F - ((float) ch1 / (float) ch0)) / cpl;//( (float)ch0 - (TSL2591_LUX_COEFB * (float)ch1) ) / cpl;
|
||||
lux2 = ((TSL2591_LUX_COEFC * (float) ch0) - (TSL2591_LUX_COEFD * (float) ch1)) / cpl;
|
||||
lux = lux1 > lux2 ? lux1 : lux2;
|
||||
|
||||
// Alternate lux calculation
|
||||
//lux = ( (float)ch0 - ( 1.7F * (float)ch1 ) ) / cpl;
|
||||
|
||||
// Signal I2C had no errors
|
||||
return lux;
|
||||
}
|
||||
|
||||
uint32_t Adafruit_TSL2591::calculateLux(uint16_t ch0, uint16_t ch1)
|
||||
{
|
||||
return (uint32_t) calculateLuxf(ch0, ch1);
|
||||
}
|
||||
|
||||
uint32_t Adafruit_TSL2591::getFullLuminosity (void)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
if (!begin())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the device
|
||||
enable();
|
||||
|
||||
// Wait x ms for ADC to complete
|
||||
for (uint8_t d=0; d<=_integration; d++)
|
||||
{
|
||||
delay(120);
|
||||
}
|
||||
|
||||
uint32_t x;
|
||||
uint16_t y;
|
||||
y |= read16(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN0_LOW);
|
||||
x = read16(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN1_LOW);
|
||||
x <<= 16;
|
||||
x |= y;
|
||||
|
||||
disable();
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
uint16_t Adafruit_TSL2591::getLuminosity (uint8_t channel)
|
||||
{
|
||||
uint32_t x = getFullLuminosity();
|
||||
|
||||
if (channel == TSL2591_FULLSPECTRUM)
|
||||
{
|
||||
// Reads two byte value from channel 0 (visible + infrared)
|
||||
return (x & 0xFFFF);
|
||||
}
|
||||
else if (channel == TSL2591_INFRARED)
|
||||
{
|
||||
// Reads two byte value from channel 1 (infrared)
|
||||
return (x >> 16);
|
||||
}
|
||||
else if (channel == TSL2591_VISIBLE)
|
||||
{
|
||||
// Reads all and subtracts out just the visible!
|
||||
return ( (x & 0xFFFF) - (x >> 16));
|
||||
}
|
||||
|
||||
// unknown channel!
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Adafruit_TSL2591::registerInterrupt(uint16_t lowerThreshold, uint16_t upperThreshold)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
if (!begin())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
enable();
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_NPAILTL, lowerThreshold);
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_NPAILTH, lowerThreshold >> 8);
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_NPAIHTL, upperThreshold);
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_NPAIHTH, upperThreshold >> 8);
|
||||
disable();
|
||||
}
|
||||
|
||||
void Adafruit_TSL2591::registerInterrupt(uint16_t lowerThreshold, uint16_t upperThreshold, tsl2591Persist_t persist)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
if (!begin())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
enable();
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_PERSIST_FILTER, persist);
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_AILTL, lowerThreshold);
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_AILTH, lowerThreshold >> 8);
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_AIHTL, upperThreshold);
|
||||
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_THRESHOLD_AIHTH, upperThreshold >> 8);
|
||||
disable();
|
||||
}
|
||||
|
||||
void Adafruit_TSL2591::clearInterrupt()
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
if (!begin())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
enable();
|
||||
write8(TSL2591_CLEAR_INT);
|
||||
disable();
|
||||
}
|
||||
|
||||
|
||||
uint8_t Adafruit_TSL2591::getStatus()
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
if (!begin())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the device
|
||||
enable();
|
||||
uint8_t x;
|
||||
x = read8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_DEVICE_STATUS);
|
||||
disable();
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
uint8_t Adafruit_TSL2591::read8(uint8_t reg)
|
||||
{
|
||||
uint8_t x;
|
||||
|
||||
Wire.beginTransmission(TSL2591_ADDR);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write(reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(TSL2591_ADDR, 1);
|
||||
#if ARDUINO >= 100
|
||||
x = Wire.read();
|
||||
#else
|
||||
x = Wire.receive();
|
||||
#endif
|
||||
// while (! Wire.available());
|
||||
// return Wire.read();
|
||||
return x;
|
||||
}
|
||||
|
||||
uint16_t Adafruit_TSL2591::read16(uint8_t reg)
|
||||
{
|
||||
uint16_t x;
|
||||
uint16_t t;
|
||||
|
||||
Wire.beginTransmission(TSL2591_ADDR);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write(reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(TSL2591_ADDR, 2);
|
||||
#if ARDUINO >= 100
|
||||
t = Wire.read();
|
||||
x = Wire.read();
|
||||
#else
|
||||
t = Wire.receive();
|
||||
x = Wire.receive();
|
||||
#endif
|
||||
x <<= 8;
|
||||
x |= t;
|
||||
return x;
|
||||
}
|
||||
|
||||
void Adafruit_TSL2591::write8 (uint8_t reg, uint8_t value)
|
||||
{
|
||||
Wire.beginTransmission(TSL2591_ADDR);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write(reg);
|
||||
Wire.write(value);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
Wire.send(value);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
|
||||
void Adafruit_TSL2591::write8 (uint8_t reg)
|
||||
{
|
||||
Wire.beginTransmission(TSL2591_ADDR);
|
||||
#if ARDUINO >= 100
|
||||
Wire.write(reg);
|
||||
#else
|
||||
Wire.send(reg);
|
||||
#endif
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the most recent sensor event
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_TSL2591::getEvent(sensors_event_t *event)
|
||||
{
|
||||
uint16_t ir, full;
|
||||
uint32_t lum = getFullLuminosity();
|
||||
/* Early silicon seems to have issues when there is a sudden jump in */
|
||||
/* light levels. :( To work around this for now sample the sensor 2x */
|
||||
lum = getFullLuminosity();
|
||||
ir = lum >> 16;
|
||||
full = lum & 0xFFFF;
|
||||
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _sensorID;
|
||||
event->type = SENSOR_TYPE_LIGHT;
|
||||
event->timestamp = millis();
|
||||
|
||||
/* Calculate the actual lux value */
|
||||
/* 0 = sensor overflow (too much light) */
|
||||
event->light = calculateLux(full, ir);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the sensor_t data
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_TSL2591::getSensor(sensor_t *sensor)
|
||||
{
|
||||
/* Clear the sensor_t object */
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
|
||||
/* Insert the sensor name in the fixed length char array */
|
||||
strncpy (sensor->name, "TSL2591", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name)- 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _sensorID;
|
||||
sensor->type = SENSOR_TYPE_LIGHT;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = 88000.0;
|
||||
sensor->min_value = 0.0;
|
||||
sensor->resolution = 1.0;
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file Adafruit_TSL2591.h
|
||||
@author KT0WN (adafruit.com)
|
||||
|
||||
This is a library for the Adafruit TSL2591 breakout board
|
||||
This library works with the Adafruit TSL2591 breakout
|
||||
----> https://www.adafruit.com/products/1980
|
||||
|
||||
Check out the links above for our tutorials and wiring diagrams
|
||||
These chips use I2C to communicate
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2014 Adafruit Industries
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef _TSL2591_H_
|
||||
#define _TSL2591_H_
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Wire.h>
|
||||
|
||||
#define TSL2591_VISIBLE (2) // channel 0 - channel 1
|
||||
#define TSL2591_INFRARED (1) // channel 1
|
||||
#define TSL2591_FULLSPECTRUM (0) // channel 0
|
||||
|
||||
#define TSL2591_ADDR (0x29)
|
||||
#define TSL2591_READBIT (0x01)
|
||||
|
||||
#define TSL2591_COMMAND_BIT (0xA0) // 1010 0000: bits 7 and 5 for 'command normal'
|
||||
#define TSL2591_CLEAR_INT (0xE7)
|
||||
#define TSL2591_TEST_INT (0xE4)
|
||||
#define TSL2591_WORD_BIT (0x20) // 1 = read/write word (rather than byte)
|
||||
#define TSL2591_BLOCK_BIT (0x10) // 1 = using block read/write
|
||||
|
||||
#define TSL2591_ENABLE_POWEROFF (0x00)
|
||||
#define TSL2591_ENABLE_POWERON (0x01)
|
||||
#define TSL2591_ENABLE_AEN (0x02) // ALS Enable. This field activates ALS function. Writing a one activates the ALS. Writing a zero disables the ALS.
|
||||
#define TSL2591_ENABLE_AIEN (0x10) // ALS Interrupt Enable. When asserted permits ALS interrupts to be generated, subject to the persist filter.
|
||||
#define TSL2591_ENABLE_NPIEN (0x80) // No Persist Interrupt Enable. When asserted NP Threshold conditions will generate an interrupt, bypassing the persist filter
|
||||
|
||||
#define TSL2591_LUX_DF (408.0F)
|
||||
#define TSL2591_LUX_COEFB (1.64F) // CH0 coefficient
|
||||
#define TSL2591_LUX_COEFC (0.59F) // CH1 coefficient A
|
||||
#define TSL2591_LUX_COEFD (0.86F) // CH2 coefficient B
|
||||
|
||||
enum
|
||||
{
|
||||
TSL2591_REGISTER_ENABLE = 0x00,
|
||||
TSL2591_REGISTER_CONTROL = 0x01,
|
||||
TSL2591_REGISTER_THRESHOLD_AILTL = 0x04, // ALS low threshold lower byte
|
||||
TSL2591_REGISTER_THRESHOLD_AILTH = 0x05, // ALS low threshold upper byte
|
||||
TSL2591_REGISTER_THRESHOLD_AIHTL = 0x06, // ALS high threshold lower byte
|
||||
TSL2591_REGISTER_THRESHOLD_AIHTH = 0x07, // ALS high threshold upper byte
|
||||
TSL2591_REGISTER_THRESHOLD_NPAILTL = 0x08, // No Persist ALS low threshold lower byte
|
||||
TSL2591_REGISTER_THRESHOLD_NPAILTH = 0x09, // etc
|
||||
TSL2591_REGISTER_THRESHOLD_NPAIHTL = 0x0A,
|
||||
TSL2591_REGISTER_THRESHOLD_NPAIHTH = 0x0B,
|
||||
TSL2591_REGISTER_PERSIST_FILTER = 0x0C,
|
||||
TSL2591_REGISTER_PACKAGE_PID = 0x11,
|
||||
TSL2591_REGISTER_DEVICE_ID = 0x12,
|
||||
TSL2591_REGISTER_DEVICE_STATUS = 0x13,
|
||||
TSL2591_REGISTER_CHAN0_LOW = 0x14,
|
||||
TSL2591_REGISTER_CHAN0_HIGH = 0x15,
|
||||
TSL2591_REGISTER_CHAN1_LOW = 0x16,
|
||||
TSL2591_REGISTER_CHAN1_HIGH = 0x17
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TSL2591_INTEGRATIONTIME_100MS = 0x00,
|
||||
TSL2591_INTEGRATIONTIME_200MS = 0x01,
|
||||
TSL2591_INTEGRATIONTIME_300MS = 0x02,
|
||||
TSL2591_INTEGRATIONTIME_400MS = 0x03,
|
||||
TSL2591_INTEGRATIONTIME_500MS = 0x04,
|
||||
TSL2591_INTEGRATIONTIME_600MS = 0x05,
|
||||
}
|
||||
tsl2591IntegrationTime_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
// bit 7:4: 0
|
||||
TSL2591_PERSIST_EVERY = 0x00, // Every ALS cycle generates an interrupt
|
||||
TSL2591_PERSIST_ANY = 0x01, // Any value outside of threshold range
|
||||
TSL2591_PERSIST_2 = 0x02, // 2 consecutive values out of range
|
||||
TSL2591_PERSIST_3 = 0x03, // 3 consecutive values out of range
|
||||
TSL2591_PERSIST_5 = 0x04, // 5 consecutive values out of range
|
||||
TSL2591_PERSIST_10 = 0x05, // 10 consecutive values out of range
|
||||
TSL2591_PERSIST_15 = 0x06, // 15 consecutive values out of range
|
||||
TSL2591_PERSIST_20 = 0x07, // 20 consecutive values out of range
|
||||
TSL2591_PERSIST_25 = 0x08, // 25 consecutive values out of range
|
||||
TSL2591_PERSIST_30 = 0x09, // 30 consecutive values out of range
|
||||
TSL2591_PERSIST_35 = 0x0A, // 35 consecutive values out of range
|
||||
TSL2591_PERSIST_40 = 0x0B, // 40 consecutive values out of range
|
||||
TSL2591_PERSIST_45 = 0x0C, // 45 consecutive values out of range
|
||||
TSL2591_PERSIST_50 = 0x0D, // 50 consecutive values out of range
|
||||
TSL2591_PERSIST_55 = 0x0E, // 55 consecutive values out of range
|
||||
TSL2591_PERSIST_60 = 0x0F, // 60 consecutive values out of range
|
||||
}
|
||||
tsl2591Persist_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TSL2591_GAIN_LOW = 0x00, // low gain (1x)
|
||||
TSL2591_GAIN_MED = 0x10, // medium gain (25x)
|
||||
TSL2591_GAIN_HIGH = 0x20, // medium gain (428x)
|
||||
TSL2591_GAIN_MAX = 0x30, // max gain (9876x)
|
||||
}
|
||||
tsl2591Gain_t;
|
||||
|
||||
class Adafruit_TSL2591 : public Adafruit_Sensor
|
||||
{
|
||||
public:
|
||||
Adafruit_TSL2591(int32_t sensorID = -1);
|
||||
|
||||
boolean begin ( void );
|
||||
void enable ( void );
|
||||
void disable ( void );
|
||||
void write8 ( uint8_t r);
|
||||
void write8 ( uint8_t r, uint8_t v );
|
||||
uint16_t read16 ( uint8_t reg );
|
||||
uint8_t read8 ( uint8_t reg );
|
||||
|
||||
uint32_t calculateLux ( uint16_t ch0, uint16_t ch1 );
|
||||
float calculateLuxf ( uint16_t ch0, uint16_t ch1 );
|
||||
void setGain ( tsl2591Gain_t gain );
|
||||
void setTiming ( tsl2591IntegrationTime_t integration );
|
||||
uint16_t getLuminosity (uint8_t channel );
|
||||
uint32_t getFullLuminosity ( );
|
||||
|
||||
tsl2591IntegrationTime_t getTiming();
|
||||
tsl2591Gain_t getGain();
|
||||
|
||||
// Interrupt
|
||||
void clearInterrupt(void);
|
||||
void registerInterrupt(uint16_t lowerThreshold, uint16_t upperThreshold);
|
||||
void registerInterrupt(uint16_t lowerThreshold, uint16_t upperThreshold, tsl2591Persist_t persist);
|
||||
uint8_t getStatus();
|
||||
|
||||
/* Unified Sensor API Functions */
|
||||
bool getEvent ( sensors_event_t* );
|
||||
void getSensor ( sensor_t* );
|
||||
|
||||
private:
|
||||
tsl2591IntegrationTime_t _integration;
|
||||
tsl2591Gain_t _gain;
|
||||
int32_t _sensorID;
|
||||
|
||||
boolean _initialized;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
This is an Arduino library for the TSL2591 digital luminosity (light) sensors.
|
||||
|
||||
Pick one up at http://www.adafruit.com/products/1980
|
||||
|
||||
To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_TSL2591. Check that the Adafruit_TSL2591 folder contains Adafruit_TSL2591.cpp and Adafruit_TSL2591.h
|
||||
|
||||
Place the Adafruit_TSL2591 library folder your <arduinosketchfolder>/libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE.
|
||||
|
||||
You'll also need the Adafruit_Sensor library from https://github.com/adafruit/Adafruit_Sensor
|
||||
@@ -0,0 +1,200 @@
|
||||
/* TSL2591 Digital Light Sensor */
|
||||
/* Dynamic Range: 600M:1 */
|
||||
/* Maximum Lux: 88K */
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include "Adafruit_TSL2591.h"
|
||||
|
||||
// Example for demonstrating the TSL2591 library - public domain!
|
||||
|
||||
// connect SCL to analog 5
|
||||
// connect SDA to analog 4
|
||||
// connect Vin to 3.3-5V DC
|
||||
// connect GROUND to common ground
|
||||
|
||||
Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // pass in a number for the sensor identifier (for your use later)
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Displays some basic information on this sensor from the unified
|
||||
sensor API sensor_t type (see Adafruit_Sensor for more information)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void displaySensorDetails(void)
|
||||
{
|
||||
sensor_t sensor;
|
||||
tsl.getSensor(&sensor);
|
||||
Serial.println(F("------------------------------------"));
|
||||
Serial.print (F("Sensor: ")); Serial.println(sensor.name);
|
||||
Serial.print (F("Driver Ver: ")); Serial.println(sensor.version);
|
||||
Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id);
|
||||
Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F(" lux"));
|
||||
Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F(" lux"));
|
||||
Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F(" lux"));
|
||||
Serial.println(F("------------------------------------"));
|
||||
Serial.println(F(""));
|
||||
delay(500);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Configures the gain and integration time for the TSL2591
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void configureSensor(void)
|
||||
{
|
||||
// You can change the gain on the fly, to adapt to brighter/dimmer light situations
|
||||
//tsl.setGain(TSL2591_GAIN_LOW); // 1x gain (bright light)
|
||||
tsl.setGain(TSL2591_GAIN_MED); // 25x gain
|
||||
// tsl.setGain(TSL2591_GAIN_HIGH); // 428x gain
|
||||
|
||||
// Changing the integration time gives you a longer time over which to sense light
|
||||
// longer timelines are slower, but are good in very low light situtations!
|
||||
tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS); // shortest integration time (bright light)
|
||||
// tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS);
|
||||
// tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS);
|
||||
// tsl.setTiming(TSL2591_INTEGRATIONTIME_400MS);
|
||||
// tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS);
|
||||
// tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS); // longest integration time (dim light)
|
||||
|
||||
/* Display the gain and integration time for reference sake */
|
||||
Serial.println(F("------------------------------------"));
|
||||
Serial.print (F("Gain: "));
|
||||
tsl2591Gain_t gain = tsl.getGain();
|
||||
switch(gain)
|
||||
{
|
||||
case TSL2591_GAIN_LOW:
|
||||
Serial.println(F("1x (Low)"));
|
||||
break;
|
||||
case TSL2591_GAIN_MED:
|
||||
Serial.println(F("25x (Medium)"));
|
||||
break;
|
||||
case TSL2591_GAIN_HIGH:
|
||||
Serial.println(F("428x (High)"));
|
||||
break;
|
||||
case TSL2591_GAIN_MAX:
|
||||
Serial.println(F("9876x (Max)"));
|
||||
break;
|
||||
}
|
||||
Serial.print (F("Timing: "));
|
||||
Serial.print((tsl.getTiming() + 1) * 100, DEC);
|
||||
Serial.println(F(" ms"));
|
||||
Serial.println(F("------------------------------------"));
|
||||
Serial.println(F(""));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Program entry point for the Arduino sketch
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
Serial.println(F("Starting Adafruit TSL2591 Test!"));
|
||||
|
||||
if (tsl.begin())
|
||||
{
|
||||
Serial.println(F("Found a TSL2591 sensor"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("No sensor found ... check your wiring?"));
|
||||
while (1);
|
||||
}
|
||||
|
||||
/* Display some basic information on this sensor */
|
||||
displaySensorDetails();
|
||||
|
||||
/* Configure the sensor */
|
||||
configureSensor();
|
||||
|
||||
// Now we're ready to get readings ... move on to loop()!
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Shows how to perform a basic read on visible, full spectrum or
|
||||
infrared light (returns raw 16-bit ADC values)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void simpleRead(void)
|
||||
{
|
||||
// Simple data read example. Just read the infrared, fullspecrtrum diode
|
||||
// or 'visible' (difference between the two) channels.
|
||||
// This can take 100-600 milliseconds! Uncomment whichever of the following you want to read
|
||||
uint16_t x = tsl.getLuminosity(TSL2591_VISIBLE);
|
||||
//uint16_t x = tsl.getLuminosity(TSL2591_FULLSPECTRUM);
|
||||
//uint16_t x = tsl.getLuminosity(TSL2591_INFRARED);
|
||||
|
||||
Serial.print(F("[ ")); Serial.print(millis()); Serial.print(F(" ms ] "));
|
||||
Serial.print(F("Luminosity: "));
|
||||
Serial.println(x, DEC);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Show how to read IR and Full Spectrum at once and convert to lux
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void advancedRead(void)
|
||||
{
|
||||
// More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
|
||||
// That way you can do whatever math and comparisons you want!
|
||||
uint32_t lum = tsl.getFullLuminosity();
|
||||
uint16_t ir, full;
|
||||
ir = lum >> 16;
|
||||
full = lum & 0xFFFF;
|
||||
Serial.print(F("[ ")); Serial.print(millis()); Serial.print(F(" ms ] "));
|
||||
Serial.print(F("IR: ")); Serial.print(ir); Serial.print(F(" "));
|
||||
Serial.print(F("Full: ")); Serial.print(full); Serial.print(F(" "));
|
||||
Serial.print(F("Visible: ")); Serial.print(full - ir); Serial.print(F(" "));
|
||||
Serial.print(F("Lux: ")); Serial.println(tsl.calculateLux(full, ir));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Performs a read using the Adafruit Unified Sensor API.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void unifiedSensorAPIRead(void)
|
||||
{
|
||||
/* Get a new sensor event */
|
||||
sensors_event_t event;
|
||||
tsl.getEvent(&event);
|
||||
|
||||
/* Display the results (light is measured in lux) */
|
||||
Serial.print(F("[ ")); Serial.print(event.timestamp); Serial.print(F(" ms ] "));
|
||||
if ((event.light == 0) |
|
||||
(event.light > 4294966000.0) |
|
||||
(event.light <-4294966000.0))
|
||||
{
|
||||
/* If event.light = 0 lux the sensor is probably saturated */
|
||||
/* and no reliable data could be generated! */
|
||||
/* if event.light is +/- 4294967040 there was a float over/underflow */
|
||||
Serial.println(F("Invalid data (adjust gain or timing)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(event.light); Serial.println(F(" lux"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Arduino loop function, called once 'setup' is complete (your own code
|
||||
should go here)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void loop(void)
|
||||
{
|
||||
//simpleRead();
|
||||
advancedRead();
|
||||
// unifiedSensorAPIRead();
|
||||
|
||||
delay(500);
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/* TSL2591 Digital Light Sensor, example with (simple) interrupt support */
|
||||
/* Dynamic Range: 600M:1 */
|
||||
/* Maximum Lux: 88K */
|
||||
|
||||
/* This example shows how the interrupt system on the TLS2591
|
||||
* can be used to detect a meaningful change in light levels.
|
||||
*
|
||||
* Two thresholds can be set:
|
||||
*
|
||||
* Lower Threshold - Any light sample on CHAN0 below this value
|
||||
* will trigger an interrupt
|
||||
* Upper Threshold - Any light sample on CHAN0 above this value
|
||||
* will trigger an interrupt
|
||||
*
|
||||
* If CHAN0 (full light) crosses below the low threshold specified,
|
||||
* or above the higher threshold, an interrupt is asserted on the interrupt
|
||||
* pin. The use of the HW pin is optional, though, since the change can
|
||||
* also be detected in software by looking at the status byte via
|
||||
* tsl.getStatus().
|
||||
*
|
||||
* An optional third parameter can be used in the .registerInterrupt
|
||||
* function to indicate the number of samples that must stay outside
|
||||
* the threshold window before the interrupt fires, providing some basic
|
||||
* debouncing of light level data.
|
||||
*
|
||||
* For example, the following code will fire an interrupt on any and every
|
||||
* sample outside the window threshold (meaning a sample below 100 or above
|
||||
* 1500 on CHAN0 or FULL light):
|
||||
*
|
||||
* tsl.registerInterrupt(100, 1500, TSL2591_PERSIST_ANY);
|
||||
*
|
||||
* This code would require five consecutive changes before the interrupt
|
||||
* fires though (see tls2591Persist_t in Adafruit_TLS2591.h for possible
|
||||
* values):
|
||||
*
|
||||
* tsl.registerInterrupt(100, 1500, TSL2591_PERSIST_5);
|
||||
*/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include "Adafruit_TSL2591.h"
|
||||
|
||||
// Example for demonstrating the TSL2591 library - public domain!
|
||||
|
||||
// connect SCL to analog 5
|
||||
// connect SDA to analog 4
|
||||
// connect Vin to 3.3-5V DC
|
||||
// connect GROUND to common ground
|
||||
|
||||
// Interrupt thresholds and persistance
|
||||
#define TLS2591_INT_THRESHOLD_LOWER (100)
|
||||
#define TLS2591_INT_THRESHOLD_UPPER (1500)
|
||||
//#define TLS2591_INT_PERSIST (TSL2591_PERSIST_ANY) // Fire on any valid change
|
||||
#define TLS2591_INT_PERSIST (TSL2591_PERSIST_60) // Require at least 60 samples to fire
|
||||
|
||||
Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // pass in a number for the sensor identifier (for your use later)
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Displays some basic information on this sensor from the unified
|
||||
sensor API sensor_t type (see Adafruit_Sensor for more information)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void displaySensorDetails(void)
|
||||
{
|
||||
sensor_t sensor;
|
||||
tsl.getSensor(&sensor);
|
||||
Serial.println("------------------------------------");
|
||||
Serial.print ("Sensor: "); Serial.println(sensor.name);
|
||||
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
|
||||
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
|
||||
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux");
|
||||
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux");
|
||||
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux");
|
||||
Serial.println("------------------------------------");
|
||||
Serial.println("");
|
||||
delay(500);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Configures the gain and integration time for the TSL2591
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void configureSensor(void)
|
||||
{
|
||||
// You can change the gain on the fly, to adapt to brighter/dimmer light situations
|
||||
//tsl.setGain(TSL2591_GAIN_LOW); // 1x gain (bright light)
|
||||
tsl.setGain(TSL2591_GAIN_MED); // 25x gain
|
||||
// tsl.setGain(TSL2591_GAIN_HIGH); // 428x gain
|
||||
|
||||
// Changing the integration time gives you a longer time over which to sense light
|
||||
// longer timelines are slower, but are good in very low light situtations!
|
||||
tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS); // shortest integration time (bright light)
|
||||
// tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS);
|
||||
// tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS);
|
||||
// tsl.setTiming(TSL2591_INTEGRATIONTIME_400MS);
|
||||
// tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS);
|
||||
// tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS); // longest integration time (dim light)
|
||||
|
||||
/* Display the gain and integration time for reference sake */
|
||||
Serial.println("------------------------------------");
|
||||
Serial.print ("Gain: ");
|
||||
tsl2591Gain_t gain = tsl.getGain();
|
||||
switch (gain)
|
||||
{
|
||||
case TSL2591_GAIN_LOW:
|
||||
Serial.println("1x (Low)");
|
||||
break;
|
||||
case TSL2591_GAIN_MED:
|
||||
Serial.println("25x (Medium)");
|
||||
break;
|
||||
case TSL2591_GAIN_HIGH:
|
||||
Serial.println("428x (High)");
|
||||
break;
|
||||
case TSL2591_GAIN_MAX:
|
||||
Serial.println("9876x (Max)");
|
||||
break;
|
||||
}
|
||||
Serial.print ("Timing: ");
|
||||
Serial.print((tsl.getTiming() + 1) * 100, DEC);
|
||||
Serial.println(" ms");
|
||||
Serial.println("------------------------------------");
|
||||
Serial.println("");
|
||||
|
||||
/* Setup the SW interrupt to trigger between 100 and 1500 lux */
|
||||
/* Threshold values are defined at the top of this sketch */
|
||||
tsl.clearInterrupt();
|
||||
tsl.registerInterrupt(TLS2591_INT_THRESHOLD_LOWER,
|
||||
TLS2591_INT_THRESHOLD_UPPER,
|
||||
TLS2591_INT_PERSIST);
|
||||
|
||||
/* Display the interrupt threshold window */
|
||||
Serial.print("Interrupt Threshold Window: -");
|
||||
Serial.print(TLS2591_INT_THRESHOLD_LOWER, DEC);
|
||||
Serial.print(" to +");
|
||||
Serial.println(TLS2591_INT_THRESHOLD_LOWER, DEC);
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Program entry point for the Arduino sketch
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void setup(void)
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
// Enable this line for Flora, Zero and Feather boards with no FTDI chip
|
||||
// Waits for the serial port to connect before sending data out
|
||||
// while (!Serial) { delay(1); }
|
||||
|
||||
Serial.println("Starting Adafruit TSL2591 interrupt Test!");
|
||||
|
||||
if (tsl.begin())
|
||||
{
|
||||
Serial.println("Found a TSL2591 sensor");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("No sensor found ... check your wiring?");
|
||||
while (1);
|
||||
}
|
||||
|
||||
/* Display some basic information on this sensor */
|
||||
displaySensorDetails();
|
||||
|
||||
/* Configure the sensor (including the interrupt threshold) */
|
||||
configureSensor();
|
||||
|
||||
// Now we're ready to get readings ... move on to loop()!
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Show how to read IR and Full Spectrum at once and convert to lux
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void advancedRead(void)
|
||||
{
|
||||
// More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
|
||||
// That way you can do whatever math and comparisons you want!
|
||||
uint32_t lum = tsl.getFullLuminosity();
|
||||
uint16_t ir, full;
|
||||
ir = lum >> 16;
|
||||
full = lum & 0xFFFF;
|
||||
Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
|
||||
Serial.print("IR: "); Serial.print(ir); Serial.print(" ");
|
||||
Serial.print("Full: "); Serial.print(full); Serial.print(" ");
|
||||
Serial.print("Visible: "); Serial.print(full - ir); Serial.print(" ");
|
||||
Serial.print("Lux: "); Serial.println(tsl.calculateLux(full, ir));
|
||||
}
|
||||
|
||||
|
||||
void getStatus(void)
|
||||
{
|
||||
uint8_t x = tsl.getStatus();
|
||||
// bit 4: ALS Interrupt occured
|
||||
// bit 5: No-persist Interrupt occurence
|
||||
if (x & 0x10) {
|
||||
Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
|
||||
Serial.println("ALS Interrupt occured");
|
||||
}
|
||||
if (x & 0x20) {
|
||||
Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
|
||||
Serial.println("No-persist Interrupt occured");
|
||||
}
|
||||
|
||||
// Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
|
||||
Serial.print("Status: ");
|
||||
Serial.println(x, BIN);
|
||||
tsl.clearInterrupt();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*
|
||||
Arduino loop function, called once 'setup' is complete (your own code
|
||||
should go here)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void loop(void)
|
||||
{
|
||||
advancedRead();
|
||||
getStatus();
|
||||
delay(500);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
name=Adafruit TSL2591 Library
|
||||
version=1.0.2
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=Library for the TSL2591 digital luminosity (light) sensors.
|
||||
paragraph=Library for the TSL2591 digital luminosity (light) sensors.
|
||||
category=Sensors
|
||||
url=https://github.com/adafruit/Adafruit_TSL2591_Library
|
||||
architectures=*
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Name: PingTest.ino
|
||||
Created: 05/08/2017 10:20:19
|
||||
Author: pbecc
|
||||
*/
|
||||
#undef PROVA_
|
||||
|
||||
|
||||
#include <WiFi.h>
|
||||
#include "esp32_ping.h"
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
const char ssid[] = "TP-LINK_C20B"; // your network SSID (name)
|
||||
const char password[] = "paolo-48"; // your network password
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.print("Connecting t ");
|
||||
Serial.println(ssid);
|
||||
// WiFi.mode(WIFI_STA);
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
|
||||
|
||||
}
|
||||
Serial.println("Pinging address: 192.168.1.1");
|
||||
}
|
||||
|
||||
// the loop function runs over and over again until power down or reset
|
||||
void loop() {
|
||||
int ia[4] = { 192,168,1,1 };
|
||||
int i = 0;
|
||||
while (Serial.available()) {
|
||||
|
||||
char c = Serial.read();
|
||||
delay(100);
|
||||
int val = 0;
|
||||
while (c != '.' && c != 10 && c!=255) {
|
||||
if (c >= '0'&& c<='9') {
|
||||
val = val*10+(c-'0');
|
||||
}
|
||||
c = Serial.read();
|
||||
}
|
||||
|
||||
ia[i++] =val ;
|
||||
}
|
||||
IPAddress adr = IPAddress(ia[0], ia[1], ia[2], ia[3]);
|
||||
Serial.printf("Ping : %d . %d . %d . %d ->", ia[0], ia[1], ia[2], ia[3]);
|
||||
if (ping_start(adr, 4, 0, 0, 5))
|
||||
Serial.println("OK");
|
||||
else
|
||||
Serial.println("FAILED");
|
||||
delay(10000);
|
||||
|
||||
}
|
||||
int readnu(char s) {
|
||||
char c = Serial.read();
|
||||
Serial.print(c);
|
||||
int digit = 1,val=0;
|
||||
while (c != s && c != 10&&c>0) {
|
||||
if(c>'0') val += digit*(c - '0');
|
||||
digit *= 10;
|
||||
c=Serial.read();
|
||||
Serial.print(int(c));
|
||||
}
|
||||
Serial.println(digit);
|
||||
return digit;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# ESP32_ping
|
||||
Ping library for ESP32
|
||||
|
||||
WORK IN PROGRESS
|
||||
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* ESP32 Ping library
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* and its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice appear in all
|
||||
* copies and that both that the copyright notice and this
|
||||
* permission notice and warranty disclaimer appear in supporting
|
||||
* documentation, and that the name of the author not be used in
|
||||
* advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
*
|
||||
* The author disclaim all warranties with regard to this
|
||||
* software, including all implied warranties of merchantability
|
||||
* and fitness. In no event shall the author be liable for any
|
||||
* special, indirect or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether
|
||||
* in an action of contract, negligence or other tortious action,
|
||||
* arising out of or in connection with the use or performance of
|
||||
* this software.
|
||||
*
|
||||
* --------------------------------------------------------------------------------
|
||||
* Ping Library is based on the following source code:
|
||||
*
|
||||
* Lua RTOS, ping utility
|
||||
*
|
||||
*
|
||||
* Author: Jaume Oliv� (jolive@iberoxarxa.com / jolive@whitecatboard.org)
|
||||
*
|
||||
* --------------------------------------------------------------------------------
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef ESP32
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "esp32_ping.h"
|
||||
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/ip4.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/netdb.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
static uint16_t ping_seq_num;
|
||||
static uint8_t stopped = 0;
|
||||
|
||||
/*
|
||||
* Statistics
|
||||
*/
|
||||
static uint32_t transmitted = 0;
|
||||
static uint32_t received = 0;
|
||||
static float min_time = 0;
|
||||
static float max_time = 0;
|
||||
static float mean_time = 0;
|
||||
static float last_mean_time = 0;
|
||||
static float var_time = 0;
|
||||
|
||||
#define PING_ID 0xAFAF
|
||||
|
||||
#define PING_DEFAULT_COUNT 10
|
||||
#define PING_DEFAULT_INTERVAL 1
|
||||
#define PING_DEFAULT_SIZE 32
|
||||
#define PING_DEFAULT_TIMEOUT 1
|
||||
|
||||
/*
|
||||
* Helper functions
|
||||
*
|
||||
*/
|
||||
static void ping_prepare_echo(struct icmp_echo_hdr *iecho, uint16_t len) {
|
||||
size_t i;
|
||||
size_t data_len = len - sizeof(struct icmp_echo_hdr);
|
||||
|
||||
ICMPH_TYPE_SET(iecho, ICMP_ECHO);
|
||||
ICMPH_CODE_SET(iecho, 0);
|
||||
iecho->chksum = 0;
|
||||
iecho->id = PING_ID;
|
||||
iecho->seqno = htons(++ping_seq_num);
|
||||
|
||||
/* fill the additional data buffer with some data */
|
||||
for (i = 0; i < data_len; i++) {
|
||||
((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
|
||||
}
|
||||
|
||||
iecho->chksum = inet_chksum(iecho, len);
|
||||
}
|
||||
|
||||
static err_t ping_send(int s, ip4_addr_t *addr, int size) {
|
||||
struct icmp_echo_hdr *iecho;
|
||||
struct sockaddr_in to;
|
||||
size_t ping_size = sizeof(struct icmp_echo_hdr) + size;
|
||||
int err;
|
||||
|
||||
iecho = (struct icmp_echo_hdr *)mem_malloc((mem_size_t)ping_size);
|
||||
if (!iecho) {
|
||||
return ERR_MEM;
|
||||
}
|
||||
|
||||
ping_prepare_echo(iecho, (uint16_t)ping_size);
|
||||
|
||||
to.sin_len = sizeof(to);
|
||||
to.sin_family = AF_INET;
|
||||
inet_addr_from_ipaddr(&to.sin_addr, addr);
|
||||
|
||||
if ((err = sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to)))) {
|
||||
transmitted++;
|
||||
}
|
||||
|
||||
return (err ? ERR_OK : ERR_VAL);
|
||||
}
|
||||
|
||||
static void ping_recv(int s) {
|
||||
char buf[64];
|
||||
int fromlen, len;
|
||||
struct sockaddr_in from;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_echo_hdr *iecho = NULL;
|
||||
char ipa[16];
|
||||
struct timeval begin;
|
||||
struct timeval end;
|
||||
uint64_t micros_begin;
|
||||
uint64_t micros_end;
|
||||
float elapsed;
|
||||
|
||||
// Register begin time
|
||||
gettimeofday(&begin, NULL);
|
||||
|
||||
// Send
|
||||
while ((len = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) {
|
||||
if (len >= (int)(sizeof(struct ip_hdr) + sizeof(struct icmp_echo_hdr))) {
|
||||
// Register end time
|
||||
gettimeofday(&end, NULL);
|
||||
|
||||
/// Get from IP address
|
||||
ip4_addr_t fromaddr;
|
||||
inet_addr_to_ipaddr(&fromaddr, &from.sin_addr);
|
||||
|
||||
strcpy(ipa, inet_ntoa(fromaddr));
|
||||
|
||||
// Get echo
|
||||
iphdr = (struct ip_hdr *)buf;
|
||||
iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4));
|
||||
|
||||
// Print ....
|
||||
if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) {
|
||||
received++;
|
||||
|
||||
// Get elapsed time in milliseconds
|
||||
micros_begin = begin.tv_sec * 1000000;
|
||||
micros_begin += begin.tv_usec;
|
||||
|
||||
micros_end = end.tv_sec * 1000000;
|
||||
micros_end += end.tv_usec;
|
||||
|
||||
elapsed = (float)(micros_end - micros_begin) / (float)1000.0;
|
||||
|
||||
// Update statistics
|
||||
// Mean and variance are computed in an incremental way
|
||||
if (elapsed < min_time) {
|
||||
min_time = elapsed;
|
||||
}
|
||||
|
||||
if (elapsed > max_time) {
|
||||
max_time = elapsed;
|
||||
}
|
||||
|
||||
last_mean_time = mean_time;
|
||||
mean_time = (((received - 1) * mean_time) + elapsed) / received;
|
||||
|
||||
if (received > 1) {
|
||||
var_time = var_time + ((elapsed - last_mean_time) * (elapsed - mean_time));
|
||||
}
|
||||
|
||||
// Print ...
|
||||
log_d("%d bytes from %s: icmp_seq=%d time=%.3f ms\r\n", len, ipa,
|
||||
ntohs(iecho->seqno), elapsed
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len < 0) {
|
||||
log_d("Request timeout for icmp_seq %d\r\n", ping_seq_num);
|
||||
}
|
||||
}
|
||||
/*
|
||||
static void stop_action(int i) {
|
||||
signal(i, SIG_DFL);
|
||||
|
||||
stopped = 1;
|
||||
}
|
||||
+/
|
||||
/*
|
||||
* Operation functions
|
||||
*
|
||||
*/
|
||||
void ping(const char *name, int count, int interval, int size, int timeout) {
|
||||
// Resolve name
|
||||
hostent * target = gethostbyname(name);
|
||||
IPAddress adr = *target->h_addr_list[0];
|
||||
if (target->h_length == 0) {
|
||||
// TODO: error not found target?????
|
||||
return;
|
||||
}
|
||||
ping_start(adr, count, interval, size, timeout);
|
||||
}
|
||||
bool ping_start(struct ping_option *ping_o) {
|
||||
|
||||
|
||||
return ping_start(ping_o->ip,ping_o->count,0,0,0);
|
||||
|
||||
}
|
||||
bool ping_start(IPAddress adr, int count=0, int interval=0, int size=0, int timeout=0) {
|
||||
// driver_error_t *error;
|
||||
struct sockaddr_in address;
|
||||
ip4_addr_t ping_target;
|
||||
int s;
|
||||
// Get default values if argument are not provided
|
||||
if (count == 0) {
|
||||
count = PING_DEFAULT_COUNT;
|
||||
}
|
||||
|
||||
if (interval == 0) {
|
||||
interval = PING_DEFAULT_INTERVAL;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
size = PING_DEFAULT_SIZE;
|
||||
}
|
||||
|
||||
if (timeout == 0) {
|
||||
timeout = PING_DEFAULT_TIMEOUT;
|
||||
}
|
||||
|
||||
// Create socket
|
||||
if ((s = socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0) {
|
||||
// TODO: error
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
address.sin_addr.s_addr = adr;
|
||||
ping_target.addr = address.sin_addr.s_addr;
|
||||
|
||||
// Setup socket
|
||||
struct timeval tout;
|
||||
|
||||
// Timeout
|
||||
tout.tv_sec = timeout;
|
||||
tout.tv_usec = 0;
|
||||
|
||||
if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tout, sizeof(tout)) < 0) {
|
||||
closesocket(s);
|
||||
// TODO: error
|
||||
return false;
|
||||
}
|
||||
|
||||
stopped = 0;
|
||||
transmitted = 0;
|
||||
received = 0;
|
||||
min_time = 1.E+9;// FLT_MAX;
|
||||
max_time = 0.0;
|
||||
mean_time = 0.0;
|
||||
var_time = 0.0;
|
||||
|
||||
// Register signal for stop ping
|
||||
//signal(SIGINT, stop_action);
|
||||
|
||||
// Begin ping ...
|
||||
char ipa[16];
|
||||
|
||||
strcpy(ipa, inet_ntoa(ping_target));
|
||||
log_i("PING %s: %d data bytes\r\n", ipa, size);
|
||||
|
||||
ping_seq_num = 0;
|
||||
|
||||
while ((ping_seq_num < count) && (!stopped)) {
|
||||
if (ping_send(s, &ping_target, size) == ERR_OK) {
|
||||
ping_recv(s);
|
||||
}
|
||||
delay( interval*1000L);
|
||||
}
|
||||
|
||||
closesocket(s);
|
||||
|
||||
log_i("%d packets transmitted, %d packets received, %.1f%% packet loss\r\n",
|
||||
transmitted,
|
||||
received,
|
||||
((((float)transmitted - (float)received) / (float)transmitted) * 100.0)
|
||||
);
|
||||
|
||||
if (received) {
|
||||
ping_resp pingresp;
|
||||
log_i("round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\r\n", min_time, mean_time, max_time, sqrt(var_time / received));
|
||||
pingresp.total_count = 10;
|
||||
pingresp.timeout_count = 10;
|
||||
pingresp.total_bytes = 1;
|
||||
pingresp.total_time = mean_time;
|
||||
pingresp.ping_err = 0;
|
||||
return true;
|
||||
// ping_o->sent_function(ping_o, (uint8*)&pingresp);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv)
|
||||
{
|
||||
if (ping_opt == NULL)
|
||||
return false;
|
||||
|
||||
ping_opt->recv_function = ping_recv;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent)
|
||||
{
|
||||
if (ping_opt == NULL)
|
||||
return false;
|
||||
|
||||
ping_opt->sent_function = ping_sent;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
|
||||
#ifndef _PING_
|
||||
#define _PING_
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef ESP32
|
||||
|
||||
typedef void(*ping_recv_function)(void* arg, void *pdata);
|
||||
typedef void(*ping_sent_function)(void* arg, void *pdata);
|
||||
|
||||
struct ping_option {
|
||||
uint32_t count;
|
||||
uint32_t ip;
|
||||
uint32_t coarse_time;
|
||||
ping_recv_function recv_function;
|
||||
ping_sent_function sent_function;
|
||||
void* reverse;
|
||||
};
|
||||
|
||||
struct ping_resp {
|
||||
uint32_t total_count;
|
||||
uint32_t resp_time;
|
||||
uint32_t seqno;
|
||||
uint32_t timeout_count;
|
||||
uint32_t bytes;
|
||||
uint32_t total_bytes;
|
||||
uint32_t total_time;
|
||||
int8_t ping_err;
|
||||
};
|
||||
|
||||
bool ping_start(struct ping_option *ping_opt);
|
||||
void ping(const char *name, int count, int interval, int size, int timeout);
|
||||
bool ping_start(IPAddress adr, int count, int interval, int size, int timeout);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
# EspESPeasySoftwareSerial
|
||||
# ESPeasySoftwareSerial
|
||||
|
||||
Implementation of the Arduino software serial library for the ESP8266
|
||||
|
||||
@@ -7,5 +7,3 @@ Speed up to 115200 baud is supported. The constructor also has an optional input
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "EspESPeasySoftwareSerial",
|
||||
"name": "ESPeasySoftwareSerial",
|
||||
"version": "3.3.1",
|
||||
"keywords": [
|
||||
"serial", "io", "softwareserial"
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#ifndef ESP8266Ping_H
|
||||
#define ESP8266Ping_H
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <Arduino.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
@@ -57,3 +58,4 @@ class PingClass {
|
||||
PingClass Ping;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
extern "C" void esp_schedule();
|
||||
extern "C" void esp_yield();
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# PlatformIO folders
|
||||
.pioenvs
|
||||
.piolibdeps
|
||||
pio
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "HLW8012",
|
||||
"license": "GPL-3.0",
|
||||
"platforms": [
|
||||
"atmelavr",
|
||||
"espressif8266"
|
||||
],
|
||||
"repository": {
|
||||
"url": "https://bitbucket.org/xoseperez/hlw8012.git",
|
||||
"type": "git"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"version": "1.0.0",
|
||||
"export": {
|
||||
"exclude": "tests"
|
||||
},
|
||||
"examples": [
|
||||
"examples/*/*.ino"
|
||||
],
|
||||
"dependencies": [],
|
||||
"authors": [
|
||||
{
|
||||
"maintainer": true,
|
||||
"name": "Xose Perez",
|
||||
"url": "http://tinkerman.cat",
|
||||
"email": "xose.perez@gmail.com"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"current",
|
||||
"hlw8012",
|
||||
"power",
|
||||
"voltage"
|
||||
],
|
||||
"id": 1281,
|
||||
"description": "HLW8012 library for Arduino and ESP8266"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# HLW8012 change log
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [1.0.0] 2017-01-13
|
||||
### Added
|
||||
- Added reactive power calculation
|
||||
- Added reset calibration values
|
||||
|
||||
### Fixed
|
||||
- Using volatile for variable inside callbacks
|
||||
|
||||
## [0.1.0] 2016-11-08
|
||||
- Initial working version
|
||||
@@ -0,0 +1,675 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# HLW8012
|
||||
|
||||
HLW8012 library for Arduino and ESP8266 using the [Arduino Core for ESP8266][1].
|
||||
|
||||

|
||||
|
||||
|
||||
This is the IC present in some chinese products like [Itead's Sonoff POW][2].
|
||||
The HLW8012 is a current, voltage and power monitor IC that outputs a pulse of a frequency inversely proportional to the value to be read.
|
||||
This IC provides two PWM outputs, the first one for power and the second one for current or voltage, depending on the SEL pin. The output values are always RMS. Power measurements are very consistent but current or voltage measurements require a minimum time lapse after changing the SEL pin value to become stable. This fact reduces sampling frequency.
|
||||
Higher values (of power, current or voltage) mean shorter pulses.
|
||||
|
||||
Typical values are:
|
||||
|
||||
* A 1Hz pulse on CF pin means around 12W RMS
|
||||
* A 1Hz pulse on CF1 pin means 15mA or 0.5V RMS depending on the value in SEL pin
|
||||
|
||||
These ratios are per datasheet typical application, but the actual circuitry might be different.
|
||||
Even if the circuit matches that on the datasheet the IC tolerances are quite loosy (+-15% for clock frequency, for instance).
|
||||
|
||||
## Features
|
||||
|
||||
The main features of the HLW8012 library are:
|
||||
|
||||
* Two available modes: interrupt-driven or non-interrupt-driven.
|
||||
* Default calibration based on product datasheet (3.1 Typical Applications).
|
||||
* You can specify the resistor values for your circuit.
|
||||
* Optional manual calibration based on expected values.
|
||||
|
||||
## Usage
|
||||
|
||||
Check the examples for indications on how to use the library.
|
||||
|
||||
### Interrupt driven mode
|
||||
|
||||
When using interrupts, values are monitored in the background. When calling the get***() methods the last sampled value is returned, this value might be up to a few seconds old if they are very low values. This is specially obvious when switching off the load. The new value of 0W or 0mA is ideally represented by infinite-length pulses. That means that the interrupt is not triggered, the value does not get updated and it will only timeout after 2 seconds (configurable through the pulse_timeout parameter in the begin() method). During that time lapse the library will still return the last non-zero value.
|
||||
|
||||
### Non interrupt mode
|
||||
|
||||
On the other hand, when not using interrupts, you have to let some time for the pulses in CF1 to stabilize before reading the value. So after calling setMode or toggleMode leave 2 seconds minimum before calling the get methods. The get method for the current mode will measure the pulse width and return the corresponding value, the other one will return the cached value (or 0 if none).
|
||||
|
||||
Use non-interrupt approach and a low pulse_timeout (200ms) only if you are deploying a battery powered device and you care more about your device power consumption than about precission. But then you should know the HLW8012 takes about 15mW...
|
||||
|
||||
### Notes
|
||||
|
||||
I've put together this library after doing a lot of tests with a Sonoff POW[2]. The HLW8012 datasheet (in the "docs" folder) gives some information but I couldn't find any about this issue in the CF1 line that requires some time for the pulse length to stabilize (apparently). Any help about that will be very welcome.
|
||||
|
||||
## Manual calibration
|
||||
|
||||
Use a pure resistive load with a well-known power consumption or use a multimeter to monitor it. A bulb is usually a good idea, although a toaster would be better since it's power consumption is higher.
|
||||
|
||||
Then use the expected*() methods and feed the values. For instance, for a 60W bulb in a 230 line that would be:
|
||||
|
||||
```
|
||||
hlw8012.expectedActivePower(60.0);
|
||||
hlw8012.expectedVoltage(230.0);
|
||||
hlw8012.expectedCurrent(60.0 / 230.0);
|
||||
```
|
||||
|
||||
|
||||
[1]:https://github.com/esp8266/Arduino
|
||||
[2]:https://www.itead.cc/sonoff-pow.html?acc=70efdf2ec9b086079795c442636b55fb
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -0,0 +1,120 @@
|
||||
#include <Arduino.h>
|
||||
#include "HLW8012.h"
|
||||
|
||||
#define SERIAL_BAUDRATE 115200
|
||||
|
||||
// GPIOs
|
||||
#define RELAY_PIN 12
|
||||
#define SEL_PIN 5
|
||||
#define CF1_PIN 13
|
||||
#define CF_PIN 14
|
||||
|
||||
// Check values every 2 seconds
|
||||
#define UPDATE_TIME 2000
|
||||
|
||||
// Set SEL_PIN to HIGH to sample current
|
||||
// This is the case for Itead's Sonoff POW, where a
|
||||
// the SEL_PIN drives a transistor that pulls down
|
||||
// the SEL pin in the HLW8012 when closed
|
||||
#define CURRENT_MODE HIGH
|
||||
|
||||
// These are the nominal values for the resistors in the circuit
|
||||
#define CURRENT_RESISTOR 0.001
|
||||
#define VOLTAGE_RESISTOR_UPSTREAM ( 5 * 470000 ) // Real: 2280k
|
||||
#define VOLTAGE_RESISTOR_DOWNSTREAM ( 1000 ) // Real 1.009k
|
||||
|
||||
HLW8012 hlw8012;
|
||||
|
||||
void unblockingDelay(unsigned long mseconds) {
|
||||
unsigned long timeout = millis();
|
||||
while ((millis() - timeout) < mseconds) delay(1);
|
||||
}
|
||||
|
||||
void calibrate() {
|
||||
|
||||
// Let's first read power, current and voltage
|
||||
// with an interval in between to allow the signal to stabilise:
|
||||
|
||||
hlw8012.getActivePower();
|
||||
|
||||
hlw8012.setMode(MODE_CURRENT);
|
||||
unblockingDelay(2000);
|
||||
hlw8012.getCurrent();
|
||||
|
||||
hlw8012.setMode(MODE_VOLTAGE);
|
||||
unblockingDelay(2000);
|
||||
hlw8012.getVoltage();
|
||||
|
||||
// Calibrate using a 60W bulb (pure resistive) on a 230V line
|
||||
hlw8012.expectedActivePower(60.0);
|
||||
hlw8012.expectedVoltage(230.0);
|
||||
hlw8012.expectedCurrent(60.0 / 230.0);
|
||||
|
||||
// Show corrected factors
|
||||
Serial.print("[HLW] New current multiplier : "); Serial.println(hlw8012.getCurrentMultiplier());
|
||||
Serial.print("[HLW] New voltage multiplier : "); Serial.println(hlw8012.getVoltageMultiplier());
|
||||
Serial.print("[HLW] New power multiplier : "); Serial.println(hlw8012.getPowerMultiplier());
|
||||
Serial.println();
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
// Init serial port and clean garbage
|
||||
Serial.begin(SERIAL_BAUDRATE);
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
// Close the relay to switch on the load
|
||||
pinMode(RELAY_PIN, OUTPUT);
|
||||
digitalWrite(RELAY_PIN, HIGH);
|
||||
|
||||
// Initialize HLW8012
|
||||
// void begin(unsigned char cf_pin, unsigned char cf1_pin, unsigned char sel_pin, unsigned char currentWhen = HIGH, bool use_interrupts = false, unsigned long pulse_timeout = PULSE_TIMEOUT);
|
||||
// * cf_pin, cf1_pin and sel_pin are GPIOs to the HLW8012 IC
|
||||
// * currentWhen is the value in sel_pin to select current sampling
|
||||
// * set use_interrupts to false, we will have to call handle() in the main loop to do the sampling
|
||||
// * set pulse_timeout to 500ms for a fast response but losing precision (that's ~24W precision :( )
|
||||
hlw8012.begin(CF_PIN, CF1_PIN, SEL_PIN, CURRENT_MODE, false, 500000);
|
||||
|
||||
// These values are used to calculate current, voltage and power factors as per datasheet formula
|
||||
// These are the nominal values for the Sonoff POW resistors:
|
||||
// * The CURRENT_RESISTOR is the 1milliOhm copper-manganese resistor in series with the main line
|
||||
// * The VOLTAGE_RESISTOR_UPSTREAM are the 5 470kOhm resistors in the voltage divider that feeds the V2P pin in the HLW8012
|
||||
// * The VOLTAGE_RESISTOR_DOWNSTREAM is the 1kOhm resistor in the voltage divider that feeds the V2P pin in the HLW8012
|
||||
hlw8012.setResistors(CURRENT_RESISTOR, VOLTAGE_RESISTOR_UPSTREAM, VOLTAGE_RESISTOR_DOWNSTREAM);
|
||||
|
||||
// Show default (as per datasheet) multipliers
|
||||
Serial.print("[HLW] Default current multiplier : "); Serial.println(hlw8012.getCurrentMultiplier());
|
||||
Serial.print("[HLW] Default voltage multiplier : "); Serial.println(hlw8012.getVoltageMultiplier());
|
||||
Serial.print("[HLW] Default power multiplier : "); Serial.println(hlw8012.getPowerMultiplier());
|
||||
Serial.println();
|
||||
|
||||
calibrate();
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
static unsigned long last = millis();
|
||||
|
||||
// This UPDATE_TIME should be at least twice the minimum time for the current or voltage
|
||||
// signals to stabilize. Experimentally that's about 1 second.
|
||||
if ((millis() - last) > UPDATE_TIME) {
|
||||
|
||||
last = millis();
|
||||
Serial.print("[HLW] Active Power (W) : "); Serial.println(hlw8012.getActivePower());
|
||||
Serial.print("[HLW] Voltage (V) : "); Serial.println(hlw8012.getVoltage());
|
||||
Serial.print("[HLW] Current (A) : "); Serial.println(hlw8012.getCurrent());
|
||||
Serial.print("[HLW] Apparent Power (VA) : "); Serial.println(hlw8012.getApparentPower());
|
||||
Serial.print("[HLW] Power Factor (%) : "); Serial.println((int) (100 * hlw8012.getPowerFactor()));
|
||||
Serial.println();
|
||||
|
||||
// When not using interrupts we have to manually switch to current or voltage monitor
|
||||
// This means that every time we get into the conditional we only update one of them
|
||||
// while the other will return the cached value.
|
||||
hlw8012.toggleMode();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#include <Arduino.h>
|
||||
#include <LowPower.h>
|
||||
#include "HLW8012.h"
|
||||
|
||||
#define SERIAL_BAUDRATE 115200
|
||||
|
||||
// GPIOs
|
||||
#define SEL_PIN 5
|
||||
#define CF1_PIN 13
|
||||
#define CF_PIN 14
|
||||
|
||||
// Set SEL_PIN to HIGH to sample current
|
||||
// This is the case for Itead's Sonoff POW, where a
|
||||
// the SEL_PIN drives a transistor that pulls down
|
||||
// the SEL pin in the HLW8012 when closed
|
||||
#define CURRENT_MODE HIGH
|
||||
|
||||
// Maximum pulse width, a 2Hz pulse means a precission of ~24W
|
||||
#define MAX_PULSE_WIDTH 500000
|
||||
|
||||
HLW8012 hlw8012;
|
||||
|
||||
void setup() {
|
||||
|
||||
// Init serial port and clean garbage
|
||||
Serial.begin(SERIAL_BAUDRATE);
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
// Initialize HLW8012
|
||||
hlw8012.begin(CF_PIN, CF1_PIN, SEL_PIN, CURRENT_MODE, false, MAX_PULSE_WIDTH);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// Sleep for 20 seconds
|
||||
for (unsigned short i = 0; i < 5; i++ ) {
|
||||
LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);
|
||||
}
|
||||
|
||||
unsigned long start = millis();
|
||||
Serial.print("[HLW] Active Power (W) : "); Serial.println(hlw8012.getActivePower());
|
||||
Serial.print("[HLW] Awake for (ms) : "); Serial.println(millis() - start);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
#include <Arduino.h>
|
||||
#include "HLW8012.h"
|
||||
|
||||
#define SERIAL_BAUDRATE 115200
|
||||
|
||||
// GPIOs
|
||||
#define RELAY_PIN 12
|
||||
#define SEL_PIN 5
|
||||
#define CF1_PIN 13
|
||||
#define CF_PIN 14
|
||||
|
||||
// Check values every 10 seconds
|
||||
#define UPDATE_TIME 10000
|
||||
|
||||
// Set SEL_PIN to HIGH to sample current
|
||||
// This is the case for Itead's Sonoff POW, where a
|
||||
// the SEL_PIN drives a transistor that pulls down
|
||||
// the SEL pin in the HLW8012 when closed
|
||||
#define CURRENT_MODE HIGH
|
||||
|
||||
// These are the nominal values for the resistors in the circuit
|
||||
#define CURRENT_RESISTOR 0.001
|
||||
#define VOLTAGE_RESISTOR_UPSTREAM ( 5 * 470000 ) // Real: 2280k
|
||||
#define VOLTAGE_RESISTOR_DOWNSTREAM ( 1000 ) // Real 1.009k
|
||||
|
||||
HLW8012 hlw8012;
|
||||
|
||||
// When using interrupts we have to call the library entry point
|
||||
// whenever an interrupt is triggered
|
||||
void hlw8012_cf1_interrupt() {
|
||||
hlw8012.cf1_interrupt();
|
||||
}
|
||||
void hlw8012_cf_interrupt() {
|
||||
hlw8012.cf_interrupt();
|
||||
}
|
||||
|
||||
// Library expects an interrupt on both edges
|
||||
void setInterrupts() {
|
||||
attachInterrupt(CF1_PIN, hlw8012_cf1_interrupt, CHANGE);
|
||||
attachInterrupt(CF_PIN, hlw8012_cf_interrupt, CHANGE);
|
||||
}
|
||||
|
||||
void calibrate() {
|
||||
|
||||
// Let some time to register values
|
||||
unsigned long timeout = millis();
|
||||
while ((millis() - timeout) < 10000) {
|
||||
delay(1);
|
||||
}
|
||||
|
||||
// Calibrate using a 60W bulb (pure resistive) on a 230V line
|
||||
hlw8012.expectedActivePower(60.0);
|
||||
hlw8012.expectedVoltage(230.0);
|
||||
hlw8012.expectedCurrent(60.0 / 230.0);
|
||||
|
||||
// Show corrected factors
|
||||
Serial.print("[HLW] New current multiplier : "); Serial.println(hlw8012.getCurrentMultiplier());
|
||||
Serial.print("[HLW] New voltage multiplier : "); Serial.println(hlw8012.getVoltageMultiplier());
|
||||
Serial.print("[HLW] New power multiplier : "); Serial.println(hlw8012.getPowerMultiplier());
|
||||
Serial.println();
|
||||
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
// Init serial port and clean garbage
|
||||
Serial.begin(SERIAL_BAUDRATE);
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
// Close the relay to switch on the load
|
||||
pinMode(RELAY_PIN, OUTPUT);
|
||||
digitalWrite(RELAY_PIN, HIGH);
|
||||
|
||||
// Initialize HLW8012
|
||||
// void begin(unsigned char cf_pin, unsigned char cf1_pin, unsigned char sel_pin, unsigned char currentWhen = HIGH, bool use_interrupts = false, unsigned long pulse_timeout = PULSE_TIMEOUT);
|
||||
// * cf_pin, cf1_pin and sel_pin are GPIOs to the HLW8012 IC
|
||||
// * currentWhen is the value in sel_pin to select current sampling
|
||||
// * set use_interrupts to true to use interrupts to monitor pulse widths
|
||||
// * leave pulse_timeout to the default value, recommended when using interrupts
|
||||
hlw8012.begin(CF_PIN, CF1_PIN, SEL_PIN, CURRENT_MODE, true);
|
||||
|
||||
// These values are used to calculate current, voltage and power factors as per datasheet formula
|
||||
// These are the nominal values for the Sonoff POW resistors:
|
||||
// * The CURRENT_RESISTOR is the 1milliOhm copper-manganese resistor in series with the main line
|
||||
// * The VOLTAGE_RESISTOR_UPSTREAM are the 5 470kOhm resistors in the voltage divider that feeds the V2P pin in the HLW8012
|
||||
// * The VOLTAGE_RESISTOR_DOWNSTREAM is the 1kOhm resistor in the voltage divider that feeds the V2P pin in the HLW8012
|
||||
hlw8012.setResistors(CURRENT_RESISTOR, VOLTAGE_RESISTOR_UPSTREAM, VOLTAGE_RESISTOR_DOWNSTREAM);
|
||||
|
||||
// Show default (as per datasheet) multipliers
|
||||
Serial.print("[HLW] Default current multiplier : "); Serial.println(hlw8012.getCurrentMultiplier());
|
||||
Serial.print("[HLW] Default voltage multiplier : "); Serial.println(hlw8012.getVoltageMultiplier());
|
||||
Serial.print("[HLW] Default power multiplier : "); Serial.println(hlw8012.getPowerMultiplier());
|
||||
Serial.println();
|
||||
|
||||
setInterrupts();
|
||||
calibrate();
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
static unsigned long last = millis();
|
||||
|
||||
// This UPDATE_TIME should be at least twice the interrupt timeout (2 second by default)
|
||||
if ((millis() - last) > UPDATE_TIME) {
|
||||
|
||||
last = millis();
|
||||
Serial.print("[HLW] Active Power (W) : "); Serial.println(hlw8012.getActivePower());
|
||||
Serial.print("[HLW] Voltage (V) : "); Serial.println(hlw8012.getVoltage());
|
||||
Serial.print("[HLW] Current (A) : "); Serial.println(hlw8012.getCurrent());
|
||||
Serial.print("[HLW] Apparent Power (VA) : "); Serial.println(hlw8012.getApparentPower());
|
||||
Serial.print("[HLW] Power Factor (%) : "); Serial.println((int) (100 * hlw8012.getPowerFactor()));
|
||||
Serial.println();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "HLW8012",
|
||||
"keywords": "hlw8012,power,current,voltage",
|
||||
"description": "HLW8012 library for Arduino and ESP8266",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://bitbucket.org/xoseperez/hlw8012.git"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0",
|
||||
"exclude": "tests",
|
||||
"frameworks": "arduino",
|
||||
"platforms": ["atmelavr", "espressif8266"],
|
||||
"dependencies": [
|
||||
],
|
||||
"authors": {
|
||||
"name": "Xose Perez",
|
||||
"email": "xose.perez@gmail.com",
|
||||
"url": "http://tinkerman.cat",
|
||||
"maintainer": true
|
||||
},
|
||||
"examples": [
|
||||
"examples/*/*.ino"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
name=HLW8012
|
||||
version=1.0.0
|
||||
author=Xose Pérez <xose.perez@gmail.com>
|
||||
maintainer=Xose Perez <xose.perez@gmail.com>
|
||||
sentence=HLW8012 for Arduino / ESP8216
|
||||
paragraph=HLW8012 power/current/voltage monitor IC library for Arduino and ESP8266. Use 2.x.x for ESP and 1.3 for AVR.
|
||||
category=Sensors
|
||||
url=https://bitbucket.org/xoseperez/hlw8012
|
||||
architectures=*
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
|
||||
HLW8012 1.0.0
|
||||
|
||||
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "HLW8012.h"
|
||||
|
||||
void HLW8012::begin(
|
||||
unsigned char cf_pin,
|
||||
unsigned char cf1_pin,
|
||||
unsigned char sel_pin,
|
||||
unsigned char currentWhen,
|
||||
bool use_interrupts,
|
||||
unsigned long pulse_timeout
|
||||
) {
|
||||
|
||||
_cf_pin = cf_pin;
|
||||
_cf1_pin = cf1_pin;
|
||||
_sel_pin = sel_pin;
|
||||
_current_mode = currentWhen;
|
||||
_use_interrupts = use_interrupts;
|
||||
_pulse_timeout = pulse_timeout;
|
||||
|
||||
pinMode(_cf_pin, INPUT_PULLUP);
|
||||
pinMode(_cf1_pin, INPUT_PULLUP);
|
||||
pinMode(_sel_pin, OUTPUT);
|
||||
|
||||
_calculateDefaultMultipliers();
|
||||
|
||||
_mode = _current_mode;
|
||||
digitalWrite(_sel_pin, _mode);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void HLW8012::setMode(hlw8012_mode_t mode) {
|
||||
_mode = (mode == MODE_CURRENT) ? _current_mode : 1 - _current_mode;
|
||||
digitalWrite(_sel_pin, _mode);
|
||||
if (_use_interrupts) {
|
||||
_last_cf1_interrupt = _first_cf1_interrupt = micros();
|
||||
}
|
||||
}
|
||||
|
||||
hlw8012_mode_t HLW8012::getMode() {
|
||||
return (_mode == _current_mode) ? MODE_CURRENT : MODE_VOLTAGE;
|
||||
}
|
||||
|
||||
hlw8012_mode_t HLW8012::toggleMode() {
|
||||
hlw8012_mode_t new_mode = getMode() == MODE_CURRENT ? MODE_VOLTAGE : MODE_CURRENT;
|
||||
setMode(new_mode);
|
||||
return new_mode;
|
||||
}
|
||||
|
||||
double HLW8012::getCurrent() {
|
||||
|
||||
// Power measurements are more sensitive to switch offs,
|
||||
// so we first check if power is 0 to set _current to 0 too
|
||||
if (_power == 0) {
|
||||
_current_pulse_width = 0;
|
||||
|
||||
} else if (_use_interrupts) {
|
||||
_checkCF1Signal();
|
||||
|
||||
} else if (_mode == _current_mode) {
|
||||
_current_pulse_width = pulseIn(_cf1_pin, HIGH, _pulse_timeout);
|
||||
}
|
||||
|
||||
_current = (_current_pulse_width > 0) ? _current_multiplier / _current_pulse_width / 2 : 0;
|
||||
return _current;
|
||||
|
||||
}
|
||||
|
||||
unsigned int HLW8012::getVoltage() {
|
||||
if (_use_interrupts) {
|
||||
_checkCF1Signal();
|
||||
} else if (_mode != _current_mode) {
|
||||
_voltage_pulse_width = pulseIn(_cf1_pin, HIGH, _pulse_timeout);
|
||||
}
|
||||
_voltage = (_voltage_pulse_width > 0) ? _voltage_multiplier / _voltage_pulse_width / 2 : 0;
|
||||
return _voltage;
|
||||
}
|
||||
|
||||
unsigned int HLW8012::getActivePower() {
|
||||
if (_use_interrupts) {
|
||||
_checkCFSignal();
|
||||
} else {
|
||||
_power_pulse_width = pulseIn(_cf_pin, HIGH, _pulse_timeout);
|
||||
}
|
||||
_power = (_power_pulse_width > 0) ? _power_multiplier / _power_pulse_width / 2 : 0;
|
||||
return _power;
|
||||
}
|
||||
|
||||
unsigned int HLW8012::getApparentPower() {
|
||||
double current = getCurrent();
|
||||
unsigned int voltage = getVoltage();
|
||||
return voltage * current;
|
||||
}
|
||||
|
||||
unsigned int HLW8012::getReactivePower() {
|
||||
unsigned int active = getActivePower();
|
||||
unsigned int apparent = getApparentPower();
|
||||
if (apparent > active) {
|
||||
return sqrt(apparent * apparent - active * active);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
double HLW8012::getPowerFactor() {
|
||||
unsigned int active = getActivePower();
|
||||
unsigned int apparent = getApparentPower();
|
||||
if (active > apparent) return 1;
|
||||
if (apparent == 0) return 0;
|
||||
return (double) active / apparent;
|
||||
}
|
||||
|
||||
void HLW8012::expectedCurrent(double value) {
|
||||
if (_current == 0) getCurrent();
|
||||
if (_current > 0) _current_multiplier *= (value / _current);
|
||||
}
|
||||
|
||||
void HLW8012::expectedVoltage(unsigned int value) {
|
||||
if (_voltage == 0) getVoltage();
|
||||
if (_voltage > 0) _voltage_multiplier *= ((double) value / _voltage);
|
||||
}
|
||||
|
||||
void HLW8012::expectedActivePower(unsigned int value) {
|
||||
if (_power == 0) getActivePower();
|
||||
if (_power > 0) _power_multiplier *= ((double) value / _power);
|
||||
}
|
||||
|
||||
void HLW8012::resetMultipliers() {
|
||||
_calculateDefaultMultipliers();
|
||||
}
|
||||
|
||||
void HLW8012::setResistors(double current, double voltage_upstream, double voltage_downstream) {
|
||||
if (voltage_downstream > 0) {
|
||||
_current_resistor = current;
|
||||
_voltage_resistor = (voltage_upstream + voltage_downstream) / voltage_downstream;
|
||||
_calculateDefaultMultipliers();
|
||||
}
|
||||
}
|
||||
|
||||
void HLW8012::cf_interrupt() {
|
||||
unsigned long now = micros();
|
||||
_power_pulse_width = now - _last_cf_interrupt;
|
||||
_last_cf_interrupt = now;
|
||||
}
|
||||
|
||||
void HLW8012::cf1_interrupt() {
|
||||
|
||||
unsigned long now = micros();
|
||||
unsigned long pulse_width;
|
||||
|
||||
if ((now - _first_cf1_interrupt) > _pulse_timeout) {
|
||||
|
||||
if (_last_cf1_interrupt == _first_cf1_interrupt) {
|
||||
pulse_width = 0;
|
||||
} else {
|
||||
pulse_width = now - _last_cf1_interrupt;
|
||||
}
|
||||
|
||||
if (_mode == _current_mode) {
|
||||
_current_pulse_width = pulse_width;
|
||||
} else {
|
||||
_voltage_pulse_width = pulse_width;
|
||||
}
|
||||
|
||||
_mode = 1 - _mode;
|
||||
digitalWrite(_sel_pin, _mode);
|
||||
_first_cf1_interrupt = now;
|
||||
|
||||
}
|
||||
|
||||
_last_cf1_interrupt = now;
|
||||
|
||||
}
|
||||
|
||||
void HLW8012::_checkCFSignal() {
|
||||
if ((micros() - _last_cf_interrupt) > _pulse_timeout) _power_pulse_width = 0;
|
||||
}
|
||||
|
||||
void HLW8012::_checkCF1Signal() {
|
||||
if ((micros() - _last_cf1_interrupt) > _pulse_timeout) {
|
||||
if (_mode == _current_mode) {
|
||||
_current_pulse_width = 0;
|
||||
} else {
|
||||
_voltage_pulse_width = 0;
|
||||
}
|
||||
toggleMode();
|
||||
}
|
||||
}
|
||||
|
||||
// These are the multipliers for current, voltage and power as per datasheet
|
||||
// These values divided by output period (in useconds) give the actual value
|
||||
// For power a frequency of 1Hz means around 12W
|
||||
// For current a frequency of 1Hz means around 15mA
|
||||
// For voltage a frequency of 1Hz means around 0.5V
|
||||
void HLW8012::_calculateDefaultMultipliers() {
|
||||
_current_multiplier = ( 1000000.0 * 512 * V_REF / _current_resistor / 24.0 / F_OSC );
|
||||
_voltage_multiplier = ( 1000000.0 * 512 * V_REF * _voltage_resistor / 2.0 / F_OSC );
|
||||
_power_multiplier = ( 1000000.0 * 128 * V_REF * V_REF * _voltage_resistor / _current_resistor / 48.0 / F_OSC );
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
|
||||
HLW8012 1.0.0
|
||||
|
||||
Copyright (C) 2016 by Xose Pérez <xose dot perez at gmail dot com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HLW8012_h
|
||||
#define HLW8012_h
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// Internal voltage reference value
|
||||
#define V_REF 2.43
|
||||
|
||||
// The factor of a 1mOhm resistor
|
||||
// as per recomended circuit in datasheet
|
||||
// A 1mOhm resistor allows a ~30A max measurement
|
||||
#define R_CURRENT 0.001
|
||||
|
||||
// This is the factor of a voltage divider of 6x 470K upstream and 1k downstream
|
||||
// as per recomended circuit in datasheet
|
||||
#define R_VOLTAGE 2821
|
||||
|
||||
// Frequency of the HLW8012 internal clock
|
||||
#define F_OSC 3579000
|
||||
|
||||
// Minimum delay between selecting a mode and reading a sample
|
||||
#define READING_INTERVAL 3000
|
||||
|
||||
// Maximum pulse with in microseconds
|
||||
// If longer than this pulse width is reset to 0
|
||||
// This value is purely experimental.
|
||||
// Higher values allow for a better precission but reduce sampling rate
|
||||
// and response speed to change
|
||||
// Lower values increase sampling rate but reduce precission
|
||||
// Values below 0.5s are not recommended since current and voltage output
|
||||
// will have no time to stabilise
|
||||
#define PULSE_TIMEOUT 2000000
|
||||
|
||||
// CF1 mode
|
||||
typedef enum {
|
||||
MODE_CURRENT,
|
||||
MODE_VOLTAGE
|
||||
} hlw8012_mode_t;
|
||||
|
||||
class HLW8012 {
|
||||
|
||||
public:
|
||||
|
||||
void cf_interrupt();
|
||||
void cf1_interrupt();
|
||||
|
||||
void begin(
|
||||
unsigned char cf_pin,
|
||||
unsigned char cf1_pin,
|
||||
unsigned char sel_pin,
|
||||
unsigned char currentWhen = HIGH,
|
||||
bool use_interrupts = true,
|
||||
unsigned long pulse_timeout = PULSE_TIMEOUT);
|
||||
|
||||
void setMode(hlw8012_mode_t mode);
|
||||
hlw8012_mode_t getMode();
|
||||
hlw8012_mode_t toggleMode();
|
||||
|
||||
double getCurrent();
|
||||
unsigned int getVoltage();
|
||||
unsigned int getActivePower();
|
||||
unsigned int getApparentPower();
|
||||
double getPowerFactor();
|
||||
unsigned int getReactivePower();
|
||||
|
||||
void setResistors(double current, double voltage_upstream, double voltage_downstream);
|
||||
|
||||
void expectedCurrent(double current);
|
||||
void expectedVoltage(unsigned int current);
|
||||
void expectedActivePower(unsigned int power);
|
||||
|
||||
double getCurrentMultiplier() { return _current_multiplier; };
|
||||
double getVoltageMultiplier() { return _voltage_multiplier; };
|
||||
double getPowerMultiplier() { return _power_multiplier; };
|
||||
|
||||
void setCurrentMultiplier(double current_multiplier) { _current_multiplier = current_multiplier; };
|
||||
void setVoltageMultiplier(double voltage_multiplier) { _voltage_multiplier = voltage_multiplier; };
|
||||
void setPowerMultiplier(double power_multiplier) { _power_multiplier = power_multiplier; };
|
||||
void resetMultipliers();
|
||||
|
||||
private:
|
||||
|
||||
unsigned char _cf_pin;
|
||||
unsigned char _cf1_pin;
|
||||
unsigned char _sel_pin;
|
||||
|
||||
double _current_resistor = R_CURRENT;
|
||||
double _voltage_resistor = R_VOLTAGE;
|
||||
|
||||
double _current_multiplier;
|
||||
double _voltage_multiplier;
|
||||
double _power_multiplier;
|
||||
|
||||
unsigned long _pulse_timeout = PULSE_TIMEOUT;
|
||||
volatile unsigned long _voltage_pulse_width = 0;
|
||||
volatile unsigned long _current_pulse_width = 0;
|
||||
volatile unsigned long _power_pulse_width = 0;
|
||||
|
||||
double _current = 0;
|
||||
unsigned int _voltage = 0;
|
||||
unsigned int _power = 0;
|
||||
|
||||
unsigned char _current_mode = HIGH;
|
||||
volatile unsigned char _mode;
|
||||
|
||||
bool _use_interrupts = true;
|
||||
volatile unsigned long _last_cf_interrupt = 0;
|
||||
volatile unsigned long _last_cf1_interrupt = 0;
|
||||
volatile unsigned long _first_cf1_interrupt = 0;
|
||||
|
||||
void _checkCFSignal();
|
||||
void _checkCF1Signal();
|
||||
void _calculateDefaultMultipliers();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -168,6 +168,51 @@ void ICACHE_FLASH_ATTR IRsend::sendNEC (unsigned long data, int nbits,
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRsend::sendPioneer (unsigned long data, int nbits,
|
||||
unsigned int repeat, unsigned long secondData) {
|
||||
// Details about timings can be found at:
|
||||
// http://www.sbprojects.com/knowledge/ir/nec.php
|
||||
// More about the pioneer format:
|
||||
// http://www.adrian-kingston.com/IRFormatPioneer.htm
|
||||
|
||||
// Set IR carrier frequency
|
||||
enableIROut(40);
|
||||
IRtimer usecs = IRtimer();
|
||||
|
||||
for (unsigned int i = 0; i <= repeat; i++) {
|
||||
usecs.reset();
|
||||
// Header
|
||||
mark(PIONEER_HDR_MARK);
|
||||
space(PIONEER_HDR_SPACE);
|
||||
|
||||
sendData(PIONEER_BIT_MARK, PIONEER_ONE_SPACE, PIONEER_BIT_MARK, PIONEER_ZERO_SPACE,
|
||||
data, nbits, true);
|
||||
|
||||
// Footer
|
||||
mark(PIONEER_BIT_MARK);
|
||||
space(PIONEER_ONE_SPACE);
|
||||
// Gap till next command.
|
||||
space(max(0ul, PIONEER_MIN_COMMAND_LENGTH - usecs.elapsed()));
|
||||
|
||||
// Some Pioneer signals have two 32 bit commands
|
||||
if (secondData) {
|
||||
usecs.reset();
|
||||
// Header
|
||||
mark(PIONEER_HDR_MARK);
|
||||
space(PIONEER_HDR_SPACE);
|
||||
|
||||
sendData(PIONEER_BIT_MARK, PIONEER_ONE_SPACE, PIONEER_BIT_MARK, PIONEER_ZERO_SPACE,
|
||||
secondData, nbits, true);
|
||||
|
||||
// Footer
|
||||
mark(PIONEER_BIT_MARK);
|
||||
space(PIONEER_ONE_SPACE);
|
||||
// Gap till next command.
|
||||
space(max(0ul, PIONEER_MIN_COMMAND_LENGTH - usecs.elapsed()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRsend::sendLG (unsigned long data, int nbits,
|
||||
unsigned int repeat) {
|
||||
// Args:
|
||||
|
||||
@@ -53,6 +53,7 @@ enum decode_type_t {
|
||||
RC5,
|
||||
RC6,
|
||||
NEC,
|
||||
PIONEER,
|
||||
SONY,
|
||||
PANASONIC,
|
||||
JVC,
|
||||
@@ -92,6 +93,7 @@ public:
|
||||
#define REPEAT 0xffffffff
|
||||
|
||||
#define SEND_PROTOCOL_NEC case NEC: sendNEC(data, nbits); break;
|
||||
#define SEND_PROTOCOL_PIONEER case PIONEER: sendPioneer(data, nbits, 1, 0ul); break;
|
||||
#define SEND_PROTOCOL_SONY case SONY: sendSony(data, nbits); break;
|
||||
#define SEND_PROTOCOL_RC5 case RC5: sendRC5(data, nbits); break;
|
||||
#define SEND_PROTOCOL_RC6 case RC6: sendRC6(data, nbits); break;
|
||||
@@ -162,6 +164,7 @@ public:
|
||||
void send(int type, unsigned long data, int nbits) {
|
||||
switch (type) {
|
||||
SEND_PROTOCOL_NEC
|
||||
SEND_PROTOCOL_PIONEER
|
||||
SEND_PROTOCOL_SONY
|
||||
SEND_PROTOCOL_RC5
|
||||
SEND_PROTOCOL_RC6
|
||||
@@ -179,6 +182,7 @@ public:
|
||||
void sendCOOLIX(unsigned long data, int nbits);
|
||||
void sendWhynter(unsigned long data, int nbits);
|
||||
void sendNEC(unsigned long data, int nbits=32, unsigned int repeat=0);
|
||||
void sendPioneer(unsigned long data, int nbits=32, unsigned int repeat=0, unsigned long secondData=0ul);
|
||||
void sendLG(unsigned long data, int nbits=28, unsigned int repeat=0);
|
||||
// sendSony() should typically be called with repeat=2 as Sony devices
|
||||
// expect the code to be sent at least 3 times. (code + 2 repeats = 3 codes)
|
||||
|
||||
@@ -60,6 +60,14 @@
|
||||
#define NEC_RPT_SPACE 2250
|
||||
#define NEC_MIN_COMMAND_LENGTH 108000UL
|
||||
|
||||
#define PIONEER_HDR_MARK 8000
|
||||
#define PIONEER_HDR_SPACE 4000
|
||||
#define PIONEER_BIT_MARK 500
|
||||
#define PIONEER_ONE_SPACE 1500
|
||||
#define PIONEER_ZERO_SPACE 500
|
||||
#define PIONEER_RPT_SPACE 2250
|
||||
#define PIONEER_MIN_COMMAND_LENGTH 90000UL
|
||||
|
||||
// Timings based on http://www.sbprojects.com/knowledge/ir/sirc.php
|
||||
#define SONY_HDR_MARK 2400
|
||||
#define SONY_HDR_SPACE 600
|
||||
|
||||
@@ -151,7 +151,7 @@ void QEIx4::begin(int16_t pinA, int16_t pinB, int16_t pinI, uint8_t mode)
|
||||
_pinI = pinI;
|
||||
|
||||
_counter = 0;
|
||||
_bHasChanged = true;
|
||||
_bHasChanged = false;
|
||||
|
||||
if (mode == 1)
|
||||
_eventMask = QEIx4_1x_MASK;
|
||||
|
||||
Executable
+362
@@ -0,0 +1,362 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// Created by Tim Eckel - teckel@leethost.com
|
||||
// Copyright 2016 License: GNU GPL v3 http://www.gnu.org/licenses/gpl.html
|
||||
//
|
||||
// See "NewPing.h" for purpose, syntax, version history, links, and more.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#include "NewPing.h"
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// NewPing constructor
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
NewPing::NewPing(uint8_t trigger_pin, uint8_t echo_pin, unsigned int max_cm_distance) {
|
||||
#if DO_BITWISE == true
|
||||
_triggerBit = digitalPinToBitMask(trigger_pin); // Get the port register bitmask for the trigger pin.
|
||||
_echoBit = digitalPinToBitMask(echo_pin); // Get the port register bitmask for the echo pin.
|
||||
|
||||
_triggerOutput = portOutputRegister(digitalPinToPort(trigger_pin)); // Get the output port register for the trigger pin.
|
||||
_echoInput = portInputRegister(digitalPinToPort(echo_pin)); // Get the input port register for the echo pin.
|
||||
|
||||
_triggerMode = (uint8_t *) portModeRegister(digitalPinToPort(trigger_pin)); // Get the port mode register for the trigger pin.
|
||||
#else
|
||||
_triggerPin = trigger_pin;
|
||||
_echoPin = echo_pin;
|
||||
#endif
|
||||
|
||||
set_max_distance(max_cm_distance); // Call function to set the max sensor distance.
|
||||
|
||||
#if (defined (__arm__) && defined (TEENSYDUINO)) || DO_BITWISE != true
|
||||
pinMode(echo_pin, INPUT); // Set echo pin to input (on Teensy 3.x (ARM), pins default to disabled, at least one pinMode() is needed for GPIO mode).
|
||||
pinMode(trigger_pin, OUTPUT); // Set trigger pin to output (on Teensy 3.x (ARM), pins default to disabled, at least one pinMode() is needed for GPIO mode).
|
||||
#endif
|
||||
|
||||
#if defined (ARDUINO_AVR_YUN)
|
||||
pinMode(echo_pin, INPUT); // Set echo pin to input for the Arduino Yun, not sure why it doesn't default this way.
|
||||
#endif
|
||||
|
||||
#if ONE_PIN_ENABLED != true && DO_BITWISE == true
|
||||
*_triggerMode |= _triggerBit; // Set trigger pin to output.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Standard ping methods
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
unsigned int NewPing::ping(unsigned int max_cm_distance) {
|
||||
if (max_cm_distance > 0) set_max_distance(max_cm_distance); // Call function to set a new max sensor distance.
|
||||
|
||||
if (!ping_trigger()) return NO_ECHO; // Trigger a ping, if it returns false, return NO_ECHO to the calling function.
|
||||
|
||||
#if URM37_ENABLED == true
|
||||
#if DO_BITWISE == true
|
||||
while (!(*_echoInput & _echoBit)) // Wait for the ping echo.
|
||||
#else
|
||||
while (!digitalRead(_echoPin)) // Wait for the ping echo.
|
||||
#endif
|
||||
if (micros() > _max_time) return NO_ECHO; // Stop the loop and return NO_ECHO (false) if we're beyond the set maximum distance.
|
||||
#else
|
||||
#if DO_BITWISE == true
|
||||
while (*_echoInput & _echoBit) // Wait for the ping echo.
|
||||
#else
|
||||
while (digitalRead(_echoPin)) // Wait for the ping echo.
|
||||
#endif
|
||||
if (micros() > _max_time) return NO_ECHO; // Stop the loop and return NO_ECHO (false) if we're beyond the set maximum distance.
|
||||
#endif
|
||||
|
||||
return (micros() - (_max_time - _maxEchoTime) - PING_OVERHEAD); // Calculate ping time, include overhead.
|
||||
}
|
||||
|
||||
|
||||
unsigned long NewPing::ping_cm(unsigned int max_cm_distance) {
|
||||
unsigned long echoTime = NewPing::ping(max_cm_distance); // Calls the ping method and returns with the ping echo distance in uS.
|
||||
#if ROUNDING_ENABLED == false
|
||||
return (echoTime / US_ROUNDTRIP_CM); // Call the ping method and returns the distance in centimeters (no rounding).
|
||||
#else
|
||||
return NewPingConvert(echoTime, US_ROUNDTRIP_CM); // Convert uS to centimeters.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
unsigned long NewPing::ping_in(unsigned int max_cm_distance) {
|
||||
unsigned long echoTime = NewPing::ping(max_cm_distance); // Calls the ping method and returns with the ping echo distance in uS.
|
||||
#if ROUNDING_ENABLED == false
|
||||
return (echoTime / US_ROUNDTRIP_IN); // Call the ping method and returns the distance in inches (no rounding).
|
||||
#else
|
||||
return NewPingConvert(echoTime, US_ROUNDTRIP_IN); // Convert uS to inches.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
unsigned long NewPing::ping_median(uint8_t it, unsigned int max_cm_distance) {
|
||||
unsigned int uS[it], last;
|
||||
uint8_t j, i = 0;
|
||||
unsigned long t;
|
||||
uS[0] = NO_ECHO;
|
||||
|
||||
while (i < it) {
|
||||
t = micros(); // Start ping timestamp.
|
||||
last = ping(max_cm_distance); // Send ping.
|
||||
|
||||
if (last != NO_ECHO) { // Ping in range, include as part of median.
|
||||
if (i > 0) { // Don't start sort till second ping.
|
||||
for (j = i; j > 0 && uS[j - 1] < last; j--) // Insertion sort loop.
|
||||
uS[j] = uS[j - 1]; // Shift ping array to correct position for sort insertion.
|
||||
} else j = 0; // First ping is sort starting point.
|
||||
uS[j] = last; // Add last ping to array in sorted position.
|
||||
i++; // Move to next ping.
|
||||
} else it--; // Ping out of range, skip and don't include as part of median.
|
||||
|
||||
if (i < it && micros() - t < PING_MEDIAN_DELAY)
|
||||
delay((PING_MEDIAN_DELAY + t - micros()) / 1000); // Millisecond delay between pings.
|
||||
|
||||
}
|
||||
return (uS[it >> 1]); // Return the ping distance median.
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Standard and timer interrupt ping method support functions (not called directly)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
boolean NewPing::ping_trigger() {
|
||||
#if DO_BITWISE == true
|
||||
#if ONE_PIN_ENABLED == true
|
||||
*_triggerMode |= _triggerBit; // Set trigger pin to output.
|
||||
#endif
|
||||
|
||||
*_triggerOutput &= ~_triggerBit; // Set the trigger pin low, should already be low, but this will make sure it is.
|
||||
delayMicroseconds(4); // Wait for pin to go low.
|
||||
*_triggerOutput |= _triggerBit; // Set trigger pin high, this tells the sensor to send out a ping.
|
||||
delayMicroseconds(10); // Wait long enough for the sensor to realize the trigger pin is high. Sensor specs say to wait 10uS.
|
||||
*_triggerOutput &= ~_triggerBit; // Set trigger pin back to low.
|
||||
|
||||
#if ONE_PIN_ENABLED == true
|
||||
*_triggerMode &= ~_triggerBit; // Set trigger pin to input (when using one Arduino pin, this is technically setting the echo pin to input as both are tied to the same Arduino pin).
|
||||
#endif
|
||||
|
||||
#if URM37_ENABLED == true
|
||||
if (!(*_echoInput & _echoBit)) return false; // Previous ping hasn't finished, abort.
|
||||
_max_time = micros() + _maxEchoTime + MAX_SENSOR_DELAY; // Maximum time we'll wait for ping to start (most sensors are <450uS, the SRF06 can take up to 34,300uS!)
|
||||
while (*_echoInput & _echoBit) // Wait for ping to start.
|
||||
if (micros() > _max_time) return false; // Took too long to start, abort.
|
||||
#else
|
||||
if (*_echoInput & _echoBit) return false; // Previous ping hasn't finished, abort.
|
||||
_max_time = micros() + _maxEchoTime + MAX_SENSOR_DELAY; // Maximum time we'll wait for ping to start (most sensors are <450uS, the SRF06 can take up to 34,300uS!)
|
||||
while (!(*_echoInput & _echoBit)) // Wait for ping to start.
|
||||
if (micros() > _max_time) return false; // Took too long to start, abort.
|
||||
#endif
|
||||
#else
|
||||
#if ONE_PIN_ENABLED == true
|
||||
pinMode(_triggerPin, OUTPUT); // Set trigger pin to output.
|
||||
#endif
|
||||
|
||||
digitalWrite(_triggerPin, LOW); // Set the trigger pin low, should already be low, but this will make sure it is.
|
||||
delayMicroseconds(4); // Wait for pin to go low.
|
||||
digitalWrite(_triggerPin, HIGH); // Set trigger pin high, this tells the sensor to send out a ping.
|
||||
delayMicroseconds(10); // Wait long enough for the sensor to realize the trigger pin is high. Sensor specs say to wait 10uS.
|
||||
digitalWrite(_triggerPin, LOW); // Set trigger pin back to low.
|
||||
|
||||
#if ONE_PIN_ENABLED == true
|
||||
pinMode(_triggerPin, INPUT); // Set trigger pin to input (when using one Arduino pin, this is technically setting the echo pin to input as both are tied to the same Arduino pin).
|
||||
#endif
|
||||
|
||||
#if URM37_ENABLED == true
|
||||
if (!digitalRead(_echoPin)) return false; // Previous ping hasn't finished, abort.
|
||||
_max_time = micros() + _maxEchoTime + MAX_SENSOR_DELAY; // Maximum time we'll wait for ping to start (most sensors are <450uS, the SRF06 can take up to 34,300uS!)
|
||||
while (digitalRead(_echoPin)) // Wait for ping to start.
|
||||
if (micros() > _max_time) return false; // Took too long to start, abort.
|
||||
#else
|
||||
if (digitalRead(_echoPin)) return false; // Previous ping hasn't finished, abort.
|
||||
_max_time = micros() + _maxEchoTime + MAX_SENSOR_DELAY; // Maximum time we'll wait for ping to start (most sensors are <450uS, the SRF06 can take up to 34,300uS!)
|
||||
while (!digitalRead(_echoPin)) // Wait for ping to start.
|
||||
if (micros() > _max_time) return false; // Took too long to start, abort.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
_max_time = micros() + _maxEchoTime; // Ping started, set the time-out.
|
||||
return true; // Ping started successfully.
|
||||
}
|
||||
|
||||
|
||||
void NewPing::set_max_distance(unsigned int max_cm_distance) {
|
||||
#if ROUNDING_ENABLED == false
|
||||
_maxEchoTime = min(max_cm_distance + 1, (unsigned int) MAX_SENSOR_DISTANCE + 1) * US_ROUNDTRIP_CM; // Calculate the maximum distance in uS (no rounding).
|
||||
#else
|
||||
_maxEchoTime = min(max_cm_distance, (unsigned int) MAX_SENSOR_DISTANCE) * US_ROUNDTRIP_CM + (US_ROUNDTRIP_CM / 2); // Calculate the maximum distance in uS.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if TIMER_ENABLED == true && DO_BITWISE == true
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Timer interrupt ping methods (won't work with non-AVR, ATmega128 and all ATtiny microcontrollers)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void NewPing::ping_timer(void (*userFunc)(void), unsigned int max_cm_distance) {
|
||||
if (max_cm_distance > 0) set_max_distance(max_cm_distance); // Call function to set a new max sensor distance.
|
||||
|
||||
if (!ping_trigger()) return; // Trigger a ping, if it returns false, return without starting the echo timer.
|
||||
timer_us(ECHO_TIMER_FREQ, userFunc); // Set ping echo timer check every ECHO_TIMER_FREQ uS.
|
||||
}
|
||||
|
||||
|
||||
boolean NewPing::check_timer() {
|
||||
if (micros() > _max_time) { // Outside the time-out limit.
|
||||
timer_stop(); // Disable timer interrupt
|
||||
return false; // Cancel ping timer.
|
||||
}
|
||||
|
||||
#if URM37_ENABLED == false
|
||||
if (!(*_echoInput & _echoBit)) { // Ping echo received.
|
||||
#else
|
||||
if (*_echoInput & _echoBit) { // Ping echo received.
|
||||
#endif
|
||||
timer_stop(); // Disable timer interrupt
|
||||
ping_result = (micros() - (_max_time - _maxEchoTime) - PING_TIMER_OVERHEAD); // Calculate ping time including overhead.
|
||||
return true; // Return ping echo true.
|
||||
}
|
||||
|
||||
return false; // Return false because there's no ping echo yet.
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Timer2/Timer4 interrupt methods (can be used for non-ultrasonic needs)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Variables used for timer functions
|
||||
void (*intFunc)();
|
||||
void (*intFunc2)();
|
||||
unsigned long _ms_cnt_reset;
|
||||
volatile unsigned long _ms_cnt;
|
||||
#if defined(__arm__) && defined(TEENSYDUINO)
|
||||
IntervalTimer itimer;
|
||||
#endif
|
||||
|
||||
|
||||
void NewPing::timer_us(unsigned int frequency, void (*userFunc)(void)) {
|
||||
intFunc = userFunc; // User's function to call when there's a timer event.
|
||||
timer_setup(); // Configure the timer interrupt.
|
||||
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
OCR4C = min((frequency>>2) - 1, 255); // Every count is 4uS, so divide by 4 (bitwise shift right 2) subtract one, then make sure we don't go over 255 limit.
|
||||
TIMSK4 = (1<<TOIE4); // Enable Timer4 interrupt.
|
||||
#elif defined (__arm__) && defined (TEENSYDUINO) // Timer for Teensy 3.x
|
||||
itimer.begin(userFunc, frequency); // Really simple on the Teensy 3.x, calls userFunc every 'frequency' uS.
|
||||
#else
|
||||
OCR2A = min((frequency>>2) - 1, 255); // Every count is 4uS, so divide by 4 (bitwise shift right 2) subtract one, then make sure we don't go over 255 limit.
|
||||
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 interrupt.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NewPing::timer_ms(unsigned long frequency, void (*userFunc)(void)) {
|
||||
intFunc = NewPing::timer_ms_cntdwn; // Timer events are sent here once every ms till user's frequency is reached.
|
||||
intFunc2 = userFunc; // User's function to call when user's frequency is reached.
|
||||
_ms_cnt = _ms_cnt_reset = frequency; // Current ms counter and reset value.
|
||||
timer_setup(); // Configure the timer interrupt.
|
||||
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
OCR4C = 249; // Every count is 4uS, so 1ms = 250 counts - 1.
|
||||
TIMSK4 = (1<<TOIE4); // Enable Timer4 interrupt.
|
||||
#elif defined (__arm__) && defined (TEENSYDUINO) // Timer for Teensy 3.x
|
||||
itimer.begin(NewPing::timer_ms_cntdwn, 1000); // Set timer to 1ms (1000 uS).
|
||||
#else
|
||||
OCR2A = 249; // Every count is 4uS, so 1ms = 250 counts - 1.
|
||||
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 interrupt.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NewPing::timer_stop() { // Disable timer interrupt.
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
TIMSK4 = 0;
|
||||
#elif defined (__arm__) && defined (TEENSYDUINO) // Timer for Teensy 3.x
|
||||
itimer.end();
|
||||
#else
|
||||
TIMSK2 &= ~(1<<OCIE2A);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Timer2/Timer4 interrupt method support functions (not called directly)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void NewPing::timer_setup() {
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
timer_stop(); // Disable Timer4 interrupt.
|
||||
TCCR4A = TCCR4C = TCCR4D = TCCR4E = 0;
|
||||
TCCR4B = (1<<CS42) | (1<<CS41) | (1<<CS40) | (1<<PSR4); // Set Timer4 prescaler to 64 (4uS/count, 4uS-1020uS range).
|
||||
TIFR4 = (1<<TOV4);
|
||||
TCNT4 = 0; // Reset Timer4 counter.
|
||||
#elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__) || defined (__AVR_ATmega8535__) // Alternate timer commands for certain microcontrollers.
|
||||
timer_stop(); // Disable Timer2 interrupt.
|
||||
ASSR &= ~(1<<AS2); // Set clock, not pin.
|
||||
TCCR2 = (1<<WGM21 | 1<<CS22); // Set Timer2 to CTC mode, prescaler to 64 (4uS/count, 4uS-1020uS range).
|
||||
TCNT2 = 0; // Reset Timer2 counter.
|
||||
#elif defined (__arm__) && defined (TEENSYDUINO)
|
||||
timer_stop(); // Stop the timer.
|
||||
#else
|
||||
timer_stop(); // Disable Timer2 interrupt.
|
||||
ASSR &= ~(1<<AS2); // Set clock, not pin.
|
||||
TCCR2A = (1<<WGM21); // Set Timer2 to CTC mode.
|
||||
TCCR2B = (1<<CS22); // Set Timer2 prescaler to 64 (4uS/count, 4uS-1020uS range).
|
||||
TCNT2 = 0; // Reset Timer2 counter.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NewPing::timer_ms_cntdwn() {
|
||||
if (!_ms_cnt--) { // Count down till we reach zero.
|
||||
intFunc2(); // Scheduled time reached, run the main timer event function.
|
||||
_ms_cnt = _ms_cnt_reset; // Reset the ms timer.
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
ISR(TIMER4_OVF_vect) {
|
||||
intFunc(); // Call wrapped function.
|
||||
}
|
||||
#elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__) || defined (__AVR_ATmega8535__) // Alternate timer commands for certain microcontrollers.
|
||||
ISR(TIMER2_COMP_vect) {
|
||||
intFunc(); // Call wrapped function.
|
||||
}
|
||||
#elif defined (__arm__)
|
||||
// Do nothing...
|
||||
#else
|
||||
ISR(TIMER2_COMPA_vect) {
|
||||
intFunc(); // Call wrapped function.
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Conversion methods (rounds result to nearest cm or inch).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
unsigned int NewPing::convert_cm(unsigned int echoTime) {
|
||||
#if ROUNDING_ENABLED == false
|
||||
return (echoTime / US_ROUNDTRIP_CM); // Convert uS to centimeters (no rounding).
|
||||
#else
|
||||
return NewPingConvert(echoTime, US_ROUNDTRIP_CM); // Convert uS to centimeters.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
unsigned int NewPing::convert_in(unsigned int echoTime) {
|
||||
#if ROUNDING_ENABLED == false
|
||||
return (echoTime / US_ROUNDTRIP_IN); // Convert uS to inches (no rounding).
|
||||
#else
|
||||
return NewPingConvert(echoTime, US_ROUNDTRIP_IN); // Convert uS to inches.
|
||||
#endif
|
||||
}
|
||||
Executable
+245
@@ -0,0 +1,245 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// NewPing Library - v1.8 - 07/30/2016
|
||||
//
|
||||
// AUTHOR/LICENSE:
|
||||
// Created by Tim Eckel - teckel@leethost.com
|
||||
// Copyright 2016 License: GNU GPL v3 http://www.gnu.org/licenses/gpl.html
|
||||
//
|
||||
// LINKS:
|
||||
// Project home: https://bitbucket.org/teckel12/arduino-new-ping/wiki/Home
|
||||
// Blog: http://arduino.cc/forum/index.php/topic,106043.0.html
|
||||
//
|
||||
// DISCLAIMER:
|
||||
// This software is furnished "as is", without technical support, and with no
|
||||
// warranty, express or implied, as to its usefulness for any purpose.
|
||||
//
|
||||
// BACKGROUND:
|
||||
// When I first received an ultrasonic sensor I was not happy with how poorly
|
||||
// it worked. Quickly I realized the problem wasn't the sensor, it was the
|
||||
// available ping and ultrasonic libraries causing the problem. The NewPing
|
||||
// library totally fixes these problems, adds many new features, and breaths
|
||||
// new life into these very affordable distance sensors.
|
||||
//
|
||||
// FEATURES:
|
||||
// * Works with many different ultrasonic sensors: SR04, SRF05, SRF06, DYP-ME007, URM37 & Parallax PING))).
|
||||
// * Compatible with the entire Arduino line-up (and clones), Teensy family (including $19 96Mhz 32 bit Teensy 3.2) and non-AVR microcontrollers.
|
||||
// * Interface with all but the SRF06 sensor using only one Arduino pin.
|
||||
// * Doesn't lag for a full second if no ping/echo is received.
|
||||
// * Ping sensors consistently and reliably at up to 30 times per second.
|
||||
// * Timer interrupt method for event-driven sketches.
|
||||
// * Built-in digital filter method ping_median() for easy error correction.
|
||||
// * Uses port registers for a faster pin interface and smaller code size.
|
||||
// * Allows you to set a maximum distance where pings beyond that distance are read as no ping "clear".
|
||||
// * Ease of using multiple sensors (example sketch with 15 sensors).
|
||||
// * More accurate distance calculation (cm, inches & uS).
|
||||
// * Doesn't use pulseIn, which is slow and gives incorrect results with some ultrasonic sensor models.
|
||||
// * Actively developed with features being added and bugs/issues addressed.
|
||||
//
|
||||
// CONSTRUCTOR:
|
||||
// NewPing sonar(trigger_pin, echo_pin [, max_cm_distance])
|
||||
// trigger_pin & echo_pin - Arduino pins connected to sensor trigger and echo.
|
||||
// NOTE: To use the same Arduino pin for trigger and echo, specify the same pin for both values.
|
||||
// max_cm_distance - [Optional] Maximum distance you wish to sense. Default=500cm.
|
||||
//
|
||||
// METHODS:
|
||||
// sonar.ping([max_cm_distance]) - Send a ping and get the echo time (in microseconds) as a result. [max_cm_distance] allows you to optionally set a new max distance.
|
||||
// sonar.ping_in([max_cm_distance]) - Send a ping and get the distance in whole inches. [max_cm_distance] allows you to optionally set a new max distance.
|
||||
// sonar.ping_cm([max_cm_distance]) - Send a ping and get the distance in whole centimeters. [max_cm_distance] allows you to optionally set a new max distance.
|
||||
// sonar.ping_median(iterations [, max_cm_distance]) - Do multiple pings (default=5), discard out of range pings and return median in microseconds. [max_cm_distance] allows you to optionally set a new max distance.
|
||||
// NewPing::convert_in(echoTime) - Convert echoTime from microseconds to inches (rounds to nearest inch).
|
||||
// NewPing::convert_cm(echoTime) - Convert echoTime from microseconds to centimeters (rounds to nearest cm).
|
||||
// sonar.ping_timer(function [, max_cm_distance]) - Send a ping and call function to test if ping is complete. [max_cm_distance] allows you to optionally set a new max distance.
|
||||
// sonar.check_timer() - Check if ping has returned within the set distance limit.
|
||||
// NewPing::timer_us(frequency, function) - Call function every frequency microseconds.
|
||||
// NewPing::timer_ms(frequency, function) - Call function every frequency milliseconds.
|
||||
// NewPing::timer_stop() - Stop the timer.
|
||||
//
|
||||
// HISTORY:
|
||||
// 07/30/2016 v1.8 - Added support for non-AVR microcontrollers. For non-AVR
|
||||
// microcontrollers, advanced ping_timer() timer methods are disabled due to
|
||||
// inconsistencies or no support at all between platforms. However, standard
|
||||
// ping methods are all supported. Added new optional variable to ping(),
|
||||
// ping_in(), ping_cm(), ping_median(), and ping_timer() methods which allows
|
||||
// you to set a new maximum distance for each ping. Added support for the
|
||||
// ATmega16, ATmega32 and ATmega8535 microcontrollers. Changed convert_cm()
|
||||
// and convert_in() methods to static members. You can now call them without
|
||||
// an object. For example: cm = NewPing::convert_cm(distance);
|
||||
//
|
||||
// 09/29/2015 v1.7 - Removed support for the Arduino Due and Zero because
|
||||
// they're both 3.3 volt boards and are not 5 volt tolerant while the HC-SR04
|
||||
// is a 5 volt sensor. Also, the Due and Zero don't support pin manipulation
|
||||
// compatibility via port registers which can be done (see the Teensy 3.2).
|
||||
//
|
||||
// 06/17/2014 v1.6 - Corrected delay between pings when using ping_median()
|
||||
// method. Added support for the URM37 sensor (must change URM37_ENABLED from
|
||||
// false to true). Added support for Arduino microcontrollers like the $20
|
||||
// 32 bit ARM Cortex-M4 based Teensy 3.2. Added automatic support for the
|
||||
// Atmel ATtiny family of microcontrollers. Added timer support for the
|
||||
// ATmega8 microcontroller. Rounding disabled by default, reduces compiled
|
||||
// code size (can be turned on with ROUNDING_ENABLED switch). Added
|
||||
// TIMER_ENABLED switch to get around compile-time "__vector_7" errors when
|
||||
// using the Tone library, or you can use the toneAC, NewTone or
|
||||
// TimerFreeTone libraries: https://bitbucket.org/teckel12/arduino-toneac/
|
||||
// Other speed and compiled size optimizations.
|
||||
//
|
||||
// 08/15/2012 v1.5 - Added ping_median() method which does a user specified
|
||||
// number of pings (default=5) and returns the median ping in microseconds
|
||||
// (out of range pings ignored). This is a very effective digital filter.
|
||||
// Optimized for smaller compiled size (even smaller than sketches that
|
||||
// don't use a library).
|
||||
//
|
||||
// 07/14/2012 v1.4 - Added support for the Parallax PING)))� sensor. Interface
|
||||
// with all but the SRF06 sensor using only one Arduino pin. You can also
|
||||
// interface with the SRF06 using one pin if you install a 0.1uf capacitor
|
||||
// on the trigger and echo pins of the sensor then tie the trigger pin to
|
||||
// the Arduino pin (doesn't work with Teensy). To use the same Arduino pin
|
||||
// for trigger and echo, specify the same pin for both values. Various bug
|
||||
// fixes.
|
||||
//
|
||||
// 06/08/2012 v1.3 - Big feature addition, event-driven ping! Uses Timer2
|
||||
// interrupt, so be mindful of PWM or timing conflicts messing with Timer2
|
||||
// may cause (namely PWM on pins 3 & 11 on Arduino, PWM on pins 9 and 10 on
|
||||
// Mega, and Tone library). Simple to use timer interrupt functions you can
|
||||
// use in your sketches totally unrelated to ultrasonic sensors (don't use if
|
||||
// you're also using NewPing's ping_timer because both use Timer2 interrupts).
|
||||
// Loop counting ping method deleted in favor of timing ping method after
|
||||
// inconsistent results kept surfacing with the loop timing ping method.
|
||||
// Conversion to cm and inches now rounds to the nearest cm or inch. Code
|
||||
// optimized to save program space and fixed a couple minor bugs here and
|
||||
// there. Many new comments added as well as line spacing to group code
|
||||
// sections for better source readability.
|
||||
//
|
||||
// 05/25/2012 v1.2 - Lots of code clean-up thanks to Arduino Forum members.
|
||||
// Rebuilt the ping timing code from scratch, ditched the pulseIn code as it
|
||||
// doesn't give correct results (at least with ping sensors). The NewPing
|
||||
// library is now VERY accurate and the code was simplified as a bonus.
|
||||
// Smaller and faster code as well. Fixed some issues with very close ping
|
||||
// results when converting to inches. All functions now return 0 only when
|
||||
// there's no ping echo (out of range) and a positive value for a successful
|
||||
// ping. This can effectively be used to detect if something is out of range
|
||||
// or in-range and at what distance. Now compatible with Arduino 0023.
|
||||
//
|
||||
// 05/16/2012 v1.1 - Changed all I/O functions to use low-level port registers
|
||||
// for ultra-fast and lean code (saves from 174 to 394 bytes). Tested on both
|
||||
// the Arduino Uno and Teensy 2.0 but should work on all Arduino-based
|
||||
// platforms because it calls standard functions to retrieve port registers
|
||||
// and bit masks. Also made a couple minor fixes to defines.
|
||||
//
|
||||
// 05/15/2012 v1.0 - Initial release.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#ifndef NewPing_h
|
||||
#define NewPing_h
|
||||
|
||||
#if defined (ARDUINO) && ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#include <pins_arduino.h>
|
||||
#endif
|
||||
|
||||
#if defined (__AVR__)
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#endif
|
||||
|
||||
// Shouldn't need to change these values unless you have a specific need to do so.
|
||||
#define MAX_SENSOR_DISTANCE 500 // Maximum sensor distance can be as high as 500cm, no reason to wait for ping longer than sound takes to travel this distance and back. Default=500
|
||||
#define US_ROUNDTRIP_CM 57 // Microseconds (uS) it takes sound to travel round-trip 1cm (2cm total), uses integer to save compiled code space. Default=57
|
||||
#define US_ROUNDTRIP_IN 146 // Microseconds (uS) it takes sound to travel round-trip 1 inch (2 inches total), uses integer to save compiled code space. Defalult=146
|
||||
#define ONE_PIN_ENABLED true // Set to "false" to disable one pin mode which saves around 14-26 bytes of binary size. Default=true
|
||||
#define ROUNDING_ENABLED false // Set to "true" to enable distance rounding which also adds 64 bytes to binary size. Default=false
|
||||
#define URM37_ENABLED false // Set to "true" to enable support for the URM37 sensor in PWM mode. Default=false
|
||||
#define TIMER_ENABLED true // Set to "false" to disable the timer ISR (if getting "__vector_7" compile errors set this to false). Default=true
|
||||
|
||||
// Probably shouldn't change these values unless you really know what you're doing.
|
||||
#define NO_ECHO 0 // Value returned if there's no ping echo within the specified MAX_SENSOR_DISTANCE or max_cm_distance. Default=0
|
||||
#define MAX_SENSOR_DELAY 5800 // Maximum uS it takes for sensor to start the ping. Default=5800
|
||||
#define ECHO_TIMER_FREQ 24 // Frequency to check for a ping echo (every 24uS is about 0.4cm accuracy). Default=24
|
||||
#define PING_MEDIAN_DELAY 29000 // Microsecond delay between pings in the ping_median method. Default=29000
|
||||
#define PING_OVERHEAD 5 // Ping overhead in microseconds (uS). Default=5
|
||||
#define PING_TIMER_OVERHEAD 13 // Ping timer overhead in microseconds (uS). Default=13
|
||||
#if URM37_ENABLED == true
|
||||
#undef US_ROUNDTRIP_CM
|
||||
#undef US_ROUNDTRIP_IN
|
||||
#define US_ROUNDTRIP_CM 50 // Every 50uS PWM signal is low indicates 1cm distance. Default=50
|
||||
#define US_ROUNDTRIP_IN 127 // If 50uS is 1cm, 1 inch would be 127uS (50 x 2.54 = 127). Default=127
|
||||
#endif
|
||||
|
||||
// Conversion from uS to distance (round result to nearest cm or inch).
|
||||
#define NewPingConvert(echoTime, conversionFactor) (max(((unsigned int)echoTime + conversionFactor / 2) / conversionFactor, (echoTime ? 1 : 0)))
|
||||
|
||||
// Detect non-AVR microcontrollers (Teensy 3.x, Arduino DUE, etc.) and don't use port registers or timer interrupts as required.
|
||||
#if (defined (__arm__) && defined (TEENSYDUINO))
|
||||
#undef PING_OVERHEAD
|
||||
#define PING_OVERHEAD 1
|
||||
#undef PING_TIMER_OVERHEAD
|
||||
#define PING_TIMER_OVERHEAD 1
|
||||
#define DO_BITWISE true
|
||||
#elif !defined (__AVR__)
|
||||
#undef PING_OVERHEAD
|
||||
#define PING_OVERHEAD 1
|
||||
#undef PING_TIMER_OVERHEAD
|
||||
#define PING_TIMER_OVERHEAD 1
|
||||
#undef TIMER_ENABLED
|
||||
#define TIMER_ENABLED false
|
||||
#define DO_BITWISE false
|
||||
#else
|
||||
#define DO_BITWISE true
|
||||
#endif
|
||||
|
||||
// Disable the timer interrupts when using ATmega128 and all ATtiny microcontrollers.
|
||||
#if defined (__AVR_ATmega128__) || defined (__AVR_ATtiny24__) || defined (__AVR_ATtiny44__) || defined (__AVR_ATtiny84__) || defined (__AVR_ATtiny25__) || defined (__AVR_ATtiny45__) || defined (__AVR_ATtiny85__) || defined (__AVR_ATtiny261__) || defined (__AVR_ATtiny461__) || defined (__AVR_ATtiny861__) || defined (__AVR_ATtiny43U__)
|
||||
#undef TIMER_ENABLED
|
||||
#define TIMER_ENABLED false
|
||||
#endif
|
||||
|
||||
// Define timers when using ATmega8, ATmega16, ATmega32 and ATmega8535 microcontrollers.
|
||||
#if defined (__AVR_ATmega8__) || defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__) || defined (__AVR_ATmega8535__)
|
||||
#define OCR2A OCR2
|
||||
#define TIMSK2 TIMSK
|
||||
#define OCIE2A OCIE2
|
||||
#endif
|
||||
|
||||
class NewPing {
|
||||
public:
|
||||
NewPing(uint8_t trigger_pin, uint8_t echo_pin, unsigned int max_cm_distance = MAX_SENSOR_DISTANCE);
|
||||
unsigned int ping(unsigned int max_cm_distance = 0);
|
||||
unsigned long ping_cm(unsigned int max_cm_distance = 0);
|
||||
unsigned long ping_in(unsigned int max_cm_distance = 0);
|
||||
unsigned long ping_median(uint8_t it = 5, unsigned int max_cm_distance = 0);
|
||||
static unsigned int convert_cm(unsigned int echoTime);
|
||||
static unsigned int convert_in(unsigned int echoTime);
|
||||
#if TIMER_ENABLED == true
|
||||
void ping_timer(void (*userFunc)(void), unsigned int max_cm_distance = 0);
|
||||
boolean check_timer();
|
||||
unsigned long ping_result;
|
||||
static void timer_us(unsigned int frequency, void (*userFunc)(void));
|
||||
static void timer_ms(unsigned long frequency, void (*userFunc)(void));
|
||||
static void timer_stop();
|
||||
#endif
|
||||
private:
|
||||
boolean ping_trigger();
|
||||
void set_max_distance(unsigned int max_cm_distance);
|
||||
#if TIMER_ENABLED == true
|
||||
boolean ping_trigger_timer(unsigned int trigger_delay);
|
||||
boolean ping_wait_timer();
|
||||
static void timer_setup();
|
||||
static void timer_ms_cntdwn();
|
||||
#endif
|
||||
#if DO_BITWISE == true
|
||||
uint8_t _triggerBit;
|
||||
uint8_t _echoBit;
|
||||
volatile uint8_t *_triggerOutput;
|
||||
volatile uint8_t *_echoInput;
|
||||
volatile uint8_t *_triggerMode;
|
||||
#else
|
||||
uint8_t _triggerPin;
|
||||
uint8_t _echoPin;
|
||||
#endif
|
||||
unsigned int _maxEchoTime;
|
||||
unsigned long _max_time;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// This example code was used to successfully communicate with 15 ultrasonic sensors. You can adjust
|
||||
// the number of sensors in your project by changing SONAR_NUM and the number of NewPing objects in the
|
||||
// "sonar" array. You also need to change the pins for each sensor for the NewPing objects. Each sensor
|
||||
// is pinged at 33ms intervals. So, one cycle of all sensors takes 495ms (33 * 15 = 495ms). The results
|
||||
// are sent to the "oneSensorCycle" function which currently just displays the distance data. Your project
|
||||
// would normally process the sensor results in this function (for example, decide if a robot needs to
|
||||
// turn and call the turn function). Keep in mind this example is event-driven. Your complete sketch needs
|
||||
// to be written so there's no "delay" commands and the loop() cycles at faster than a 33ms rate. If other
|
||||
// processes take longer than 33ms, you'll need to increase PING_INTERVAL so it doesn't get behind.
|
||||
// ---------------------------------------------------------------------------
|
||||
#include <NewPing.h>
|
||||
|
||||
#define SONAR_NUM 15 // Number of sensors.
|
||||
#define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.
|
||||
#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).
|
||||
|
||||
unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor.
|
||||
unsigned int cm[SONAR_NUM]; // Where the ping distances are stored.
|
||||
uint8_t currentSensor = 0; // Keeps track of which sensor is active.
|
||||
|
||||
NewPing sonar[SONAR_NUM] = { // Sensor object array.
|
||||
NewPing(41, 42, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
|
||||
NewPing(43, 44, MAX_DISTANCE),
|
||||
NewPing(45, 20, MAX_DISTANCE),
|
||||
NewPing(21, 22, MAX_DISTANCE),
|
||||
NewPing(23, 24, MAX_DISTANCE),
|
||||
NewPing(25, 26, MAX_DISTANCE),
|
||||
NewPing(27, 28, MAX_DISTANCE),
|
||||
NewPing(29, 30, MAX_DISTANCE),
|
||||
NewPing(31, 32, MAX_DISTANCE),
|
||||
NewPing(34, 33, MAX_DISTANCE),
|
||||
NewPing(35, 36, MAX_DISTANCE),
|
||||
NewPing(37, 38, MAX_DISTANCE),
|
||||
NewPing(39, 40, MAX_DISTANCE),
|
||||
NewPing(50, 51, MAX_DISTANCE),
|
||||
NewPing(52, 53, MAX_DISTANCE)
|
||||
};
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
pingTimer[0] = millis() + 75; // First ping starts at 75ms, gives time for the Arduino to chill before starting.
|
||||
for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor.
|
||||
pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors.
|
||||
if (millis() >= pingTimer[i]) { // Is it this sensor's time to ping?
|
||||
pingTimer[i] += PING_INTERVAL * SONAR_NUM; // Set next time this sensor will be pinged.
|
||||
if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
|
||||
sonar[currentSensor].timer_stop(); // Make sure previous timer is canceled before starting a new ping (insurance).
|
||||
currentSensor = i; // Sensor being accessed.
|
||||
cm[currentSensor] = 0; // Make distance zero in case there's no ping echo for this sensor.
|
||||
sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).
|
||||
}
|
||||
}
|
||||
// Other code that *DOESN'T* analyze ping results can go here.
|
||||
}
|
||||
|
||||
void echoCheck() { // If ping received, set the sensor distance to array.
|
||||
if (sonar[currentSensor].check_timer())
|
||||
cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
|
||||
}
|
||||
|
||||
void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.
|
||||
// The following code would be replaced with your code that does something with the ping results.
|
||||
for (uint8_t i = 0; i < SONAR_NUM; i++) {
|
||||
Serial.print(i);
|
||||
Serial.print("=");
|
||||
Serial.print(cm[i]);
|
||||
Serial.print("cm ");
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// This example shows how to use NewPing's ping_timer method which uses the Timer2 interrupt to get the
|
||||
// ping time. The advantage of using this method over the standard ping method is that it permits a more
|
||||
// event-driven sketch which allows you to appear to do two things at once. An example would be to ping
|
||||
// an ultrasonic sensor for a possible collision while at the same time navigating. This allows a
|
||||
// properly developed sketch to multitask. Be aware that because the ping_timer method uses Timer2,
|
||||
// other features or libraries that also use Timer2 would be effected. For example, the PWM function on
|
||||
// pins 3 & 11 on Arduino Uno (pins 9 and 11 on Arduino Mega) and the Tone library. Note, only the PWM
|
||||
// functionality of the pins is lost (as they use Timer2 to do PWM), the pins are still available to use.
|
||||
// NOTE: For Teensy/Leonardo (ATmega32U4) the library uses Timer4 instead of Timer2.
|
||||
// ---------------------------------------------------------------------------
|
||||
#include <NewPing.h>
|
||||
|
||||
#define TRIGGER_PIN 12 // Arduino pin tied to trigger pin on ping sensor.
|
||||
#define ECHO_PIN 11 // Arduino pin tied to echo pin on ping sensor.
|
||||
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
|
||||
|
||||
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
|
||||
|
||||
unsigned int pingSpeed = 50; // How frequently are we going to send out a ping (in milliseconds). 50ms would be 20 times a second.
|
||||
unsigned long pingTimer; // Holds the next ping time.
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
|
||||
pingTimer = millis(); // Start now.
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Notice how there's no delays in this sketch to allow you to do other processing in-line while doing distance pings.
|
||||
if (millis() >= pingTimer) { // pingSpeed milliseconds since last ping, do another ping.
|
||||
pingTimer += pingSpeed; // Set the next ping time.
|
||||
sonar.ping_timer(echoCheck); // Send out the ping, calls "echoCheck" function every 24uS where you can check the ping status.
|
||||
}
|
||||
// Do other stuff here, really. Think of it as multi-tasking.
|
||||
}
|
||||
|
||||
void echoCheck() { // Timer2 interrupt calls this function every 24uS where you can check the ping status.
|
||||
// Don't do anything here!
|
||||
if (sonar.check_timer()) { // This is how you check to see if the ping was received.
|
||||
// Here's where you can add code.
|
||||
Serial.print("Ping: ");
|
||||
Serial.print(sonar.ping_result / US_ROUNDTRIP_CM); // Ping returned, uS result in ping_result, convert to cm with US_ROUNDTRIP_CM.
|
||||
Serial.println("cm");
|
||||
}
|
||||
// Don't do anything here!
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// Example NewPing library sketch that does a ping about 20 times per second.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#include <NewPing.h>
|
||||
|
||||
#define TRIGGER_PIN 12 // Arduino pin tied to trigger pin on the ultrasonic sensor.
|
||||
#define ECHO_PIN 11 // Arduino pin tied to echo pin on the ultrasonic sensor.
|
||||
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
|
||||
|
||||
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
|
||||
}
|
||||
|
||||
void loop() {
|
||||
delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
|
||||
Serial.print("Ping: ");
|
||||
Serial.print(sonar.ping_cm()); // Send ping, get distance in cm and print result (0 = outside set distance range)
|
||||
Serial.println("cm");
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// While the NewPing library's primary goal is to interface with ultrasonic sensors, interfacing with
|
||||
// the Timer2 interrupt was a result of creating an interrupt-based ping method. Since these Timer2
|
||||
// interrupt methods were built, the library may as well provide the functionality to use these methods
|
||||
// in your sketches. This shows how simple it is (no ultrasonic sensor required). Keep in mind that
|
||||
// these methods use Timer2, as does NewPing's ping_timer method for using ultrasonic sensors. You
|
||||
// can't use ping_timer at the same time you're using timer_ms or timer_us as all use the same timer.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#include <NewPing.h>
|
||||
|
||||
#define LED_PIN 13 // Pin with LED attached.
|
||||
|
||||
void setup() {
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
NewPing::timer_ms(500, toggleLED); // Create a Timer2 interrupt that calls toggleLED in your sketch once every 500 milliseconds.
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Do anything here, the Timer2 interrupt will take care of the flashing LED without your intervention.
|
||||
}
|
||||
|
||||
void toggleLED() {
|
||||
digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Toggle the LED.
|
||||
}
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
###################################
|
||||
# Syntax Coloring Map For NewPing
|
||||
###################################
|
||||
|
||||
###################################
|
||||
# Datatypes (KEYWORD1)
|
||||
###################################
|
||||
|
||||
NewPing KEYWORD1
|
||||
|
||||
###################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
###################################
|
||||
|
||||
ping KEYWORD2
|
||||
ping_in KEYWORD2
|
||||
ping_cm KEYWORD2
|
||||
ping_median KEYWORD2
|
||||
ping_timer KEYWORD2
|
||||
check_timer KEYWORD2
|
||||
timer_us KEYWORD2
|
||||
timer_ms KEYWORD2
|
||||
timer_stop KEYWORD2
|
||||
convert_in KEYWORD2
|
||||
convert_cm KEYWORD2
|
||||
|
||||
###################################
|
||||
# Constants (LITERAL1)
|
||||
###################################
|
||||
+116
-29
@@ -25,7 +25,7 @@
|
||||
|
||||
#include "jkSDS011.h"
|
||||
|
||||
CjkSDS011::CjkSDS011(int16_t pinRX, int16_t pinTX) : _serial(pinRX, pinTX)
|
||||
CjkSDS011::CjkSDS011(int16_t pinRX, int16_t pinTX)
|
||||
{
|
||||
_sws = ! ( pinRX < 0 || pinRX == 3 );
|
||||
_pm2_5 = NAN;
|
||||
@@ -35,43 +35,131 @@ CjkSDS011::CjkSDS011(int16_t pinRX, int16_t pinTX) : _serial(pinRX, pinTX)
|
||||
_pm10_avr = 0;
|
||||
_avr = 0;
|
||||
_data.SetPacketLength(10);
|
||||
_command.SetPacketLength(19);
|
||||
_working_period = -1;
|
||||
_sleepmode_active = false;
|
||||
_serial = new ESPeasySoftwareSerial(pinRX, pinTX);
|
||||
_serial->begin(9600);
|
||||
}
|
||||
|
||||
_serial.begin(9600);
|
||||
CjkSDS011::~CjkSDS011() {
|
||||
delete _serial;
|
||||
}
|
||||
|
||||
void CjkSDS011::SendCommand(byte byte1, byte byte2, byte byte3) {
|
||||
_command[0] = 0xAA; // Head
|
||||
_command[1] = 0xB4; // Command ID
|
||||
_command[2] = byte1; // Data Byte 1
|
||||
_command[3] = byte2; // Data Byte 2
|
||||
_command[4] = byte3; // Data Byte 3
|
||||
_command[5] = 0; // Data Byte 4
|
||||
_command[6] = 0; // Data Byte 5
|
||||
_command[7] = 0; // Data Byte 6
|
||||
_command[8] = 0; // Data Byte 7
|
||||
_command[9] = 0; // Data Byte 8
|
||||
_command[10] = 0; // Data Byte 9
|
||||
_command[11] = 0; // Data Byte 10
|
||||
_command[12] = 0; // Data Byte 11
|
||||
_command[13] = 0; // Data Byte 12
|
||||
_command[14] = 0; // Data Byte 13
|
||||
_command[15] = 0xFF; // Device ID byte 1, FF: All sensor response
|
||||
_command[16] = 0xFF; // Device ID byte 2, FF: All sensor response
|
||||
|
||||
byte checksum = 0;
|
||||
for (byte i=2; i< 17; ++i) {
|
||||
checksum += _command[i];
|
||||
}
|
||||
_command[17] = checksum; // Checksum
|
||||
_command[18] = 0xAB; // Tail
|
||||
|
||||
for (int i = 0; i < 19; ++i) {
|
||||
_serial->write(_command[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void CjkSDS011::SetSleepMode(bool enabled) {
|
||||
byte databyte3 = enabled ? 0 : 1;
|
||||
SendCommand(6, 1, databyte3);
|
||||
}
|
||||
|
||||
void CjkSDS011::SetWorkingPeriod(int minutes) {
|
||||
// Data byte 1: 8
|
||||
// Data byte 2: 0: query the current mode
|
||||
// 1: set mode
|
||||
// Data byte 3: 0:continuous(default)
|
||||
// 1-30minute:work 30 seconds and sleep n*60-30 seconds
|
||||
if (minutes < 0 || minutes > 30) return;
|
||||
// Working period is stored in the flash of the sensor. Only write to change.
|
||||
const int currentWorkingPeriod = GetWorkingPeriod();
|
||||
if (minutes != currentWorkingPeriod)
|
||||
SendCommand(8, 1, minutes);
|
||||
}
|
||||
|
||||
int CjkSDS011::GetWorkingPeriod() {
|
||||
// Data byte 1: 8
|
||||
// Data byte 2: 0: query the current mode
|
||||
// 1: set mode
|
||||
// Data byte 3: 0:continuous(default)
|
||||
// 1-30minute:work 30 seconds and sleep n*60-30 seconds
|
||||
SendCommand(8, 0, 0);
|
||||
Process();
|
||||
return _working_period;
|
||||
}
|
||||
|
||||
void CjkSDS011::ParseCommandReply() {
|
||||
switch(_data[2]) {
|
||||
case 6: // Enable/Disable sleep mode.
|
||||
if (_data[3] == 0)
|
||||
_sleepmode_active = _data[4];
|
||||
break;
|
||||
case 8: // Set/Get working period
|
||||
if (_data[3] == 0)
|
||||
_working_period = _data[4];
|
||||
break;
|
||||
default:
|
||||
// Not implemented.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CjkSDS011::Process()
|
||||
{
|
||||
while (_serial.available())
|
||||
while (_serial->available())
|
||||
{
|
||||
_data.AddData(_serial.read());
|
||||
_data.AddData(_serial->read());
|
||||
|
||||
if (_data[0] == 0xAA && _data[9] == 0xAB && (_data[1] == 0xC0 || _data[1] == 0xCF)) // correct packet frame?
|
||||
if (_data[0] == 0xAA && _data[9] == 0xAB) // correct packet frame?
|
||||
{
|
||||
byte checksum = 0;
|
||||
for (byte i=2; i<= 7; i++)
|
||||
checksum += _data[i];
|
||||
checksum += _data[i];
|
||||
if (checksum != _data[8])
|
||||
continue;
|
||||
|
||||
if (_data[1] == 0xC0) // SDS011 or SDS018?
|
||||
{
|
||||
_pm2_5 = (float)((_data[3] << 8) | _data[2]) * 0.1;
|
||||
_pm10_ = (float)((_data[5] << 8) | _data[4]) * 0.1;
|
||||
_available = true;
|
||||
switch(_data[1]) {
|
||||
case 0xC0: // SDS011 or SDS018?
|
||||
_pm2_5 = (float)((_data[3] << 8) | _data[2]) * 0.1;
|
||||
_pm10_ = (float)((_data[5] << 8) | _data[4]) * 0.1;
|
||||
_available = true;
|
||||
break;
|
||||
case 0xCF: // SDS198?
|
||||
_pm2_5 = (float)((_data[5] << 8) | _data[4]);
|
||||
_pm10_ = (float)((_data[3] << 8) | _data[2]);
|
||||
_available = true;
|
||||
break;
|
||||
case 0xC5: // Reply on command ID 0xB4
|
||||
ParseCommandReply();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
else if (_data[1] == 0xCF) // SDS198?
|
||||
{
|
||||
_pm2_5 = (float)((_data[5] << 8) | _data[4]);
|
||||
_pm10_ = (float)((_data[3] << 8) | _data[2]);
|
||||
_available = true;
|
||||
if (_available) {
|
||||
_pm2_5avr += _pm2_5;
|
||||
_pm10_avr += _pm10_;
|
||||
_avr++;
|
||||
_data.Clear();
|
||||
return;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
_pm2_5avr += _pm2_5;
|
||||
_pm10_avr += _pm10_;
|
||||
_avr++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,7 +171,7 @@ boolean CjkSDS011::available()
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CjkSDS011::ReadAverage(float &pm25, float &pm10)
|
||||
boolean CjkSDS011::ReadAverage(float &pm25, float &pm10)
|
||||
{
|
||||
if (_avr)
|
||||
{
|
||||
@@ -92,10 +180,9 @@ void CjkSDS011::ReadAverage(float &pm25, float &pm10)
|
||||
_pm2_5avr = 0;
|
||||
_pm10_avr = 0;
|
||||
_avr = 0;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pm25 = NAN;
|
||||
pm10 = NAN;
|
||||
}
|
||||
pm25 = NAN;
|
||||
pm10 = NAN;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -27,13 +27,16 @@
|
||||
#define _jkSDS011_H_
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "SensorSerial.h"
|
||||
//#include "SensorSerial.h"
|
||||
#include "SensorSerialBuffer.h"
|
||||
#include "ESPeasySoftwareSerial.h"
|
||||
|
||||
|
||||
class CjkSDS011
|
||||
{
|
||||
public:
|
||||
CjkSDS011(int16_t pinRX, int16_t pinTX);
|
||||
virtual ~CjkSDS011();
|
||||
|
||||
void Process();
|
||||
|
||||
@@ -42,11 +45,28 @@ public:
|
||||
float GetPM2_5() { return _pm2_5; };
|
||||
float GetPM10_() { return _pm10_; };
|
||||
|
||||
void ReadAverage(float &pm25, float &pm10);
|
||||
// Return true when there are valid samples.
|
||||
boolean ReadAverage(float &pm25, float &pm10);
|
||||
|
||||
void SetSleepMode(bool enabled);
|
||||
|
||||
// Set interval to get new data, 0 .. 30 minutes.
|
||||
// Minutes = 0 => continous mode.
|
||||
// The setting is still effective after power off(factory default is continuous measurement)
|
||||
void SetWorkingPeriod(int minutes);
|
||||
|
||||
// Get the working period in minutes (0 = continuous reading)
|
||||
// Negative return value indicates error during communication.
|
||||
int GetWorkingPeriod();
|
||||
|
||||
private:
|
||||
SensorSerial _serial;
|
||||
void SendCommand(byte byte1, byte byte2, byte byte3);
|
||||
void ParseCommandReply();
|
||||
|
||||
// SensorSerial _serial;
|
||||
ESPeasySoftwareSerial *_serial;
|
||||
CSensorSerialBuffer _data;
|
||||
CSensorSerialBuffer _command;
|
||||
float _pm2_5;
|
||||
float _pm10_;
|
||||
float _pm2_5avr;
|
||||
@@ -54,6 +74,8 @@ private:
|
||||
uint16_t _avr;
|
||||
boolean _available;
|
||||
boolean _sws;
|
||||
int _working_period;
|
||||
boolean _sleepmode_active;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,8 +27,9 @@
|
||||
#endif
|
||||
|
||||
// MQTT_KEEPALIVE : keepAlive interval in Seconds
|
||||
// Keepalive timeout for default MQTT Broker is 10s
|
||||
#ifndef MQTT_KEEPALIVE
|
||||
#define MQTT_KEEPALIVE 15
|
||||
#define MQTT_KEEPALIVE 10
|
||||
#endif
|
||||
|
||||
// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
|
||||
|
||||
+553
-118
@@ -5,13 +5,27 @@
|
||||
# http://docs.platformio.org/en/stable/projectconf.html
|
||||
#
|
||||
|
||||
###########################################################################################
|
||||
# You can uncomment or add here Your favorite environment you want to work on at the moment
|
||||
# (uncomment only one !)
|
||||
###########################################################################################
|
||||
|
||||
[platformio]
|
||||
#env_default = esp32dev
|
||||
#env_default = dev_ESP8266_4096
|
||||
#env_default = normal_ESP8266_1024
|
||||
#env_default = normal_ESP8266_4096
|
||||
# ..etc
|
||||
|
||||
|
||||
|
||||
#minimal version for esps with 512K or less flash (only has minimal plugin set)
|
||||
; [env:mini_512]
|
||||
; platform = espressif8266@1.5.0
|
||||
; framework = arduino
|
||||
; platform = ${common.platform}
|
||||
; framework = ${common.framework}
|
||||
; board = esp01
|
||||
; upload_speed=460800
|
||||
; build_flags = !echo -Wl,-Tesp8266.flash.512k64.ld -D BUILD_GIT=\'\"$(git describe)\"\'
|
||||
; upload_speed = ${common.upload_speed}
|
||||
; build_flags = !echo -Wl,-Tesp8266.flash.512k64.ld -D BUILD_GIT=\'\"$(git describe)\"\'
|
||||
; # upload_port = /dev/ttyUSB0
|
||||
|
||||
# add these:
|
||||
@@ -19,140 +33,561 @@
|
||||
# -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-promo -Wstrict-null-sentinel
|
||||
# -Wstrict-overflow=5 -Wundef -Wno-unused -Wno-variadic-macros -Wno-parentheses -fdiagnostics-show-option
|
||||
# thanks @chouffe103
|
||||
[compiler_warnings]
|
||||
build_flags =
|
||||
-Wall -Wno-parentheses -fdiagnostics-show-option
|
||||
|
||||
##########################################################################################
|
||||
|
||||
###### Definition cheat sheet:
|
||||
# board_flash_mode in terms of performance: QIO > QOUT > DIO > DOUT
|
||||
# for lib_ldf_mode, see http://docs.platformio.org/en/latest/librarymanager/ldf.html#ldf
|
||||
|
||||
###### Frequently used build flags:
|
||||
# Use custom.h file to override default settings for ESPeasy: -D USE_CUSTOM_H
|
||||
# Set VCC mode to measure Vcc of ESP chip : -D FEATURE_ADC_VCC=true
|
||||
|
||||
[core_2_3_0]
|
||||
platform = espressif8266@1.5.0
|
||||
|
||||
[core_2_4_0]
|
||||
platform = espressif8266@1.6.0
|
||||
|
||||
[core_2_4_1]
|
||||
platform = espressif8266@1.7.0
|
||||
|
||||
[core_staged]
|
||||
platform = https://github.com/platformio/platform-espressif8266.git#feature/stage
|
||||
|
||||
[core_esp32]
|
||||
platform = espressif32@0.12.0
|
||||
#platform = https://github.com/platformio/platform-espressif32.git#feature/stage
|
||||
build_flags = -D BUILD_GIT='"${env.TRAVIS_TAG}"'
|
||||
lib_ignore = ESPeasySoftwareSerial, EspESPeasySoftwareSerial, AS_BH1750, ESP8266WiFi, ESP8266Ping, ESP8266WebServer, ESP8266HTTPUpdateServer, ESP8266mDNS, IRremoteESP8266, ESPEasy_ESP8266Ping, SerialSensors
|
||||
lib_deps = ESP32WebServer
|
||||
|
||||
|
||||
[common]
|
||||
build_flags = -D BUILD_GIT='"${env.TRAVIS_TAG}"'
|
||||
lib_deps = ""
|
||||
build_flags = -D BUILD_GIT='"${env.TRAVIS_TAG}"' ; ${compiler_warnings.build_flags}
|
||||
-D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
||||
-D NDEBUG
|
||||
lib_deps = ""
|
||||
lib_ignore = ESP32_ping, ESP32WebServer
|
||||
lib_ldf_mode = chain
|
||||
upload_speed = 460800
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
platform = ${core_2_4_1.platform}
|
||||
|
||||
[normal]
|
||||
platform = ${common.platform}
|
||||
|
||||
[testing]
|
||||
platform = ${core_2_4_1.platform}
|
||||
|
||||
[dev]
|
||||
platform = ${core_2_4_1.platform}
|
||||
|
||||
|
||||
#normal version with stable plugins, 1024k version
|
||||
[esp8266_1M]
|
||||
board_flash_mode = dout
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld
|
||||
|
||||
[esp8285_1M]
|
||||
board = esp8285
|
||||
board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
build_flags = ${esp8266_1M.build_flags} -DESP8285
|
||||
|
||||
[Sonoff]
|
||||
board = esp01_1m
|
||||
board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld
|
||||
platform = ${core_2_4_1.platform}
|
||||
|
||||
[Sonoff_8285]
|
||||
board_flash_mode = ${esp8285_1M.board_flash_mode}
|
||||
board = ${esp8285_1M.board}
|
||||
build_flags = ${esp8285_1M.build_flags}
|
||||
platform = ${core_2_4_1.platform}
|
||||
|
||||
[espWroom2M]
|
||||
board_flash_mode = dout
|
||||
board = esp_wroom_02
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.2m.ld
|
||||
|
||||
[esp8266_4M]
|
||||
board_flash_mode = dio
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.4m1m.ld
|
||||
|
||||
### ESP32 pre-alpha test build ###########################################################
|
||||
# Very limited build for ESP32, to start testing regular building for ESP32. #
|
||||
# Will probably not work, not tested and guaranteed to take a few hours time of some #
|
||||
# still trying to build the version without reading this warning. #
|
||||
##########################################################################################
|
||||
[env:esp32dev]
|
||||
platform = ${core_esp32.platform}
|
||||
board = esp32dev
|
||||
build_flags = ${core_esp32.build_flags} -DPLUGIN_SET_GENERIC_ESP32
|
||||
lib_deps = ${core_esp32.lib_deps}
|
||||
lib_ignore = ${core_esp32.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
upload_speed = ${common.upload_speed}
|
||||
#upload_port = 192.168.0.100 # uncoment and change IP to own to use OTA
|
||||
# directly from Platformio, Atom ..
|
||||
|
||||
### NORMAL (STABLE) ######################################################################
|
||||
# normal version with stable plugins #
|
||||
##########################################################################################
|
||||
|
||||
# NORMAL: 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
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld
|
||||
# upload_port = /dev/ttyUSB0
|
||||
platform = ${common.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board = ${common.board}
|
||||
board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
build_flags = ${esp8266_1M.build_flags}
|
||||
|
||||
[env:normal_ESP8266_1024_DOUT]
|
||||
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
|
||||
# upload_port = /dev/ttyUSB0
|
||||
|
||||
#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
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.4m1m.ld
|
||||
# upload_port = /dev/ttyUSB0
|
||||
|
||||
#normal version with stable plugins, 4096k version for esp8285
|
||||
# NORMAL: 1024k 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
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -DESP8285
|
||||
# upload_port = /dev/ttyUSB0
|
||||
platform = ${common.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board = ${esp8285_1M.board}
|
||||
board_flash_mode = ${esp8285_1M.board_flash_mode}
|
||||
build_flags = ${esp8285_1M.build_flags}
|
||||
|
||||
# NORMAL: 2048k version --------------------------
|
||||
[env:normal_WROOM02_2048]
|
||||
platform = ${common.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board = ${espWroom2M.board}
|
||||
board_flash_mode = ${espWroom2M.board_flash_mode}
|
||||
build_flags = ${espWroom2M.build_flags}
|
||||
|
||||
# NORMAL: 4096k version --------------------------
|
||||
[env:normal_ESP8266_4096]
|
||||
platform = ${common.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board = ${common.board}
|
||||
board_flash_mode = ${esp8266_4M.board_flash_mode}
|
||||
build_flags = ${esp8266_4M.build_flags}
|
||||
|
||||
|
||||
#version with additional plugins (and dependend code) that are in test-stadium 1024k
|
||||
|
||||
### TESTING ##############################################################################
|
||||
# additional plugins (and dependend code) that are in test-stadium #
|
||||
##########################################################################################
|
||||
|
||||
# TEST: 1024k version ----------------------------
|
||||
[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
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD_TESTING
|
||||
platform = ${testing.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board = ${common.board}
|
||||
board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
build_flags = ${esp8266_1M.build_flags} -D PLUGIN_BUILD_TESTING
|
||||
|
||||
#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
|
||||
# TEST: 1024k 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
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD_TESTING -DESP8285
|
||||
platform = ${testing.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board_flash_mode = ${esp8285_1M.board_flash_mode}
|
||||
board = ${esp8285_1M.board}
|
||||
build_flags = ${esp8285_1M.build_flags} -D PLUGIN_BUILD_TESTING
|
||||
|
||||
# TEST: 2048k version ----------------------------
|
||||
[env:test_WROOM02_2048]
|
||||
platform = ${testing.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board_flash_mode = ${espWroom2M.board_flash_mode}
|
||||
board = ${espWroom2M.board}
|
||||
build_flags = ${espWroom2M.build_flags} -D PLUGIN_BUILD_TESTING
|
||||
|
||||
# TEST: 4096k version ----------------------------
|
||||
[env:test_ESP8266_4096]
|
||||
platform = ${testing.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
board = ${common.board}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board_flash_mode = ${esp8266_4M.board_flash_mode}
|
||||
build_flags = ${esp8266_4M.build_flags} -D PLUGIN_BUILD_TESTING
|
||||
|
||||
# TEST: 4096k version + FEATURE_ADC_VCC ----------
|
||||
[env:test_ESP8266_4096_VCC]
|
||||
platform = ${testing.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
board = ${common.board}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board_flash_mode = ${esp8266_4M.board_flash_mode}
|
||||
build_flags = ${esp8266_4M.build_flags} -D PLUGIN_BUILD_TESTING -D FEATURE_ADC_VCC=true
|
||||
|
||||
|
||||
#version with additional plugins (and dependend code) that is in development (probably broken or incomplete) 1024k
|
||||
|
||||
### DEV ##################################################################################
|
||||
# additional plugins (and dependend code) that is in development (probably broken or incomplete)
|
||||
##########################################################################################
|
||||
|
||||
# DEV : 1024k version ----------------------------
|
||||
[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
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD_TESTING -D PLUGIN_BUILD_DEV
|
||||
platform = ${dev.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
board = ${common.board}
|
||||
build_flags = ${esp8266_1M.build_flags} -D PLUGIN_BUILD_DEV
|
||||
|
||||
#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
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.4m1m.ld -D PLUGIN_BUILD_TESTING -D PLUGIN_BUILD_DEV
|
||||
|
||||
#version with additional plugins (and dependend code) that is in development (probably broken or incomplete) 4096k for esp8285
|
||||
# DEV: 1024k 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
|
||||
platform = ${dev.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board_flash_mode = ${esp8285_1M.board_flash_mode}
|
||||
board = ${esp8285_1M.board}
|
||||
build_flags = ${esp8285_1M.build_flags} -D PLUGIN_BUILD_DEV
|
||||
|
||||
# DEV: 2048k version -----------------------------
|
||||
[env:dev_WROOM02_2048]
|
||||
platform = ${dev.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board_flash_mode = ${espWroom2M.board_flash_mode}
|
||||
board = ${espWroom2M.board}
|
||||
build_flags = ${espWroom2M.build_flags} -D PLUGIN_BUILD_DEV
|
||||
|
||||
# DEV : 4096k version ----------------------------
|
||||
[env:dev_ESP8266_4096]
|
||||
platform = ${dev.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
board = ${common.board}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board_flash_mode = ${esp8266_4M.board_flash_mode}
|
||||
build_flags = ${esp8266_4M.build_flags} -D PLUGIN_BUILD_DEV
|
||||
|
||||
|
||||
|
||||
#special patched version for PUYA flash chips, see https://github.com/letscontrolit/ESPEasy/issues/650
|
||||
### DEV + PUYA ###########################################################################
|
||||
# special patched version for PUYA flash chips, see issue #650 at Github #
|
||||
##########################################################################################
|
||||
|
||||
# DEV+PUYA : 1024k version -----------------------
|
||||
[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
|
||||
platform = ${dev.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
board = ${common.board}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
build_flags = ${esp8266_1M.build_flags} -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
|
||||
# DEV+PUYA : 1024k version + FEATURE_ADC_VCC -----
|
||||
[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
|
||||
platform = ${dev.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
board = ${common.board}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
build_flags = ${esp8266_1M.build_flags} -D PLUGIN_BUILD_DEV -D FLASH_QUIRK_WRITE_0_TO_1 -D FEATURE_ADC_VCC=true
|
||||
|
||||
|
||||
|
||||
|
||||
### HARDWARE SPECIFIC VERSIONS ###########################################################
|
||||
# versions specially designed to fit, and contents only needed plugins for each hardware #
|
||||
##########################################################################################
|
||||
|
||||
# ITEAD Products ################################
|
||||
|
||||
# ITEAD / SONOFF BASIC version ------------------
|
||||
#[env:hard_SONOFF_BASIC]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${Sonoff.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${Sonoff.board_flash_mode}
|
||||
#board = ${Sonoff.board}
|
||||
#build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_BASIC
|
||||
|
||||
# ITEAD / SONOFF TH10 version -------------------
|
||||
#[env:hard_SONOFF_TH10]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${Sonoff.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${Sonoff.board_flash_mode}
|
||||
#board = ${Sonoff.board}
|
||||
#build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_TH10
|
||||
|
||||
# ITEAD / SONOFF TH16 version -------------------
|
||||
#[env:hard_SONOFF_TH16]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${Sonoff.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${Sonoff.board_flash_mode}
|
||||
#board = ${Sonoff.board}
|
||||
#build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_TH16
|
||||
|
||||
# ITEAD / SONOFF POW version --------------------
|
||||
# Sonoff Pow (ESP8266 - HLW8012)
|
||||
# GPIO00 Button
|
||||
# GPIO05 HLW8012 Sel output
|
||||
# GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||
# GPIO13 HLW8012 CF1 voltage / current
|
||||
# GPIO14 HLW8012 CF power
|
||||
# GPIO15 Blue Led (0 = On, 1 = Off)
|
||||
[env:hard_SONOFF_POW]
|
||||
upload_speed = ${common.upload_speed}
|
||||
framework = ${common.framework}
|
||||
platform = ${Sonoff.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
board_flash_mode = ${Sonoff.board_flash_mode}
|
||||
board = ${Sonoff.board}
|
||||
build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_POW
|
||||
|
||||
# Sonoff Pow R2 (ESP8285 - CSE7766)
|
||||
# GPIO00 Button
|
||||
# GPIO01 Serial RXD 4800 baud 8E1 CSE7766 energy sensor
|
||||
# GPIO03 Serial TXD
|
||||
# GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||
# GPIO13 Blue Led (0 = On, 1 = Off)
|
||||
#[env:hard_SONOFF_POW_R2]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${Sonoff.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${Sonoff_8285.board_flash_mode}
|
||||
#board = ${Sonoff_8285.board}
|
||||
#build_flags = ${Sonoff_8285.build_flags} -D PLUGIN_SET_SONOFF_POW_R2
|
||||
|
||||
# ITEAD / SONOFF S20 version --------------------
|
||||
#[env:hard_SONOFF_S20]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${Sonoff.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${Sonoff.board_flash_mode}
|
||||
#board = ${Sonoff.board}
|
||||
#build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_S20
|
||||
|
||||
# ITEAD / SONOFF 4CH version --------------------
|
||||
#[env:hard_SONOFF_4CH]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${Sonoff.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${Sonoff.board_flash_mode}
|
||||
#board = ${Sonoff.board}
|
||||
#build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_4CH
|
||||
|
||||
# ITEAD / SONOFF TOUCH version ------------------
|
||||
#[env:hard_SONOFF_TOUCH]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${Sonoff.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${Sonoff.board_flash_mode}
|
||||
#board = ${Sonoff.board}
|
||||
#build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_TOUCH
|
||||
|
||||
|
||||
|
||||
# LED Strips #####################################
|
||||
|
||||
# Huacanxing / H801 ------------------------------
|
||||
#[env:hard_HUACANXING_H801]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${common.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
#board = esp01_1m
|
||||
#build_flags = ${esp8266_1M.build_flags} -D PLUGIN_SET_H801
|
||||
|
||||
# MagicHome / Led Controller ---------------------
|
||||
#[env:hard_MAGICHOME]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${common.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
#board = esp01_1m
|
||||
#build_flags = ${esp8266_1M.build_flags} -D PLUGIN_SET_MAGICHOME
|
||||
|
||||
# MagicHome / Led Controller with IR -------------
|
||||
#[env:hard_MAGICHOME_IR]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${common.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
#board = esp01_1m
|
||||
#build_flags = ${esp8266_1M.build_flags} -D PLUGIN_SET_MAGICHOME_IR
|
||||
|
||||
|
||||
|
||||
|
||||
### EASY VERSIONS ########################################################################
|
||||
# versions specially designed to be small and cover a specific usage #
|
||||
##########################################################################################
|
||||
|
||||
# Easy Temperature Sensor ------------------------
|
||||
#[env:easy_TEMP]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${common.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
#board = esp01_1m
|
||||
#build_flags = ${esp8266_1M.build_flags} -D PLUGIN_SET_EASY_TEMP
|
||||
|
||||
|
||||
# Easy Carbon Sensor -----------------------------
|
||||
#[env:easy_CARBON]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${common.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
#board = esp01_1m
|
||||
#build_flags = ${esp8266_1M.build_flags} -D PLUGIN_SET_EASY_CARBON
|
||||
|
||||
## Easy Nextion ----------------------------------
|
||||
##PLUGIN_SET_EASY_NEXTION
|
||||
|
||||
# Easy OLED Display v1 ---------------------------
|
||||
#[env:easy_OLED_V1]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${common.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
#board = esp01_1m
|
||||
#build_flags = ${esp8266_1M.build_flags} -D PLUGIN_SET_EASY_OLED1
|
||||
|
||||
# Easy OLED Display v2 ---------------------------
|
||||
#[env:easy_OLED_V2]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${common.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
#board = esp01_1m
|
||||
#build_flags = ${esp8266_1M.build_flags} -D PLUGIN_SET_EASY_OLED2
|
||||
|
||||
# Easy Relay Switch ------------------------------
|
||||
#[env:easy_OLED_V2]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${common.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
#board = esp01_1m
|
||||
#build_flags = ${esp8266_1M.build_flags} -D PLUGIN_SET_EASY_RELAY
|
||||
|
||||
# Easy Generic (1M) device ----------------------
|
||||
#[env:easy_GENERIC_1M]
|
||||
#upload_speed = ${common.upload_speed}
|
||||
#framework = ${common.framework}
|
||||
#platform = ${common.platform}
|
||||
#lib_deps = ${common.lib_deps}
|
||||
#lib_ignore = ${common.lib_ignore}
|
||||
#lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
#board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
#board = esp01_1m
|
||||
#build_flags = ${esp8266_1M.build_flags} -D PLUGIN_SET_GENERIC_1M
|
||||
|
||||
# Ventus W266 weather station
|
||||
# https://www.letscontrolit.com/wiki/index.php/VentusW266
|
||||
[env:hard_Ventus_W266]
|
||||
platform = ${normal.platform}
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
lib_ldf_mode = ${common.lib_ldf_mode}
|
||||
framework = ${common.framework}
|
||||
upload_speed = ${common.upload_speed}
|
||||
board_flash_mode = ${esp8266_1M.board_flash_mode}
|
||||
board = ${common.board}
|
||||
build_flags = ${esp8266_1M.build_flags} -D PLUGIN_SET_VENTUS_W266
|
||||
|
||||
@@ -29,7 +29,7 @@ cat "$NOTES" >> "$NOTES.new"
|
||||
mv "$NOTES.new" "$NOTES"
|
||||
|
||||
git add "$NOTES"
|
||||
git commit -m "automaticly updated release notes for $NEW"
|
||||
git commit -m "automatically updated release notes for $NEW"
|
||||
|
||||
|
||||
################ tag and add tag message
|
||||
|
||||
+464
-164
@@ -38,30 +38,155 @@ bool safeReadStringUntil(Stream &input, String &str, char terminator, unsigned i
|
||||
|
||||
}
|
||||
|
||||
|
||||
#define INPUT_COMMAND_SIZE 80
|
||||
Command commandStringToEnum(const char * cmd) {
|
||||
String tmpcmd;
|
||||
tmpcmd = cmd;
|
||||
tmpcmd.toLowerCase();
|
||||
String log = F("Command: ");
|
||||
log += tmpcmd;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
char cmd_lc[INPUT_COMMAND_SIZE];
|
||||
tmpcmd.toCharArray(cmd_lc, tmpcmd.length() + 1);
|
||||
switch (cmd_lc[0]) {
|
||||
case 'a': {
|
||||
if (strcmp_P(cmd_lc, PSTR("accessinfo") ) == 0) return cmd_accessinfo;
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
if (strcmp_P(cmd_lc, PSTR("background") ) == 0) return cmd_background;
|
||||
else if (strcmp_P(cmd_lc, PSTR("blynkget") ) == 0) return cmd_BlynkGet;
|
||||
else if (strcmp_P(cmd_lc, PSTR("build") ) == 0) return cmd_build;
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
if (strcmp_P(cmd_lc, PSTR("clearaccessblock") ) == 0) return cmd_clearaccessblock;
|
||||
else if (strcmp_P(cmd_lc, PSTR("clearrtcram") ) == 0) return cmd_clearRTCRAM;
|
||||
else if (strcmp_P(cmd_lc, PSTR("config") ) == 0) return cmd_config;
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
if (strcmp_P(cmd_lc, PSTR("debug") ) == 0) return cmd_Debug;
|
||||
else if (strcmp_P(cmd_lc, PSTR("delay") ) == 0) return cmd_Delay;
|
||||
else if (strcmp_P(cmd_lc, PSTR("deepsleep") ) == 0) return cmd_deepSleep;
|
||||
break;
|
||||
}
|
||||
case 'e': {
|
||||
if (strcmp_P(cmd_lc, PSTR("erase") ) == 0) return cmd_Erase;
|
||||
else if (strcmp_P(cmd_lc, PSTR("event") ) == 0) return cmd_Event;
|
||||
else if (strcmp_P(cmd_lc, PSTR("executerules") ) == 0) return cmd_executeRules;
|
||||
break;
|
||||
}
|
||||
case 'i': {
|
||||
if (strcmp_P(cmd_lc, PSTR("i2cscanner") ) == 0) return cmd_i2cscanner;
|
||||
else if (strcmp_P(cmd_lc, PSTR("ip") ) == 0) return cmd_IP;
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
if (strcmp_P(cmd_lc, PSTR("load") ) == 0) return cmd_Load;
|
||||
else if (strcmp_P(cmd_lc, PSTR("logentry") ) == 0) return cmd_logentry;
|
||||
else if (strcmp_P(cmd_lc, PSTR("lowmem") ) == 0) return cmd_lowmem;
|
||||
break;
|
||||
}
|
||||
case 'm': {
|
||||
if (strcmp_P(cmd_lc, PSTR("malloc") ) == 0) return cmd_malloc;
|
||||
else if (strcmp_P(cmd_lc, PSTR("meminfo") ) == 0) return cmd_meminfo;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
if (strcmp_P(cmd_lc, PSTR("name") ) == 0) return cmd_Name;
|
||||
else if (strcmp_P(cmd_lc, PSTR("notify") ) == 0) return cmd_notify;
|
||||
else if (strcmp_P(cmd_lc, PSTR("nosleep") ) == 0) return cmd_NoSleep;
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
if (strcmp_P(cmd_lc, PSTR("password") ) == 0) return cmd_Password;
|
||||
else if (strcmp_P(cmd_lc, PSTR("publish") ) == 0) return cmd_Publish;
|
||||
break;
|
||||
}
|
||||
case 'r': {
|
||||
if (strcmp_P(cmd_lc, PSTR("reboot") ) == 0) return cmd_Reboot;
|
||||
else if (strcmp_P(cmd_lc, PSTR("reset") ) == 0) return cmd_Reset;
|
||||
else if (strcmp_P(cmd_lc, PSTR("restart") ) == 0) return cmd_Restart;
|
||||
else if (strcmp_P(cmd_lc, PSTR("resetflashwritecounter")) == 0) return cmd_resetFlashWriteCounter;
|
||||
else if (strcmp_P(cmd_lc, PSTR("rules") ) == 0) return cmd_Rules;
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
if (strcmp_P(cmd_lc, PSTR("sdcard") ) == 0) return cmd_sdcard;
|
||||
else if (strcmp_P(cmd_lc, PSTR("sdremove") ) == 0) return cmd_sdremove;
|
||||
else if (strcmp_P(cmd_lc, PSTR("sysload") ) == 0) return cmd_sysload;
|
||||
else if (strcmp_P(cmd_lc, PSTR("save") ) == 0) return cmd_Save;
|
||||
else if (strcmp_P(cmd_lc, PSTR("sendto") ) == 0) return cmd_SendTo;
|
||||
else if (strcmp_P(cmd_lc, PSTR("sendtohttp") ) == 0) return cmd_SendToHTTP;
|
||||
else if (strcmp_P(cmd_lc, PSTR("sendtoudp") ) == 0) return cmd_SendToUDP;
|
||||
else if (strcmp_P(cmd_lc, PSTR("serialfloat") ) == 0) return cmd_SerialFloat;
|
||||
else if (strcmp_P(cmd_lc, PSTR("settings") ) == 0) return cmd_Settings;
|
||||
break;
|
||||
}
|
||||
case 't': {
|
||||
if (strcmp_P(cmd_lc, PSTR("taskclear") ) == 0) return cmd_TaskClear;
|
||||
else if (strcmp_P(cmd_lc, PSTR("taskclearall") ) == 0) return cmd_TaskClearAll;
|
||||
else if (strcmp_P(cmd_lc, PSTR("taskrun") ) == 0) return cmd_TaskRun;
|
||||
else if (strcmp_P(cmd_lc, PSTR("taskvalueset") ) == 0) return cmd_TaskValueSet;
|
||||
else if (strcmp_P(cmd_lc, PSTR("taskvaluesetandrun") ) == 0) return cmd_TaskValueSetAndRun;
|
||||
else if (strcmp_P(cmd_lc, PSTR("timerset") ) == 0) return cmd_TimerSet;
|
||||
else if (strcmp_P(cmd_lc, PSTR("timerpause") ) == 0) return cmd_TimerPause;
|
||||
else if (strcmp_P(cmd_lc, PSTR("timerresume") ) == 0) return cmd_TimerResume;
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
if (strcmp_P(cmd_lc, PSTR("udptest") ) == 0) return cmd_udptest;
|
||||
else if (strcmp_P(cmd_lc, PSTR("unit") ) == 0) return cmd_Unit;
|
||||
break;
|
||||
}
|
||||
case 'w': {
|
||||
if (strcmp_P(cmd_lc, PSTR("wdconfig") ) == 0) return cmd_wdconfig;
|
||||
else if (strcmp_P(cmd_lc, PSTR("wdread") ) == 0) return cmd_wdread;
|
||||
else if (strcmp_P(cmd_lc, PSTR("wifiapmode") ) == 0) return cmd_WifiAPMode;
|
||||
else if (strcmp_P(cmd_lc, PSTR("wificonnect") ) == 0) return cmd_WifiConnect;
|
||||
else if (strcmp_P(cmd_lc, PSTR("wifidisconnect") ) == 0) return cmd_WifiDisconnect;
|
||||
else if (strcmp_P(cmd_lc, PSTR("wifikey2") ) == 0) return cmd_WifiKey2;
|
||||
else if (strcmp_P(cmd_lc, PSTR("wifikey") ) == 0) return cmd_WifiKey;
|
||||
else if (strcmp_P(cmd_lc, PSTR("wifissid2") ) == 0) return cmd_WifiSSID2;
|
||||
else if (strcmp_P(cmd_lc, PSTR("wifissid") ) == 0) return cmd_WifiSSID;
|
||||
else if (strcmp_P(cmd_lc, PSTR("wifiscan") ) == 0) return cmd_WifiScan;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
addLog(LOG_LEVEL_INFO, F("Command unknown"));
|
||||
return cmd_Unknown;
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, F("Command unknown"));
|
||||
return cmd_Unknown;
|
||||
}
|
||||
|
||||
void ExecuteCommand(byte source, const char *Line)
|
||||
{
|
||||
checkRAM(F("ExecuteCommand"));
|
||||
String status = "";
|
||||
boolean success = false;
|
||||
char TmpStr1[80];
|
||||
char TmpStr1[INPUT_COMMAND_SIZE];
|
||||
TmpStr1[0] = 0;
|
||||
char Command[80];
|
||||
Command[0] = 0;
|
||||
char cmd[INPUT_COMMAND_SIZE];
|
||||
cmd[0] = 0;
|
||||
int Par1 = 0;
|
||||
int Par2 = 0;
|
||||
int Par3 = 0;
|
||||
|
||||
GetArgv(Line, Command, 1);
|
||||
GetArgv(Line, cmd, 1);
|
||||
if (GetArgv(Line, TmpStr1, 2)) Par1 = str2int(TmpStr1);
|
||||
if (GetArgv(Line, TmpStr1, 3)) Par2 = str2int(TmpStr1);
|
||||
if (GetArgv(Line, TmpStr1, 4)) Par3 = str2int(TmpStr1);
|
||||
|
||||
const Command cmd_enum = commandStringToEnum(cmd);
|
||||
switch (cmd_enum) {
|
||||
|
||||
// ****************************************
|
||||
// commands for debugging
|
||||
// ****************************************
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("background")) == 0)
|
||||
case cmd_background:
|
||||
{
|
||||
success = true;
|
||||
unsigned long timer = millis() + Par1;
|
||||
@@ -69,9 +194,10 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
while (!timeOutReached(timer))
|
||||
backgroundtasks();
|
||||
Serial.println("end");
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("executeRules")) == 0)
|
||||
case cmd_executeRules:
|
||||
{
|
||||
success = true;
|
||||
if (GetArgv(Line, TmpStr1, 2))
|
||||
@@ -80,15 +206,17 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
String event = "";
|
||||
rulesProcessingFile(fileName, event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("clearRTCRAM")) == 0)
|
||||
case cmd_clearRTCRAM:
|
||||
{
|
||||
success = true;
|
||||
initRTC();
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("notify")) == 0)
|
||||
case cmd_notify:
|
||||
{
|
||||
success = true;
|
||||
String message = "";
|
||||
@@ -109,15 +237,17 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("resetFlashWriteCounter")) == 0)
|
||||
case cmd_resetFlashWriteCounter:
|
||||
{
|
||||
success = true;
|
||||
RTC.flashDayCounter = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("udptest")) == 0)
|
||||
case cmd_udptest:
|
||||
{
|
||||
success = true;
|
||||
for (byte x = 0; x < Par2; x++)
|
||||
@@ -126,18 +256,20 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
event += x;
|
||||
SendUDPCommand(Par1, (char*)event.c_str(), event.length());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("sdcard")) == 0)
|
||||
#ifdef FEATURE_SD
|
||||
case cmd_sdcard:
|
||||
{
|
||||
success = true;
|
||||
File root = SD.open("/");
|
||||
root.rewindDirectory();
|
||||
printDirectory(root, 0);
|
||||
root.close();
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("sdremove")) == 0)
|
||||
case cmd_sdremove:
|
||||
{
|
||||
success = true;
|
||||
String fname = Line;
|
||||
@@ -145,40 +277,63 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
Serial.print(F("Removing:"));
|
||||
Serial.println(fname.c_str());
|
||||
SD.remove((char*)fname.c_str());
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("lowmem")) == 0)
|
||||
case cmd_lowmem:
|
||||
{
|
||||
Serial.print(lowestRAM);
|
||||
Serial.print(F(" : "));
|
||||
Serial.println(lowestRAMfunction);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("malloc")) == 0)
|
||||
case cmd_malloc:
|
||||
{
|
||||
ramtest = (char *)malloc(Par1);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("sysload")) == 0)
|
||||
case cmd_sysload:
|
||||
{
|
||||
success = true;
|
||||
Serial.print(100 - (100 * loopCounterLast / loopCounterMax));
|
||||
Serial.print(F("% (LC="));
|
||||
Serial.print(int(loopCounterLast / 30));
|
||||
Serial.println(F(")"));
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("SerialFloat")) == 0)
|
||||
case cmd_SerialFloat:
|
||||
{
|
||||
success = true;
|
||||
pinMode(1, INPUT);
|
||||
pinMode(3, INPUT);
|
||||
delay(60000);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("meminfo")) == 0)
|
||||
case cmd_accessinfo:
|
||||
{
|
||||
success = true;
|
||||
Serial.print(F("Allowed IP range : "));
|
||||
Serial.println(describeAllowedIPrange());
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_clearaccessblock:
|
||||
{
|
||||
success = true;
|
||||
clearAccessBlock();
|
||||
Serial.print(F("Allowed IP range : "));
|
||||
Serial.println(describeAllowedIPrange());
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_meminfo:
|
||||
{
|
||||
success = true;
|
||||
Serial.print(F("SecurityStruct : "));
|
||||
@@ -189,32 +344,36 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
Serial.println(sizeof(ExtraTaskSettings));
|
||||
Serial.print(F("DeviceStruct: "));
|
||||
Serial.println(sizeof(Device));
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("TaskClear")) == 0)
|
||||
case cmd_TaskClear:
|
||||
{
|
||||
success = true;
|
||||
taskClear(Par1 - 1, true);
|
||||
break;
|
||||
}
|
||||
|
||||
//quickly clear all tasks, without saving (used by test suite)
|
||||
if (strcasecmp_P(Command, PSTR("TaskClearAll")) == 0)
|
||||
case cmd_TaskClearAll:
|
||||
{
|
||||
success = true;
|
||||
for (byte t=0; t<TASKS_MAX; t++)
|
||||
taskClear(t, false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("wdconfig")) == 0)
|
||||
case cmd_wdconfig:
|
||||
{
|
||||
success = true;
|
||||
Wire.beginTransmission(Par1); // address
|
||||
Wire.write(Par2); // command
|
||||
Wire.write(Par3); // data
|
||||
Wire.endTransmission();
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("wdread")) == 0)
|
||||
case cmd_wdread:
|
||||
{
|
||||
success = true;
|
||||
Wire.beginTransmission(Par1); // address
|
||||
@@ -228,22 +387,25 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
status = F("Reg value: ");
|
||||
status += value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("build")) == 0)
|
||||
case cmd_build:
|
||||
{
|
||||
success = true;
|
||||
Settings.Build = Par1;
|
||||
SaveSettings();
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("NoSleep")) == 0)
|
||||
case cmd_NoSleep:
|
||||
{
|
||||
success = true;
|
||||
Settings.deepSleep = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("i2cscanner")) == 0)
|
||||
case cmd_i2cscanner:
|
||||
{
|
||||
success = true;
|
||||
|
||||
@@ -263,28 +425,31 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
Serial.println(String(address, HEX));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
// commands for rules
|
||||
// ****************************************
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("config")) == 0)
|
||||
case cmd_config:
|
||||
{
|
||||
success = true;
|
||||
struct EventStruct TempEvent;
|
||||
String request = Line;
|
||||
remoteConfig(&TempEvent, request);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("deepSleep")) == 0)
|
||||
case cmd_deepSleep:
|
||||
{
|
||||
success = true;
|
||||
if (Par1 > 0)
|
||||
deepSleepStart(Par1); // call the second part of the function to avoid check and enable one-shot operation
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("TaskValueSet")) == 0)
|
||||
case cmd_TaskValueSet:
|
||||
{
|
||||
success = true;
|
||||
if (GetArgv(Line, TmpStr1, 4))
|
||||
@@ -293,48 +458,141 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
Calculate(TmpStr1, &result);
|
||||
UserVar[(VARS_PER_TASK * (Par1 - 1)) + Par2 - 1] = result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("TaskRun")) == 0)
|
||||
case cmd_TaskValueSetAndRun:
|
||||
{
|
||||
success = true;
|
||||
if (GetArgv(Line, TmpStr1, 4))
|
||||
{
|
||||
float result = 0;
|
||||
Calculate(TmpStr1, &result);
|
||||
UserVar[(VARS_PER_TASK * (Par1 - 1)) + Par2 - 1] = result;
|
||||
SensorSendTask(Par1 - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// it does nothing, just print on the log (INFO) the content of the line in the rule:
|
||||
// log example of command: logentry,S=[task#value] T=[task1#value]:
|
||||
// ACT : logentry,S=24 T=23.1
|
||||
// Command: logentry
|
||||
case cmd_logentry:
|
||||
{
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_TaskRun:
|
||||
{
|
||||
success = true;
|
||||
SensorSendTask(Par1 - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("TimerSet")) == 0)
|
||||
case cmd_TimerSet:
|
||||
{
|
||||
if (Par1>=1 && Par1<=RULES_TIMER_MAX)
|
||||
{
|
||||
success = true;
|
||||
if (Par2)
|
||||
{
|
||||
//start new timer
|
||||
RulesTimer[Par1 - 1] = millis() + (1000 * Par2);
|
||||
RulesTimer[Par1 - 1].interval = Par2*1000;
|
||||
RulesTimer[Par1 - 1].paused = false;
|
||||
RulesTimer[Par1 - 1].timestamp = millis() + (1000 * Par2);
|
||||
}
|
||||
else
|
||||
{
|
||||
//disable existing timer
|
||||
RulesTimer[Par1 - 1] = 0L;
|
||||
RulesTimer[Par1 - 1].interval = 0;
|
||||
RulesTimer[Par1 - 1].paused = false;
|
||||
RulesTimer[Par1 - 1].timestamp = 0L;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F("TIMER: invalid timer number"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Delay")) == 0)
|
||||
case cmd_TimerPause:
|
||||
{
|
||||
if (Par1>=1 && Par1<=RULES_TIMER_MAX)
|
||||
{
|
||||
success = true;
|
||||
if (RulesTimer[Par1 - 1].paused == false)
|
||||
{
|
||||
long delta = timePassedSince(RulesTimer[Par1 - 1].timestamp);
|
||||
if(RulesTimer[Par1 - 1].timestamp != 0L && delta < 0)
|
||||
{
|
||||
String event = F("Rules#TimerPause=");
|
||||
event += Par1;
|
||||
rulesProcessing(event);
|
||||
RulesTimer[Par1 - 1].paused = true;
|
||||
RulesTimer[Par1 - 1].interval = -delta; // set remaind time
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
addLog(LOG_LEVEL_INFO, F("TIMER: already paused"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F("TIMER: invalid timer number"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_TimerResume:
|
||||
{
|
||||
if (Par1>=1 && Par1<=RULES_TIMER_MAX)
|
||||
{
|
||||
success = true;
|
||||
if (RulesTimer[Par1 - 1].paused == true)
|
||||
{
|
||||
if(RulesTimer[Par1 - 1].interval > 0 && RulesTimer[Par1 - 1].timestamp != 0L)
|
||||
{
|
||||
String event = F("Rules#TimerResume=");
|
||||
event += Par1;
|
||||
rulesProcessing(event);
|
||||
RulesTimer[Par1 - 1].timestamp = millis() + (RulesTimer[Par1 - 1].interval);
|
||||
RulesTimer[Par1 - 1].paused = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
addLog(LOG_LEVEL_INFO, F("TIMER: already resumed"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F("TIMER: invalid timer number"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_Delay:
|
||||
{
|
||||
success = true;
|
||||
delayBackground(Par1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Rules")) == 0)
|
||||
case cmd_Rules:
|
||||
{
|
||||
success = true;
|
||||
if (Par1 == 1)
|
||||
Settings.UseRules = true;
|
||||
else
|
||||
Settings.UseRules = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Event")) == 0)
|
||||
case cmd_Event:
|
||||
{
|
||||
success = true;
|
||||
String event = Line;
|
||||
@@ -342,9 +600,10 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
event.replace("$", "#");
|
||||
if (Settings.UseRules)
|
||||
rulesProcessing(event);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("SendTo")) == 0)
|
||||
case cmd_SendTo:
|
||||
{
|
||||
success = true;
|
||||
String event = Line;
|
||||
@@ -355,210 +614,241 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
event = event.substring(index + 1);
|
||||
SendUDPCommand(Par1, (char*)event.c_str(), event.length());
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (strcasecmp_P(Command, PSTR("Publish")) == 0 && WiFi.status() == WL_CONNECTED)
|
||||
case cmd_Publish:
|
||||
{
|
||||
// ToDo TD-er: Not sure about this function, but at least it sends to an existing MQTTclient
|
||||
int enabledMqttController = firstEnabledMQTTController();
|
||||
if (enabledMqttController >= 0) {
|
||||
if (wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
// ToDo TD-er: Not sure about this function, but at least it sends to an existing MQTTclient
|
||||
int enabledMqttController = firstEnabledMQTTController();
|
||||
if (enabledMqttController >= 0) {
|
||||
success = true;
|
||||
String event = Line;
|
||||
event = event.substring(8);
|
||||
int index = event.indexOf(',');
|
||||
if (index > 0)
|
||||
{
|
||||
String topic = event.substring(0, index);
|
||||
String value = event.substring(index + 1);
|
||||
MQTTpublish(enabledMqttController, topic.c_str(), value.c_str(), Settings.MQTTRetainFlag);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_SendToUDP:
|
||||
{
|
||||
if (wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
success = true;
|
||||
String event = Line;
|
||||
event = event.substring(8);
|
||||
int index = event.indexOf(',');
|
||||
String strLine = Line;
|
||||
String ip = parseString(strLine, 2);
|
||||
String port = parseString(strLine, 3);
|
||||
int msgpos = getParamStartPos(strLine, 4);
|
||||
String message = strLine.substring(msgpos);
|
||||
IPAddress UDP_IP;
|
||||
if(UDP_IP.fromString(ip)) {
|
||||
portUDP.beginPacket(UDP_IP, port.toInt());
|
||||
#if defined(ESP8266)
|
||||
portUDP.write(message.c_str(), message.length());
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
portUDP.write((uint8_t*)message.c_str(), message.length());
|
||||
#endif
|
||||
portUDP.endPacket();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_SendToHTTP:
|
||||
{
|
||||
if (wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
success = true;
|
||||
String strLine = Line;
|
||||
String host = parseString(strLine, 2);
|
||||
String port = parseString(strLine, 3);
|
||||
int pathpos = getParamStartPos(strLine, 4);
|
||||
String path = strLine.substring(pathpos);
|
||||
WiFiClient client;
|
||||
if (client.connect(host.c_str(), port.toInt()))
|
||||
{
|
||||
client.print(String("GET ") + path + " HTTP/1.1\r\n" +
|
||||
"Host: " + host + "\r\n" +
|
||||
"Connection: close\r\n\r\n");
|
||||
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client.available() && !timeOutReached(timer))
|
||||
delay(1);
|
||||
|
||||
while (client.available()) {
|
||||
// String line = client.readStringUntil('\n');
|
||||
String line;
|
||||
safeReadStringUntil(client, line, '\n');
|
||||
|
||||
|
||||
if (line.substring(0, 15) == F("HTTP/1.1 200 OK"))
|
||||
addLog(LOG_LEVEL_DEBUG, line);
|
||||
delay(1);
|
||||
}
|
||||
client.flush();
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
// special commands for Blynk
|
||||
// ****************************************
|
||||
|
||||
#ifdef CPLUGIN_012
|
||||
//FIXME: this should go to PLUGIN_WRITE in _C012.ino
|
||||
case cmd_BlynkGet:
|
||||
{
|
||||
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)
|
||||
{
|
||||
String topic = event.substring(0, index);
|
||||
String value = event.substring(index + 1);
|
||||
MQTTpublish(enabledMqttController, topic.c_str(), value.c_str(), Settings.MQTTRetainFlag);
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("SendToUDP")) == 0 && WiFi.status() == WL_CONNECTED)
|
||||
{
|
||||
success = true;
|
||||
String strLine = Line;
|
||||
String ip = parseString(strLine, 2);
|
||||
String port = parseString(strLine, 3);
|
||||
int msgpos = getParamStartPos(strLine, 4);
|
||||
String message = strLine.substring(msgpos);
|
||||
IPAddress UDP_IP;
|
||||
if(UDP_IP.fromString(ip)) {
|
||||
portUDP.beginPacket(UDP_IP, port.toInt());
|
||||
#if defined(ESP8266)
|
||||
portUDP.write(message.c_str(), message.length());
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
portUDP.write((uint8_t*)message.c_str(), message.length());
|
||||
#endif
|
||||
portUDP.endPacket();
|
||||
}
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("SendToHTTP")) == 0 && WiFi.status() == WL_CONNECTED)
|
||||
{
|
||||
success = true;
|
||||
String strLine = Line;
|
||||
String host = parseString(strLine, 2);
|
||||
String port = parseString(strLine, 3);
|
||||
int pathpos = getParamStartPos(strLine, 4);
|
||||
String path = strLine.substring(pathpos);
|
||||
WiFiClient client;
|
||||
if (client.connect(host.c_str(), port.toInt()))
|
||||
{
|
||||
client.print(String("GET ") + path + " HTTP/1.1\r\n" +
|
||||
"Host: " + host + "\r\n" +
|
||||
"Connection: close\r\n\r\n");
|
||||
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client.available() && !timeOutReached(timer))
|
||||
delay(1);
|
||||
|
||||
while (client.available()) {
|
||||
// String line = client.readStringUntil('\n');
|
||||
String line;
|
||||
safeReadStringUntil(client, line, '\n');
|
||||
|
||||
|
||||
if (line.substring(0, 15) == F("HTTP/1.1 200 OK"))
|
||||
addLog(LOG_LEVEL_DEBUG, line);
|
||||
delay(1);
|
||||
}
|
||||
client.flush();
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
// 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
|
||||
// ****************************************
|
||||
if (strcasecmp_P(Command, PSTR("WifiSSID")) == 0)
|
||||
case cmd_WifiSSID:
|
||||
{
|
||||
success = true;
|
||||
strcpy(SecuritySettings.WifiSSID, Line + 9);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("WifiKey")) == 0)
|
||||
case cmd_WifiKey:
|
||||
{
|
||||
success = true;
|
||||
strcpy(SecuritySettings.WifiKey, Line + 8);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("WifiSSID2")) == 0)
|
||||
case cmd_WifiSSID2:
|
||||
{
|
||||
success = true;
|
||||
strcpy(SecuritySettings.WifiSSID2, Line + 10);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("WifiKey2")) == 0)
|
||||
case cmd_WifiKey2:
|
||||
{
|
||||
success = true;
|
||||
strcpy(SecuritySettings.WifiKey2, Line + 9);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("WifiScan")) == 0)
|
||||
case cmd_WifiScan:
|
||||
{
|
||||
success = true;
|
||||
WifiScan();
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("WifiConnect")) == 0)
|
||||
case cmd_WifiConnect:
|
||||
{
|
||||
success = true;
|
||||
WifiConnect(1);
|
||||
WiFiConnectRelaxed();
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("WifiDisconnect")) == 0)
|
||||
case cmd_WifiDisconnect:
|
||||
{
|
||||
success = true;
|
||||
WifiDisconnect();
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("WifiAPMode")) == 0)
|
||||
case cmd_WifiAPMode:
|
||||
{
|
||||
WifiAPMode(true);
|
||||
setAP(true);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Unit")) == 0)
|
||||
case cmd_Unit:
|
||||
{
|
||||
success = true;
|
||||
Settings.Unit=Par1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Name")) == 0)
|
||||
case cmd_Name:
|
||||
{
|
||||
success = true;
|
||||
strcpy(Settings.Name, Line + 5);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Password")) == 0)
|
||||
case cmd_Password:
|
||||
{
|
||||
success = true;
|
||||
strcpy(SecuritySettings.Password, Line + 9);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Reboot")) == 0)
|
||||
case cmd_Reboot:
|
||||
{
|
||||
success = true;
|
||||
pinMode(0, INPUT);
|
||||
pinMode(2, INPUT);
|
||||
pinMode(15, INPUT);
|
||||
ESP.reset();
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
ESP.restart();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Restart")) == 0)
|
||||
case cmd_Restart:
|
||||
{
|
||||
success = true;
|
||||
ESP.restart();
|
||||
break;
|
||||
}
|
||||
if (strcasecmp_P(Command, PSTR("Erase")) == 0)
|
||||
|
||||
case cmd_Erase:
|
||||
{
|
||||
success = true;
|
||||
WiFi.persistent(true); // use SDK storage of SSID/WPA parameters
|
||||
WiFi.disconnect(); // this will store empty ssid/wpa into sdk storage
|
||||
WifiDisconnect(); // this will store empty ssid/wpa into sdk storage
|
||||
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Reset")) == 0)
|
||||
case cmd_Reset:
|
||||
{
|
||||
success = true;
|
||||
ResetFactory();
|
||||
@@ -568,37 +858,41 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
#if defined(ESP32)
|
||||
ESP.restart();
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Save")) == 0)
|
||||
case cmd_Save:
|
||||
{
|
||||
success = true;
|
||||
SaveSettings();
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Load")) == 0)
|
||||
case cmd_Load:
|
||||
{
|
||||
success = true;
|
||||
LoadSettings();
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Debug")) == 0)
|
||||
case cmd_Debug:
|
||||
{
|
||||
success = true;
|
||||
Settings.SerialLogLevel = Par1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("IP")) == 0)
|
||||
case cmd_IP:
|
||||
{
|
||||
success = true;
|
||||
if (GetArgv(Line, TmpStr1, 2)) {
|
||||
if (!str2ip(TmpStr1, Settings.IP))
|
||||
Serial.println("?");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Settings")) == 0)
|
||||
case cmd_Settings:
|
||||
{
|
||||
success = true;
|
||||
char str[20];
|
||||
@@ -616,6 +910,10 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
Serial.print(F(" WifiSSID2 : ")); Serial.println(SecuritySettings.WifiSSID2);
|
||||
Serial.print(F(" WifiKey2 : ")); Serial.println(SecuritySettings.WifiKey2);
|
||||
Serial.print(F(" Free mem : ")); Serial.println(FreeMem());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
success = false;
|
||||
}
|
||||
|
||||
yield();
|
||||
@@ -628,6 +926,7 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
yield();
|
||||
}
|
||||
|
||||
#ifdef FEATURE_SD
|
||||
void printDirectory(File dir, int numTabs) {
|
||||
while (true) {
|
||||
|
||||
@@ -651,3 +950,4 @@ void printDirectory(File dir, int numTabs) {
|
||||
entry.close();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+20
-12
@@ -3,7 +3,8 @@
|
||||
//********************************************************************************
|
||||
void sendData(struct EventStruct *event)
|
||||
{
|
||||
LoadTaskSettings(event->TaskIndex);
|
||||
checkRAM(F("sendData"));
|
||||
LoadTaskSettings(event->TaskIndex);
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(event->TaskIndex);
|
||||
|
||||
@@ -88,14 +89,16 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
|
||||
strncpy(c_payload,(char*)b_payload,length);
|
||||
c_payload[length] = 0;
|
||||
|
||||
/*
|
||||
String log;
|
||||
log=F("MQTT : Topic: ");
|
||||
log+=c_topic;
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
log=F("MQTT : Payload: ");
|
||||
log+=c_payload;
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
*/
|
||||
|
||||
// sprintf_P(log, PSTR("%s%s"), "MQTT : Topic: ", c_topic);
|
||||
// addLog(LOG_LEVEL_DEBUG, log);
|
||||
@@ -115,12 +118,16 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
|
||||
\*********************************************************************************************/
|
||||
bool MQTTConnect(int controller_idx)
|
||||
{
|
||||
++mqtt_reconnect_count;
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(controller_idx, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
if (!ControllerSettings.checkHostReachable(true))
|
||||
return false;
|
||||
if (MQTTclient.connected())
|
||||
if (MQTTclient.connected()) {
|
||||
MQTTclient.disconnect();
|
||||
updateMQTTclient_connected();
|
||||
}
|
||||
mqtt = WiFiClient(); // workaround see: https://github.com/esp8266/Arduino/issues/4497#issuecomment-373023864
|
||||
if (ControllerSettings.UseDNS) {
|
||||
MQTTclient.setServer(ControllerSettings.getHost().c_str(), ControllerSettings.Port);
|
||||
} else {
|
||||
@@ -165,12 +172,9 @@ bool MQTTConnect(int controller_idx)
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
if (MQTTclient.publish(LWTTopic.c_str(), "Connected", 1)) {
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
String event = F("MQTT#Connected");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
updateMQTTclient_connected();
|
||||
statusLED(true);
|
||||
mqtt_reconnect_count = 0;
|
||||
return true; // end loop if succesfull
|
||||
}
|
||||
return false;
|
||||
@@ -182,15 +186,17 @@ bool MQTTConnect(int controller_idx)
|
||||
\*********************************************************************************************/
|
||||
bool MQTTCheck(int controller_idx)
|
||||
{
|
||||
if (!WiFiConnected(10)) {
|
||||
return false;
|
||||
}
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[controller_idx]);
|
||||
if (Protocol[ProtocolIndex].usesMQTT)
|
||||
{
|
||||
if (MQTTclient_should_reconnect || !WiFiConnected(10) || !MQTTclient.connected())
|
||||
if (MQTTclient_should_reconnect || !MQTTclient.connected())
|
||||
{
|
||||
if (MQTTclient_should_reconnect) {
|
||||
addLog(LOG_LEVEL_ERROR, F("MQTT : Intentional reconnect"));
|
||||
} else {
|
||||
addLog(LOG_LEVEL_ERROR, F("MQTT : Connection lost"));
|
||||
connectionFailures += 2;
|
||||
}
|
||||
return MQTTConnect(controller_idx);
|
||||
@@ -226,8 +232,10 @@ void SendStatus(byte source, String status)
|
||||
|
||||
boolean MQTTpublish(int controller_idx, const char* topic, const char* payload, boolean retained)
|
||||
{
|
||||
if (MQTTclient.publish(topic, payload, retained))
|
||||
if (MQTTclient.publish(topic, payload, retained)) {
|
||||
timermqtt = millis() + 10; // Make sure the MQTT is being processed as soon as possible.
|
||||
return true;
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG, F("MQTT : publish failed"));
|
||||
return false;
|
||||
}
|
||||
|
||||
+35
-1
@@ -84,6 +84,14 @@ String minutesToDayHour(int minutes) {
|
||||
return TimeString;
|
||||
}
|
||||
|
||||
String minutesToHourMinute(int minutes) {
|
||||
int hours = (minutes % 1440) / 60;
|
||||
int mins = (minutes % 1440) % 60;
|
||||
char TimeString[20];
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d%c"), hours, 'h', mins, 'm');
|
||||
return TimeString;
|
||||
}
|
||||
|
||||
String minutesToDayHourMinute(int minutes) {
|
||||
int days = minutes / 1440;
|
||||
int hours = (minutes % 1440) / 60;
|
||||
@@ -104,7 +112,33 @@ String secondsToDayHourMinuteSecond(int seconds) {
|
||||
return TimeString;
|
||||
}
|
||||
|
||||
|
||||
String format_msec_duration(long duration) {
|
||||
String result;
|
||||
if (duration < 0) {
|
||||
result = "-";
|
||||
duration = -1 * duration;
|
||||
}
|
||||
if (duration < 10000) {
|
||||
result += duration;
|
||||
result += F(" ms");
|
||||
return result;
|
||||
}
|
||||
duration /= 1000;
|
||||
if (duration < 3600) {
|
||||
int sec = duration % 60;
|
||||
int minutes = duration / 60;
|
||||
if (minutes > 0) {
|
||||
result += minutes;
|
||||
result += F(" m ");
|
||||
}
|
||||
result += sec;
|
||||
result += F(" s");
|
||||
return result;
|
||||
}
|
||||
duration /= 60;
|
||||
if (duration < 1440) return minutesToHourMinute(duration);
|
||||
return minutesToDayHourMinute(duration);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
|
||||
+446
-99
@@ -1,6 +1,9 @@
|
||||
#define STR_HELPER(x) #x
|
||||
#define STR(x) STR_HELPER(x)
|
||||
|
||||
#ifndef ESPEASY_GLOBALS_H_
|
||||
#define ESPEASY_GLOBALS_H_
|
||||
|
||||
// ********************************************************************************
|
||||
// User specific configuration
|
||||
// ********************************************************************************
|
||||
@@ -15,7 +18,8 @@
|
||||
#define DEFAULT_DELAY 60 // Sleep Delay in seconds
|
||||
|
||||
// --- Wifi AP Mode (when your Wifi Network is not reachable) ----------------------------------------
|
||||
#define DEFAULT_AP_IP 192,168,4,1 // Enter IP address (comma separated) for AP (config) mode
|
||||
#define DEFAULT_AP_IP 192,168,4,1 // Enter IP address (comma separated) for AP (config) mode
|
||||
#define DEFAULT_AP_SUBNET 255,255,255,0 // Enter IP address (comma separated) for AP (config) mode
|
||||
#define DEFAULT_AP_KEY "configesp" // Enter network WPA key for AP (config) mode
|
||||
|
||||
// --- Wifi Client Mode -----------------------------------------------------------------------------
|
||||
@@ -27,6 +31,9 @@
|
||||
#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_IPRANGE_LOW "0.0.0.0" // Allowed IP range to access webserver
|
||||
#define DEFAULT_IPRANGE_HIGH "255.255.255.255" // Allowed IP range to access webserver
|
||||
#define DEFAULT_IP_BLOCK_LEVEL 1 // 0: ALL_ALLOWED 1: LOCAL_SUBNET_ALLOWED 2: ONLY_IP_RANGE_ALLOWED
|
||||
|
||||
#define DEFAULT_WIFI_CONNECTION_TIMEOUT 10000 // minimum timeout in ms for WiFi to be connected.
|
||||
|
||||
@@ -38,7 +45,8 @@
|
||||
#define DEFAULT_SERVER "192.168.0.8" // Enter your Server IP address
|
||||
#define DEFAULT_PORT 8080 // Enter your Server port value
|
||||
|
||||
#define DEFAULT_PROTOCOL 1 // Protocol used for controller communications
|
||||
#define DEFAULT_PROTOCOL 0 // Protocol used for controller communications
|
||||
// 0 = Stand-alone (no controller set)
|
||||
// 1 = Domoticz HTTP
|
||||
// 2 = Domoticz MQTT
|
||||
// 3 = Nodo Telnet
|
||||
@@ -49,8 +57,19 @@
|
||||
// 8 = Generic HTTP
|
||||
// 9 = FHEM HTTP
|
||||
|
||||
#define DEFAULT_PIN_I2C_SDA 4
|
||||
#define DEFAULT_PIN_I2C_SCL 5
|
||||
|
||||
#define DEFAULT_PIN_STATUS_LED -1
|
||||
#define DEFAULT_PIN_STATUS_LED_INVERSED true
|
||||
|
||||
|
||||
|
||||
// --- Advanced Settings ---------------------------------------------------------------------------------
|
||||
#if defined(ESP32)
|
||||
#define USE_RTOS_MULTITASKING
|
||||
#endif
|
||||
|
||||
#define DEFAULT_USE_RULES false // (true|false) Enable Rules?
|
||||
|
||||
#define DEFAULT_MQTT_RETAIN false // (true|false) Retain MQTT messages?
|
||||
@@ -65,25 +84,29 @@
|
||||
#define LOG_TO_SYSLOG 2
|
||||
#define LOG_TO_WEBLOG 3
|
||||
#define LOG_TO_SDCARD 4
|
||||
#define DEFAULT_SYSLOG_IP "" // Syslog IP Address
|
||||
#define DEFAULT_SYSLOG_IP "" // Syslog IP Address
|
||||
#define DEFAULT_SYSLOG_LEVEL 0 // Syslog Log Level
|
||||
#define DEFAULT_SERIAL_LOG_LEVEL LOG_LEVEL_INFO // Serial Log Level
|
||||
#define DEFAULT_WEB_LOG_LEVEL LOG_LEVEL_INFO // Web Log Level
|
||||
#define DEFAULT_SERIAL_LOG_LEVEL 0 // Serial Log Level
|
||||
#define DEFAULT_WEB_LOG_LEVEL LOG_LEVEL_INFO // Web Log Level
|
||||
#define DEFAULT_SD_LOG_LEVEL 0 // SD Card Log Level
|
||||
#define DEFAULT_USE_SD_LOG false // (true|false) Enable Logging to the SD card
|
||||
|
||||
#define DEFAULT_USE_SERIAL true // (true|false) Enable Logging to the Serial Port
|
||||
#define DEFAULT_SERIAL_BAUD 115200 // Serial Port Baud Rate
|
||||
|
||||
#define DEFAULT_SYSLOG_FACILITY 0 // kern
|
||||
|
||||
/*
|
||||
// --- Experimental Advanced Settings (NOT ACTIVES at this time) ------------------------------------
|
||||
#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 //
|
||||
|
||||
#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 //
|
||||
*/
|
||||
|
||||
|
||||
@@ -95,13 +118,18 @@
|
||||
#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
|
||||
#if defined(ESP8266)
|
||||
//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
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
#define FEATURE_ARDUINO_OTA
|
||||
//#define FEATURE_MDNS
|
||||
#endif
|
||||
|
||||
//enable reporting status to ESPEasy developers.
|
||||
//this informs us of crashes and stability issues.
|
||||
@@ -123,18 +151,28 @@
|
||||
//build all plugins that still are being developed and are broken or incomplete
|
||||
//#define PLUGIN_BUILD_DEV
|
||||
|
||||
//add this if you want SD support (add 10k flash)
|
||||
//#define FEATURE_SD
|
||||
|
||||
// ********************************************************************************
|
||||
// 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)
|
||||
#define ESP_PROJECT_PID 2016110801L
|
||||
|
||||
#if defined(ESP8266)
|
||||
#define VERSION 2 // config file version (not ESPEasy version). increase if you make incompatible changes to config system.
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
#define VERSION 3 // Change in config.dat mapping needs a full reset
|
||||
#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"
|
||||
#define BUILD 20102 // git version 2.1.02
|
||||
#if defined(ESP8266)
|
||||
#define BUILD_NOTES " - Mega"
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
#define BUILD_NOTES " - Mega32"
|
||||
#endif
|
||||
|
||||
#ifndef BUILD_GIT
|
||||
#define BUILD_GIT "(custom)"
|
||||
@@ -147,7 +185,6 @@
|
||||
#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
|
||||
@@ -173,6 +210,8 @@
|
||||
#define PLUGIN_GET_DEVICEGPIONAMES 22
|
||||
#define PLUGIN_EXIT 23
|
||||
#define PLUGIN_GET_CONFIG 24
|
||||
#define PLUGIN_UNCONDITIONAL_POLL 25
|
||||
#define PLUGIN_REQUEST 26
|
||||
|
||||
#define CPLUGIN_PROTOCOL_ADD 1
|
||||
#define CPLUGIN_PROTOCOL_TEMPLATE 2
|
||||
@@ -208,14 +247,15 @@
|
||||
#define LOG_LEVEL_DEBUG 3
|
||||
#define LOG_LEVEL_DEBUG_MORE 4
|
||||
#define LOG_LEVEL_DEBUG_DEV 9 // use for testing/debugging only, not for regular use
|
||||
#define LOG_LEVEL_NRELEMENTS 5 // Update this and getLogLevelDisplayString() when new log levels are added
|
||||
|
||||
#define CMD_REBOOT 89
|
||||
#define CMD_WIFI_DISCONNECT 135
|
||||
|
||||
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
|
||||
#define DEVICES_MAX 72
|
||||
#define DEVICES_MAX 75
|
||||
#else
|
||||
#define DEVICES_MAX 64
|
||||
#define DEVICES_MAX 50
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
@@ -261,6 +301,7 @@
|
||||
#define DEVICE_TYPE_I2C 20 // connected through I2C
|
||||
#define DEVICE_TYPE_DUMMY 99 // Dummy device, has no physical connection
|
||||
|
||||
#define SENSOR_TYPE_NONE 0
|
||||
#define SENSOR_TYPE_SINGLE 1
|
||||
#define SENSOR_TYPE_TEMP_HUM 2
|
||||
#define SENSOR_TYPE_TEMP_BARO 3
|
||||
@@ -286,79 +327,153 @@
|
||||
|
||||
#define DAT_TASKS_SIZE 2048
|
||||
#define DAT_TASKS_CUSTOM_OFFSET 1024
|
||||
#define DAT_TASKS_CUSTOM_SIZE 1024
|
||||
#define DAT_CUSTOM_CONTROLLER_SIZE 1024
|
||||
#define DAT_CONTROLLER_SIZE 1024
|
||||
#define DAT_NOTIFICATION_SIZE 1024
|
||||
|
||||
#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.
|
||||
|
||||
#if defined(ESP8266)
|
||||
#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.
|
||||
#define CONFIG_FILE_SIZE 65536
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
#define DAT_OFFSET_CONTROLLER 8192 // each controller = 1k, 4 max
|
||||
#define DAT_OFFSET_CUSTOM_CONTROLLER 12288 // each custom controller config = 1k, 4 max.
|
||||
#define DAT_OFFSET_TASKS 32768 // each task = 2k, (1024 basic + 1024 bytes custom), 32 max
|
||||
#define CONFIG_FILE_SIZE 131072
|
||||
#endif
|
||||
|
||||
/*
|
||||
To modify the stock configuration without changing this repo file :
|
||||
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.
|
||||
- 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 "WebStaticData.h"
|
||||
#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>
|
||||
#define FS_NO_GLOBALS
|
||||
#if defined(ESP8266)
|
||||
#include "core_version.h"
|
||||
#define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASYM_STD
|
||||
#define FILE_CONFIG "config.dat"
|
||||
#define FILE_SECURITY "security.dat"
|
||||
#define FILE_NOTIFICATION "notification.dat"
|
||||
#define FILE_RULES "rules1.txt"
|
||||
#include <lwip/init.h>
|
||||
#ifndef LWIP_VERSION_MAJOR
|
||||
#error
|
||||
#endif
|
||||
#if LWIP_VERSION_MAJOR == 2
|
||||
// #include <lwip/priv/tcp_priv.h>
|
||||
#else
|
||||
#include <lwip/tcp_impl.h>
|
||||
#endif
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266Ping.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
ESP8266WebServer WebServer(80);
|
||||
#include <DNSServer.h>
|
||||
#include <Servo.h>
|
||||
#include <ESP8266HTTPUpdateServer.h>
|
||||
ESP8266HTTPUpdateServer httpUpdater(true);
|
||||
#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"
|
||||
}
|
||||
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;
|
||||
#ifdef FEATURE_MDNS
|
||||
#include <ESP8266mDNS.h>
|
||||
#endif
|
||||
#ifdef FEATURE_ARDUINO_OTA
|
||||
#include <ArduinoOTA.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
bool ArduinoOTAtriggered=false;
|
||||
#endif
|
||||
#define PIN_D_MAX 16
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
|
||||
// Temp fix for a missing core_version.h within ESP Arduino core. Wait until they actually have different releases
|
||||
#define ARDUINO_ESP8266_RELEASE "2_4_0"
|
||||
|
||||
#define NODE_TYPE_ID NODE_TYPE_ID_ESP_EASY32_STD
|
||||
#define ICACHE_RAM_ATTR IRAM_ATTR
|
||||
#define FILE_CONFIG "/config.dat"
|
||||
#define FILE_SECURITY "/security.dat"
|
||||
#define FILE_NOTIFICATION "/notification.dat"
|
||||
#define FILE_RULES "/rules1.txt"
|
||||
#include <WiFi.h>
|
||||
#include "esp32_ping.h"
|
||||
#include <ESP32WebServer.h>
|
||||
#include "SPIFFS.h"
|
||||
ESP32WebServer WebServer(80);
|
||||
#ifdef FEATURE_MDNS
|
||||
#include <ESPmDNS.h>
|
||||
#endif
|
||||
#ifdef FEATURE_ARDUINO_OTA
|
||||
#include <ArduinoOTA.h>
|
||||
#include <ESPmDNS.h>
|
||||
bool ArduinoOTAtriggered=false;
|
||||
#endif
|
||||
#define PIN_D_MAX 39
|
||||
int8_t ledChannelPin[16];
|
||||
#endif
|
||||
|
||||
#include <WiFiUdp.h>
|
||||
#include <DNSServer.h>
|
||||
#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>
|
||||
#ifdef FEATURE_SD
|
||||
#include <SD.h>
|
||||
#include <ESP8266HTTPUpdateServer.h>
|
||||
ESP8266HTTPUpdateServer httpUpdater(true);
|
||||
#else
|
||||
using namespace fs;
|
||||
#endif
|
||||
#include <base64.h>
|
||||
#if FEATURE_ADC_VCC
|
||||
ADC_MODE(ADC_VCC);
|
||||
#endif
|
||||
#ifndef LWIP_OPEN_SRC
|
||||
#define LWIP_OPEN_SRC
|
||||
|
||||
#define ESPEASY_WIFI_DISCONNECTED 0
|
||||
#define ESPEASY_WIFI_CONNECTED 1
|
||||
#define ESPEASY_WIFI_GOT_IP 2
|
||||
#define ESPEASY_WIFI_SERVICES_INITIALIZED 3
|
||||
|
||||
#if defined(ESP32)
|
||||
void WiFiEvent(system_event_id_t event, system_event_info_t info);
|
||||
#else
|
||||
WiFiEventHandler stationConnectedHandler;
|
||||
WiFiEventHandler stationDisconnectedHandler;
|
||||
WiFiEventHandler stationGotIpHandler;
|
||||
WiFiEventHandler APModeStationConnectedHandler;
|
||||
WiFiEventHandler APModeStationDisconnectedHandler;
|
||||
#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;
|
||||
bool dnsServerActive = false;
|
||||
#ifdef FEATURE_MDNS
|
||||
MDNSResponder mdns;
|
||||
#endif
|
||||
@@ -367,25 +482,95 @@ MDNSResponder mdns;
|
||||
WiFiClient mqtt;
|
||||
PubSubClient MQTTclient(mqtt);
|
||||
bool MQTTclient_should_reconnect = true;
|
||||
|
||||
// WebServer
|
||||
ESP8266WebServer WebServer(80);
|
||||
bool MQTTclient_connected = false;
|
||||
int mqtt_reconnect_count = 0;
|
||||
|
||||
// udp protocol stuff (syslog, global sync, node info list, ntp time)
|
||||
WiFiUDP portUDP;
|
||||
|
||||
struct CRCStruct{
|
||||
char compileTimeMD5[16+32+1]= "MD5_MD5_MD5_MD5_BoundariesOfTheSegmentsGoHere...";
|
||||
char binaryFilename[32+32+1]= "ThisIsTheDummyPlaceHolderForTheBinaryFilename64ByteLongFilenames";
|
||||
char compileTime[16]= __TIME__;
|
||||
char compileDate[16]= __DATE__;
|
||||
uint8_t runTimeMD5[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
bool checkPassed (void){ return memcmp(compileTimeMD5,runTimeMD5,16)==0 ; }
|
||||
uint32_t numberOfCRCBytes=0;
|
||||
}CRCValues;
|
||||
|
||||
enum Command {
|
||||
cmd_Unknown,
|
||||
cmd_accessinfo,
|
||||
cmd_background,
|
||||
cmd_BlynkGet,
|
||||
cmd_build,
|
||||
cmd_clearaccessblock,
|
||||
cmd_clearRTCRAM,
|
||||
cmd_config,
|
||||
cmd_Debug,
|
||||
cmd_Delay,
|
||||
cmd_deepSleep,
|
||||
cmd_Erase,
|
||||
cmd_Event,
|
||||
cmd_executeRules,
|
||||
cmd_i2cscanner,
|
||||
cmd_IP,
|
||||
cmd_Load,
|
||||
cmd_logentry,
|
||||
cmd_lowmem,
|
||||
cmd_malloc,
|
||||
cmd_meminfo,
|
||||
cmd_Name,
|
||||
cmd_notify,
|
||||
cmd_NoSleep,
|
||||
cmd_Password,
|
||||
cmd_Publish,
|
||||
cmd_Reboot,
|
||||
cmd_Reset,
|
||||
cmd_Restart,
|
||||
cmd_resetFlashWriteCounter,
|
||||
cmd_Rules,
|
||||
cmd_sdcard,
|
||||
cmd_sdremove,
|
||||
cmd_sysload,
|
||||
cmd_Save,
|
||||
cmd_SendTo,
|
||||
cmd_SendToHTTP,
|
||||
cmd_SendToUDP,
|
||||
cmd_SerialFloat,
|
||||
cmd_Settings,
|
||||
cmd_TaskClear,
|
||||
cmd_TaskClearAll,
|
||||
cmd_TaskRun,
|
||||
cmd_TaskValueSet,
|
||||
cmd_TaskValueSetAndRun,
|
||||
cmd_TimerSet,
|
||||
cmd_TimerPause,
|
||||
cmd_TimerResume,
|
||||
cmd_udptest,
|
||||
cmd_Unit,
|
||||
cmd_wdconfig,
|
||||
cmd_wdread,
|
||||
cmd_WifiAPMode,
|
||||
cmd_WifiConnect,
|
||||
cmd_WifiDisconnect,
|
||||
cmd_WifiKey2,
|
||||
cmd_WifiKey,
|
||||
cmd_WifiSSID2,
|
||||
cmd_WifiSSID,
|
||||
cmd_WifiScan
|
||||
};
|
||||
|
||||
|
||||
// Forward declarations.
|
||||
Command commandStringToEnum(const char * cmd);
|
||||
bool WiFiConnected(uint32_t timeout_ms);
|
||||
bool WiFiConnected();
|
||||
bool hostReachable(const IPAddress& ip);
|
||||
bool hostReachable(const String& hostname);
|
||||
|
||||
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;
|
||||
void formatMAC(const uint8_t* mac, char (&strMAC)[20]);
|
||||
void formatIP(const IPAddress& ip, char (&strIP)[20]);
|
||||
String to_json_object_value(const String& object, const String& value);
|
||||
|
||||
struct SecurityStruct
|
||||
{
|
||||
@@ -409,7 +594,13 @@ struct SecurityStruct
|
||||
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
|
||||
byte AllowedIPrangeLow[4]; // TD-er: Use these
|
||||
byte AllowedIPrangeHigh[4];
|
||||
byte IPblockLevel;
|
||||
|
||||
//its safe to extend this struct, up to 4096 bytes, default values in config are 0. Make sure crc is last
|
||||
uint8_t ProgmemMd5[16]; // crc of the binary that last saved the struct to file.
|
||||
uint8_t md5[16];
|
||||
} SecuritySettings;
|
||||
|
||||
struct SettingsStruct
|
||||
@@ -421,10 +612,11 @@ struct SettingsStruct
|
||||
BaudRate(0), MessageDelay(0), deepSleep(0),
|
||||
CustomCSS(false), DST(false), WDI2CAddress(0),
|
||||
UseRules(false), UseSerial(false), UseSSDP(false), UseNTP(false),
|
||||
WireClockStretchLimit(0), ConnectionFailuresThreshold(0),
|
||||
WireClockStretchLimit(0), GlobalSync(false), ConnectionFailuresThreshold(0),
|
||||
TimeZone(0), MQTTRetainFlag(false), InitSPI(false),
|
||||
Pin_status_led_Inversed(false), deepSleepOnFail(false), UseValueLogger(false),
|
||||
DST_Start(0), DST_End(0)
|
||||
DST_Start(0), DST_End(0), UseRTOSMultitasking(false), Pin_Reset(-1),
|
||||
SyslogFacility(DEFAULT_SYSLOG_FACILITY), StructSize(0)
|
||||
{
|
||||
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
|
||||
Protocol[i] = 0;
|
||||
@@ -490,7 +682,7 @@ struct SettingsStruct
|
||||
boolean UseSSDP;
|
||||
boolean UseNTP;
|
||||
unsigned long WireClockStretchLimit;
|
||||
boolean _GlobalSync; // obsolete!
|
||||
boolean GlobalSync;
|
||||
unsigned long ConnectionFailuresThreshold;
|
||||
int16_t TimeZone;
|
||||
boolean MQTTRetainFlag;
|
||||
@@ -525,11 +717,23 @@ struct SettingsStruct
|
||||
boolean Pin_status_led_Inversed;
|
||||
boolean deepSleepOnFail;
|
||||
boolean UseValueLogger;
|
||||
boolean ArduinoOTAEnable;
|
||||
uint16_t DST_Start;
|
||||
uint16_t DST_End;
|
||||
boolean UseRTOSMultitasking;
|
||||
int8_t Pin_Reset;
|
||||
byte SyslogFacility;
|
||||
uint32_t StructSize; // Forced to be 32 bit, to make sure alignment is clear.
|
||||
|
||||
//its safe to extend this struct, up to several bytes, default values in config are 0
|
||||
//look in misc.ino how config.dat is used because also other stuff is stored in it at different offsets.
|
||||
//TODO: document config.dat somewhere here
|
||||
|
||||
// FIXME @TD-er: As discussed in #1292, the CRC for the settings is now disabled.
|
||||
// make sure crc is the last value in the struct
|
||||
// Try to extend settings to make the checksum 4-byte aligned.
|
||||
// uint8_t ProgmemMd5[16]; // crc of the binary that last saved the struct to file.
|
||||
// uint8_t md5[16];
|
||||
} Settings;
|
||||
|
||||
struct ControllerSettingsStruct
|
||||
@@ -631,6 +835,7 @@ private:
|
||||
if (!UseDNS) {
|
||||
return true;
|
||||
}
|
||||
if (!WiFiConnected()) return false;
|
||||
IPAddress tmpIP;
|
||||
if (WiFi.hostByName(HostName, tmpIP)) {
|
||||
for (byte x = 0; x < 4; x++) {
|
||||
@@ -725,24 +930,40 @@ struct EventStruct
|
||||
};
|
||||
|
||||
#define LOG_STRUCT_MESSAGE_SIZE 128
|
||||
#define LOG_STRUCT_MESSAGE_LINES 20
|
||||
#ifdef ESP32
|
||||
#define LOG_STRUCT_MESSAGE_LINES 30
|
||||
#else
|
||||
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
|
||||
#define LOG_STRUCT_MESSAGE_LINES 10
|
||||
#else
|
||||
#define LOG_STRUCT_MESSAGE_LINES 15
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct LogStruct {
|
||||
LogStruct() : write_idx(0), read_idx(0) {
|
||||
for (int i = 0; i < LOG_STRUCT_MESSAGE_LINES; ++i) {
|
||||
memset(Message[i], 0, LOG_STRUCT_MESSAGE_SIZE);
|
||||
Message[i].reserve(LOG_STRUCT_MESSAGE_SIZE);
|
||||
timeStamp[i] = 0;
|
||||
log_level[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void add(const char *line) {
|
||||
void add(const byte loglevel, const char *line) {
|
||||
write_idx = (write_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
|
||||
if (write_idx == read_idx) {
|
||||
// Buffer full, move read_idx to overwrite oldest entry.
|
||||
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
|
||||
}
|
||||
timeStamp[write_idx] = millis();
|
||||
strncpy(Message[write_idx], line, LOG_STRUCT_MESSAGE_SIZE-1);
|
||||
log_level[write_idx] = loglevel;
|
||||
unsigned linelength = strlen(line);
|
||||
if (linelength > LOG_STRUCT_MESSAGE_SIZE-1)
|
||||
linelength = LOG_STRUCT_MESSAGE_SIZE-1;
|
||||
Message[write_idx] = "";
|
||||
for (unsigned i = 0; i < linelength; ++i) {
|
||||
Message[write_idx] += *(line + i);
|
||||
}
|
||||
}
|
||||
|
||||
// Read the next item and append it to the given string.
|
||||
@@ -755,6 +976,20 @@ struct LogStruct {
|
||||
return !isEmpty();
|
||||
}
|
||||
|
||||
String get_logjson_formatted(bool& logLinesAvailable, unsigned long& timestamp) {
|
||||
logLinesAvailable = false;
|
||||
if (isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
|
||||
timestamp = timeStamp[read_idx];
|
||||
String output = logjson_formatLine(read_idx);
|
||||
if (isEmpty()) return output;
|
||||
output += ",\n";
|
||||
logLinesAvailable = true;
|
||||
return output;
|
||||
}
|
||||
|
||||
bool get(String& output, const String& lineEnd, int line) {
|
||||
int tmpread((write_idx + 1+line) % LOG_STRUCT_MESSAGE_LINES);
|
||||
if (timeStamp[tmpread] != 0) {
|
||||
@@ -790,11 +1025,25 @@ struct LogStruct {
|
||||
return output;
|
||||
}
|
||||
|
||||
String logjson_formatLine(int index) {
|
||||
String output;
|
||||
output.reserve(LOG_STRUCT_MESSAGE_SIZE + 64);
|
||||
output = "{";
|
||||
output += to_json_object_value("timestamp", String(timeStamp[index]));
|
||||
output += ",\n";
|
||||
output += to_json_object_value("text", Message[index]);
|
||||
output += ",\n";
|
||||
output += to_json_object_value("level", String(log_level[index]));
|
||||
output += "}";
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
int write_idx;
|
||||
int read_idx;
|
||||
unsigned long timeStamp[LOG_STRUCT_MESSAGE_LINES];
|
||||
char Message[LOG_STRUCT_MESSAGE_LINES][LOG_STRUCT_MESSAGE_SIZE];
|
||||
byte log_level[LOG_STRUCT_MESSAGE_LINES];
|
||||
String Message[LOG_STRUCT_MESSAGE_LINES];
|
||||
|
||||
} Logging;
|
||||
|
||||
@@ -871,6 +1120,8 @@ struct systemTimerStruct
|
||||
byte Par3;
|
||||
} systemTimers[SYSTEM_TIMER_MAX];
|
||||
|
||||
#define NOTAVAILABLE_SYSTEM_TIMER_ERROR "There are no system timer available, max parallel timers are " STR(SYSTEM_TIMER_MAX)
|
||||
|
||||
struct systemCMDTimerStruct
|
||||
{
|
||||
systemCMDTimerStruct() : timer(0) {}
|
||||
@@ -915,7 +1166,12 @@ String printWebString = "";
|
||||
boolean printToWebJSON = false;
|
||||
|
||||
float UserVar[VARS_PER_TASK * TASKS_MAX];
|
||||
unsigned long RulesTimer[RULES_TIMER_MAX];
|
||||
struct rulesTiemerStatus
|
||||
{
|
||||
unsigned long timestamp;
|
||||
unsigned int interval; //interval in millisencond
|
||||
boolean paused;
|
||||
} RulesTimer[RULES_TIMER_MAX];
|
||||
|
||||
unsigned long timerSensor[TASKS_MAX];
|
||||
unsigned long timer100ms;
|
||||
@@ -926,8 +1182,6 @@ unsigned long timermqtt;
|
||||
unsigned long timermqtt_interval;
|
||||
unsigned long lastSend;
|
||||
unsigned long lastWeb;
|
||||
unsigned int NC_Count = 0;
|
||||
unsigned int C_Count = 0;
|
||||
byte cmd_within_mainloop = 0;
|
||||
unsigned long connectionFailures;
|
||||
unsigned long wdcounter = 0;
|
||||
@@ -954,18 +1208,102 @@ String dummyString = "";
|
||||
|
||||
byte lastBootCause = BOOT_CAUSE_MANUAL_REBOOT;
|
||||
|
||||
#if defined(ESP32)
|
||||
enum WiFiDisconnectReason
|
||||
{
|
||||
WIFI_DISCONNECT_REASON_UNSPECIFIED = 1,
|
||||
WIFI_DISCONNECT_REASON_AUTH_EXPIRE = 2,
|
||||
WIFI_DISCONNECT_REASON_AUTH_LEAVE = 3,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_EXPIRE = 4,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_TOOMANY = 5,
|
||||
WIFI_DISCONNECT_REASON_NOT_AUTHED = 6,
|
||||
WIFI_DISCONNECT_REASON_NOT_ASSOCED = 7,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_LEAVE = 8,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_NOT_AUTHED = 9,
|
||||
WIFI_DISCONNECT_REASON_DISASSOC_PWRCAP_BAD = 10, /* 11h */
|
||||
WIFI_DISCONNECT_REASON_DISASSOC_SUPCHAN_BAD = 11, /* 11h */
|
||||
WIFI_DISCONNECT_REASON_IE_INVALID = 13, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_MIC_FAILURE = 14, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_GROUP_KEY_UPDATE_TIMEOUT = 16, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_IE_IN_4WAY_DIFFERS = 17, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_GROUP_CIPHER_INVALID = 18, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_PAIRWISE_CIPHER_INVALID = 19, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_AKMP_INVALID = 20, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_UNSUPP_RSN_IE_VERSION = 21, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_INVALID_RSN_IE_CAP = 22, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_802_1X_AUTH_FAILED = 23, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_CIPHER_SUITE_REJECTED = 24, /* 11i */
|
||||
|
||||
WIFI_DISCONNECT_REASON_BEACON_TIMEOUT = 200,
|
||||
WIFI_DISCONNECT_REASON_NO_AP_FOUND = 201,
|
||||
WIFI_DISCONNECT_REASON_AUTH_FAIL = 202,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_FAIL = 203,
|
||||
WIFI_DISCONNECT_REASON_HANDSHAKE_TIMEOUT = 204
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ESP32
|
||||
// To do some reconnection check.
|
||||
#include <Ticker.h>
|
||||
Ticker connectionCheck;
|
||||
#endif
|
||||
|
||||
bool reconnectChecker = false;
|
||||
void connectionCheckHandler()
|
||||
{
|
||||
if (reconnectChecker == false && !WiFiConnected()){
|
||||
reconnectChecker = true;
|
||||
WiFi.reconnect();
|
||||
}
|
||||
else if (WiFiConnected() && reconnectChecker == true){
|
||||
reconnectChecker = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool useStaticIP();
|
||||
|
||||
// WiFi related data
|
||||
boolean wifiSetup = false;
|
||||
boolean wifiSetupConnect = false;
|
||||
uint8_t lastBSSID[6] = {0};
|
||||
boolean wifiConnected = false;
|
||||
unsigned long wifi_connect_timer = 0;
|
||||
uint8_t wifiStatus = ESPEASY_WIFI_DISCONNECTED;
|
||||
unsigned long last_wifi_connect_attempt_moment = 0;
|
||||
unsigned int wifi_connect_attempt = 0;
|
||||
int wifi_reconnects = -1; // First connection attempt is not a reconnect.
|
||||
uint8_t lastWiFiSettings = 0;
|
||||
String last_ssid;
|
||||
bool bssid_changed = false;
|
||||
uint8_t last_channel = 0;
|
||||
WiFiDisconnectReason lastDisconnectReason = WIFI_DISCONNECT_REASON_UNSPECIFIED;
|
||||
unsigned long lastConnectMoment = 0;
|
||||
unsigned long lastDisconnectMoment = 0;
|
||||
unsigned long lastGetIPmoment = 0;
|
||||
unsigned long lastGetScanMoment = 0;
|
||||
unsigned long lastConnectedDuration = 0;
|
||||
bool intent_to_reboot = false;
|
||||
uint8_t lastMacConnectedAPmode[6] = {0};
|
||||
uint8_t lastMacDisconnectedAPmode[6] = {0};
|
||||
|
||||
//uint32_t scan_done_status = 0;
|
||||
uint8_t scan_done_number = 0;
|
||||
//uint8_t scan_done_scan_id = 0;
|
||||
|
||||
// Semaphore like booleans for processing data gathered from WiFi events.
|
||||
bool processedConnect = true;
|
||||
bool processedDisconnect = true;
|
||||
bool processedGetIP = true;
|
||||
bool processedConnectAPmode = true;
|
||||
bool processedDisconnectAPmode = true;
|
||||
bool processedScanDone = true;
|
||||
|
||||
unsigned long start = 0;
|
||||
unsigned long elapsed = 0;
|
||||
bool webserver_state = false;
|
||||
bool webserver_init = false;
|
||||
|
||||
unsigned long elapsed10ps = 0;
|
||||
unsigned long elapsed10psU = 0;
|
||||
unsigned long elapsed50ps = 0;
|
||||
unsigned long loopCounter = 0;
|
||||
unsigned long loopCounterLast = 0;
|
||||
unsigned long loopCounterMax = 1;
|
||||
@@ -974,7 +1312,7 @@ unsigned long dailyResetCounter = 0;
|
||||
|
||||
String eventBuffer = "";
|
||||
|
||||
uint16_t lowestRAM = 0;
|
||||
uint32_t lowestRAM = 0;
|
||||
String lowestRAMfunction = "";
|
||||
|
||||
bool shouldReboot=false;
|
||||
@@ -982,4 +1320,13 @@ bool firstLoop=true;
|
||||
|
||||
boolean activeRuleSets[RULESETS_MAX];
|
||||
|
||||
boolean UseRTOSMultitasking;
|
||||
|
||||
void (*MainLoopCall_ptr)(void);
|
||||
|
||||
// These wifi event functions must be in a .h-file because otherwise the preprocessor
|
||||
// may not filter the ifdef checks properly.
|
||||
// Also the functions use a lot of global defined variables, so include at the end of this file.
|
||||
#include "ESPEasyWiFiEvent.h"
|
||||
|
||||
#endif /* ESPEASY_GLOBALS_H_ */
|
||||
|
||||
+261
-114
@@ -1,3 +1,4 @@
|
||||
|
||||
#ifdef CONTINUOUS_INTEGRATION
|
||||
#pragma GCC diagnostic error "-Wall"
|
||||
#else
|
||||
@@ -41,7 +42,7 @@
|
||||
|
||||
// Simple Arduino sketch for ESP module, supporting:
|
||||
// =================================================================================
|
||||
// Simple switch inputs and direct GPIO output control to drive relais, mosfets, etc
|
||||
// Simple switch inputs and direct GPIO output control to drive relays, mosfets, etc
|
||||
// Analog input (ESP-7/12 only)
|
||||
// Pulse counters
|
||||
// Dallas OneWire DS18b20 temperature sensors
|
||||
@@ -71,7 +72,9 @@
|
||||
// SHT1X temperature/humidity sensors
|
||||
// Ser2Net server
|
||||
|
||||
// Define globals before plugin sets to allow a personal override of the selected plugins
|
||||
#include "ESPEasy-Globals.h"
|
||||
#include "define_plugin_sets.h"
|
||||
|
||||
// Blynk_get prototype
|
||||
boolean Blynk_get(const String& command, byte controllerIndex,float *data = NULL );
|
||||
@@ -86,12 +89,22 @@ int firstEnabledBlynkController() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//void checkRAM( const __FlashStringHelper* flashString);
|
||||
|
||||
/*********************************************************************************************\
|
||||
* SETUP
|
||||
\*********************************************************************************************/
|
||||
void setup()
|
||||
{
|
||||
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
|
||||
WiFi.setAutoReconnect(false);
|
||||
setWifiMode(WIFI_OFF);
|
||||
|
||||
checkRAM(F("setup"));
|
||||
#if defined(ESP32)
|
||||
for(byte x = 0; x < 16; x++)
|
||||
ledChannelPin[x] = -1;
|
||||
#endif
|
||||
|
||||
lowestRAM = FreeMem();
|
||||
|
||||
@@ -99,7 +112,16 @@ void setup()
|
||||
// Serial.print("\n\n\nBOOOTTT\n\n\n");
|
||||
|
||||
initLog();
|
||||
|
||||
#if defined(ESP32)
|
||||
WiFi.onEvent((WiFiEventFullCb)WiFiEvent);
|
||||
#else
|
||||
// WiFi event handlers
|
||||
stationConnectedHandler = WiFi.onStationModeConnected(onConnected);
|
||||
stationDisconnectedHandler = WiFi.onStationModeDisconnected(onDisconnect);
|
||||
stationGotIpHandler = WiFi.onStationModeGotIP(onGotIP);
|
||||
APModeStationConnectedHandler = WiFi.onSoftAPModeStationConnected(onConnectedAPmode);
|
||||
APModeStationDisconnectedHandler = WiFi.onSoftAPModeStationDisconnected(onDisonnectedAPmode);
|
||||
#endif
|
||||
|
||||
if (SpiffsSectors() < 32)
|
||||
{
|
||||
@@ -112,6 +134,9 @@ void setup()
|
||||
|
||||
String log = F("\n\n\rINIT : Booting version: ");
|
||||
log += BUILD_GIT;
|
||||
log += F(" (");
|
||||
log += getSystemLibraryString();
|
||||
log += F(")");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
|
||||
@@ -148,15 +173,12 @@ void setup()
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
|
||||
|
||||
|
||||
fileSystemCheck();
|
||||
progMemMD5check();
|
||||
LoadSettings();
|
||||
|
||||
// setWifiMode(WIFI_STA);
|
||||
checkRuleSets();
|
||||
if (strcasecmp(SecuritySettings.WifiSSID, "ssid") == 0)
|
||||
wifiSetup = true;
|
||||
|
||||
ExtraTaskSettings.TaskIndex = 255; // make sure this is an unused nr to prevent cache load on boot
|
||||
|
||||
@@ -179,6 +201,7 @@ void setup()
|
||||
//make sure previous serial buffers are flushed before resetting baudrate
|
||||
Serial.flush();
|
||||
Serial.begin(Settings.BaudRate);
|
||||
// Serial.setDebugOutput(true);
|
||||
}
|
||||
|
||||
if (Settings.Build != BUILD)
|
||||
@@ -192,6 +215,7 @@ void setup()
|
||||
if (Settings.UseSerial && Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE)
|
||||
Serial.setDebugOutput(true);
|
||||
|
||||
checkRAM(F("hardwareInit"));
|
||||
hardwareInit();
|
||||
|
||||
//After booting, we want all the tasks to run without delaying more than neccesary.
|
||||
@@ -204,43 +228,48 @@ void setup()
|
||||
timer100ms = 0; // timer for periodic actions 10 x per/sec
|
||||
timer1s = 0; // timer for periodic actions once per/sec
|
||||
timerwd = 0; // timer for watchdog once per 30 sec
|
||||
timermqtt = 0; // Timer for the MQTT keep alive loop.
|
||||
timermqtt = 10000; // Timer for the MQTT keep alive loop, initial value can be high, since it will be set as soon as IP is set.
|
||||
timermqtt_interval = 250; // Interval for checking MQTT
|
||||
timerAwakeFromDeepSleep = millis();
|
||||
|
||||
PluginInit();
|
||||
CPluginInit();
|
||||
NPluginInit();
|
||||
log = F("INFO : Plugins: ");
|
||||
log += deviceCount + 1;
|
||||
log += getPluginDescriptionString();
|
||||
log += F(" (");
|
||||
log += getSystemLibraryString();
|
||||
log += F(")");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
if (deviceCount + 1 >= PLUGIN_MAX) {
|
||||
addLog(LOG_LEVEL_ERROR, F("Programming error! - Increase PLUGIN_MAX"));
|
||||
}
|
||||
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
String event = F("System#Wake");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
|
||||
WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters
|
||||
WifiAPconfig();
|
||||
|
||||
if (Settings.deepSleep)
|
||||
{
|
||||
//only one attempt in deepsleep, to conserve battery
|
||||
if (!WifiConnect(1))
|
||||
{
|
||||
if (Settings.deepSleepOnFail)
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F("SLEEP: Connection failed, going back to sleep."));
|
||||
deepSleep(Settings.Delay);
|
||||
}
|
||||
}
|
||||
if (!selectValidWiFiSettings()) {
|
||||
wifiSetup = true;
|
||||
}
|
||||
else
|
||||
WiFiConnectRelaxed();
|
||||
/*
|
||||
// FIXME TD-er:
|
||||
// Async scanning for wifi doesn't work yet like it should.
|
||||
// So no selection of strongest network yet.
|
||||
if (selectValidWiFiSettings()) {
|
||||
WifiScanAsync();
|
||||
}
|
||||
*/
|
||||
WiFiConnectRelaxed();
|
||||
|
||||
#ifdef FEATURE_REPORTING
|
||||
ReportStatus();
|
||||
#endif
|
||||
|
||||
WebServerInit();
|
||||
|
||||
#ifdef FEATURE_ARDUINO_OTA
|
||||
ArduinoOTAInit();
|
||||
#endif
|
||||
@@ -258,12 +287,6 @@ void setup()
|
||||
vcc = ESP.getVcc() / 1000.0;
|
||||
#endif
|
||||
|
||||
// Start DNS, only used if the ESP has no valid WiFi config
|
||||
// It will reply with it's own address on all DNS requests
|
||||
// (captive portal concept)
|
||||
if (wifiSetup)
|
||||
dnsServer.start(DNS_PORT, "*", apIP);
|
||||
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
String event = F("System#Boot");
|
||||
@@ -272,8 +295,55 @@ void setup()
|
||||
|
||||
writeDefaultCSS();
|
||||
|
||||
UseRTOSMultitasking = Settings.UseRTOSMultitasking;
|
||||
#ifdef USE_RTOS_MULTITASKING
|
||||
if(UseRTOSMultitasking){
|
||||
log = F("RTOS : Launching tasks");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
xTaskCreatePinnedToCore(RTOS_TaskServers, "RTOS_TaskServers", 8192, NULL, 1, NULL, 1);
|
||||
xTaskCreatePinnedToCore(RTOS_TaskSerial, "RTOS_TaskSerial", 8192, NULL, 1, NULL, 1);
|
||||
xTaskCreatePinnedToCore(RTOS_Task10ps, "RTOS_Task10ps", 8192, NULL, 1, NULL, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
// #ifndef ESP32
|
||||
// connectionCheck.attach(30, connectionCheckHandler);
|
||||
// #endif
|
||||
timer20ms = millis();
|
||||
timer100ms = millis();
|
||||
timer1s = millis();
|
||||
}
|
||||
|
||||
#ifdef USE_RTOS_MULTITASKING
|
||||
void RTOS_TaskServers( void * parameter )
|
||||
{
|
||||
while (true){
|
||||
delay(100);
|
||||
WebServer.handleClient();
|
||||
checkUDP();
|
||||
}
|
||||
}
|
||||
|
||||
void RTOS_TaskSerial( void * parameter )
|
||||
{
|
||||
while (true){
|
||||
delay(100);
|
||||
if (Settings.UseSerial)
|
||||
if (Serial.available())
|
||||
if (!PluginCall(PLUGIN_SERIAL_IN, 0, dummyString))
|
||||
serial();
|
||||
}
|
||||
}
|
||||
|
||||
void RTOS_Task10ps( void * parameter )
|
||||
{
|
||||
while (true){
|
||||
delay(100);
|
||||
run10TimesPerSecond();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int firstEnabledMQTTController() {
|
||||
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[i]);
|
||||
@@ -295,25 +365,41 @@ bool getControllerProtocolDisplayName(byte ProtocolIndex, byte parameterIdx, Str
|
||||
\*********************************************************************************************/
|
||||
void loop()
|
||||
{
|
||||
if(MainLoopCall_ptr)
|
||||
MainLoopCall_ptr();
|
||||
|
||||
loopCounter++;
|
||||
|
||||
if (wifiSetupConnect)
|
||||
{
|
||||
// try to connect for setup wizard
|
||||
WifiConnect(1);
|
||||
WiFiConnectRelaxed();
|
||||
wifiSetupConnect = false;
|
||||
}
|
||||
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
if (wifiStatus >= ESPEASY_WIFI_CONNECTED) processConnect();
|
||||
if (wifiStatus >= ESPEASY_WIFI_GOT_IP) processGotIP();
|
||||
if (wifiStatus == ESPEASY_WIFI_DISCONNECTED) processDisconnect();
|
||||
} else if (!WiFiConnected()) {
|
||||
// Somehow the WiFi has entered a limbo state.
|
||||
// FIXME TD-er: This may happen on WiFi config with AP_STA mode active.
|
||||
// addLog(LOG_LEVEL_ERROR, F("Wifi status out sync"));
|
||||
// resetWiFi();
|
||||
}
|
||||
if (!processedConnectAPmode) processConnectAPmode();
|
||||
if (!processedDisconnectAPmode) processDisconnectAPmode();
|
||||
if (!processedScanDone) processScanDone();
|
||||
|
||||
// Deep sleep mode, just run all tasks one time and go back to sleep as fast as possible
|
||||
if (firstLoop && isDeepSleepEnabled())
|
||||
bool firstLoopWiFiConnected = wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED && firstLoop;
|
||||
if (firstLoopWiFiConnected) {
|
||||
firstLoop = false;
|
||||
timerAwakeFromDeepSleep = millis(); // Allow to run for "awake" number of seconds, now we have wifi.
|
||||
}
|
||||
|
||||
// Deep sleep mode, just run all tasks one (more) time and go back to sleep as fast as possible
|
||||
if ((firstLoopWiFiConnected || readyForSleep()) && isDeepSleepEnabled())
|
||||
{
|
||||
// Setup MQTT Client
|
||||
// Controller index is forced to the first enabled MQTT controller.
|
||||
// This is normally done via frequent checks, but there's no time for in deepsleep.
|
||||
int enabledMqttController = firstEnabledMQTTController();
|
||||
if (enabledMqttController >= 0) {
|
||||
MQTTConnect(enabledMqttController);
|
||||
}
|
||||
runPeriodicalMQTT();
|
||||
// Now run all frequent tasks
|
||||
run50TimesPerSecond();
|
||||
run10TimesPerSecond();
|
||||
@@ -328,7 +414,8 @@ void loop()
|
||||
run50TimesPerSecond();
|
||||
|
||||
if (timeOutReached(timer100ms))
|
||||
run10TimesPerSecond();
|
||||
if(!UseRTOSMultitasking)
|
||||
run10TimesPerSecond();
|
||||
|
||||
if (timeOutReached(timerwd))
|
||||
runEach30Seconds();
|
||||
@@ -337,21 +424,7 @@ void loop()
|
||||
runOncePerSecond();
|
||||
|
||||
if (timeOutReached(timermqtt)) {
|
||||
// MQTT_KEEPALIVE = 15 seconds.
|
||||
timermqtt = millis() + timermqtt_interval;
|
||||
//dont do this in backgroundtasks(), otherwise causes crashes. (https://github.com/letscontrolit/ESPEasy/issues/683)
|
||||
int enabledMqttController = firstEnabledMQTTController();
|
||||
if (enabledMqttController >= 0) {
|
||||
if (!MQTTclient.loop()) {
|
||||
if (!MQTTCheck(enabledMqttController)) {
|
||||
// Check failed, no need to retry it immediately.
|
||||
if (timermqtt_interval < 2000)
|
||||
timermqtt_interval += 250;
|
||||
} else {
|
||||
timermqtt_interval = 250;
|
||||
}
|
||||
}
|
||||
}
|
||||
runPeriodicalMQTT();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,24 +436,69 @@ void loop()
|
||||
String event = F("System#Sleep");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
// Flush outstanding MQTT messages
|
||||
runPeriodicalMQTT();
|
||||
|
||||
deepSleep(Settings.Delay);
|
||||
//deepsleep will never return, its a special kind of reboot
|
||||
}
|
||||
firstLoop = false;
|
||||
}
|
||||
|
||||
|
||||
void runPeriodicalMQTT() {
|
||||
// MQTT_KEEPALIVE = 15 seconds.
|
||||
if (!WiFiConnected(10)) {
|
||||
updateMQTTclient_connected();
|
||||
return;
|
||||
}
|
||||
//dont do this in backgroundtasks(), otherwise causes crashes. (https://github.com/letscontrolit/ESPEasy/issues/683)
|
||||
int enabledMqttController = firstEnabledMQTTController();
|
||||
if (enabledMqttController >= 0) {
|
||||
if (!MQTTclient.loop()) {
|
||||
updateMQTTclient_connected();
|
||||
if (MQTTCheck(enabledMqttController)) {
|
||||
updateMQTTclient_connected();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (MQTTclient.connected()) {
|
||||
MQTTclient.disconnect();
|
||||
updateMQTTclient_connected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateMQTTclient_connected() {
|
||||
if (MQTTclient_connected != MQTTclient.connected()) {
|
||||
MQTTclient_connected = !MQTTclient_connected;
|
||||
if (!MQTTclient_connected)
|
||||
addLog(LOG_LEVEL_ERROR, F("MQTT : Connection lost"));
|
||||
if (Settings.UseRules) {
|
||||
String event = MQTTclient_connected ? F("MQTT#Connected") : F("MQTT#Disconnected");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
}
|
||||
if (!MQTTclient_connected) {
|
||||
// As suggested here: https://github.com/letscontrolit/ESPEasy/issues/1356
|
||||
if (timermqtt_interval < 30000) {
|
||||
timermqtt_interval += 5000;
|
||||
}
|
||||
} else {
|
||||
timermqtt_interval = 250;
|
||||
}
|
||||
timermqtt = millis() + timermqtt_interval;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Tasks that run 50 times per second
|
||||
\*********************************************************************************************/
|
||||
|
||||
void run50TimesPerSecond()
|
||||
{
|
||||
timer20ms = millis() + 20;
|
||||
setNextTimeInterval(timer20ms, 20);
|
||||
unsigned long start = micros();
|
||||
PluginCall(PLUGIN_FIFTY_PER_SECOND, 0, dummyString);
|
||||
|
||||
// statusLED(false);
|
||||
elapsed50ps += micros() - start;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
@@ -388,16 +506,21 @@ void run50TimesPerSecond()
|
||||
\*********************************************************************************************/
|
||||
void run10TimesPerSecond()
|
||||
{
|
||||
start = micros();
|
||||
timer100ms = millis() + 100;
|
||||
setNextTimeInterval(timer100ms, 100);
|
||||
unsigned long start = micros();
|
||||
PluginCall(PLUGIN_TEN_PER_SECOND, 0, dummyString);
|
||||
elapsed10ps += micros() - start;
|
||||
start = micros();
|
||||
PluginCall(PLUGIN_UNCONDITIONAL_POLL, 0, dummyString);
|
||||
elapsed10psU += micros() - start;
|
||||
if (Settings.UseRules && eventBuffer.length() > 0)
|
||||
{
|
||||
rulesProcessing(eventBuffer);
|
||||
eventBuffer = "";
|
||||
}
|
||||
elapsed = micros() - start;
|
||||
WebServer.handleClient();
|
||||
#ifndef USE_RTOS_MULTITASKING
|
||||
WebServer.handleClient();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -406,6 +529,7 @@ void run10TimesPerSecond()
|
||||
\*********************************************************************************************/
|
||||
void runOncePerSecond()
|
||||
{
|
||||
setNextTimeInterval(timer1s, 1000);
|
||||
dailyResetCounter++;
|
||||
if (dailyResetCounter > 86400) // 1 day elapsed... //86400
|
||||
{
|
||||
@@ -416,8 +540,6 @@ void runOncePerSecond()
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
|
||||
timer1s = millis() + 1000;
|
||||
|
||||
checkSensors();
|
||||
|
||||
if (Settings.ConnectionFailuresThreshold)
|
||||
@@ -435,7 +557,12 @@ void runOncePerSecond()
|
||||
}
|
||||
case CMD_REBOOT:
|
||||
{
|
||||
ESP.reset();
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
ESP.restart();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -447,15 +574,15 @@ void runOncePerSecond()
|
||||
if (Settings.UseNTP)
|
||||
checkTime();
|
||||
|
||||
unsigned long timer = micros();
|
||||
unsigned long start = micros();
|
||||
PluginCall(PLUGIN_ONCE_A_SECOND, 0, dummyString);
|
||||
unsigned long elapsed = micros() - start;
|
||||
|
||||
checkSystemTimers();
|
||||
|
||||
if (Settings.UseRules)
|
||||
rulesTimers();
|
||||
|
||||
timer = micros() - timer;
|
||||
|
||||
if (SecuritySettings.Password[0] != 0)
|
||||
{
|
||||
@@ -473,19 +600,22 @@ void runOncePerSecond()
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
if (Settings.SerialLogLevel == 5)
|
||||
if (Settings.SerialLogLevel == LOG_LEVEL_DEBUG_DEV)
|
||||
{
|
||||
Serial.print(F("10 ps:"));
|
||||
Serial.print(F("Plugin calls: 50 ps:"));
|
||||
Serial.print(elapsed50ps);
|
||||
Serial.print(F(" uS, 10 ps:"));
|
||||
Serial.print(elapsed10ps);
|
||||
Serial.print(F(" uS, 10 psU:"));
|
||||
Serial.print(elapsed10psU);
|
||||
Serial.print(F(" uS, 1 ps:"));
|
||||
Serial.print(elapsed);
|
||||
Serial.print(F(" uS 1 ps:"));
|
||||
Serial.println(timer);
|
||||
}
|
||||
|
||||
if (timerAPoff != 0 && timeOutReached(timerAPoff))
|
||||
{
|
||||
timerAPoff = 0;
|
||||
WifiAPMode(false);
|
||||
Serial.println(F(" uS"));
|
||||
elapsed50ps=0;
|
||||
elapsed10ps=0;
|
||||
elapsed10psU=0;
|
||||
}
|
||||
checkResetFactoryPin();
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
@@ -493,22 +623,26 @@ void runOncePerSecond()
|
||||
\*********************************************************************************************/
|
||||
void runEach30Seconds()
|
||||
{
|
||||
extern void checkRAMtoLog();
|
||||
checkRAMtoLog();
|
||||
wdcounter++;
|
||||
timerwd = millis() + 30000;
|
||||
char str[60];
|
||||
str[0] = 0;
|
||||
sprintf_P(str, PSTR("Uptime %u ConnectFailures %u FreeMem %u"), wdcounter / 2, connectionFailures, FreeMem());
|
||||
String log = F("WD : ");
|
||||
log += str;
|
||||
String log;
|
||||
log.reserve(60);
|
||||
log = F("WD : Uptime ");
|
||||
log += wdcounter / 2;
|
||||
log += F(" ConnectFailures ");
|
||||
log += connectionFailures;
|
||||
log += F(" FreeMem ");
|
||||
log += FreeMem();
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
sendSysInfoUDP(1);
|
||||
refreshNodeList();
|
||||
int enabledMqttController = firstEnabledMQTTController();
|
||||
if (enabledMqttController >= 0) {
|
||||
MQTTCheck(enabledMqttController);
|
||||
}
|
||||
|
||||
#if defined(ESP8266)
|
||||
if (Settings.UseSSDP)
|
||||
SSDP_update();
|
||||
#endif
|
||||
#if FEATURE_ADC_VCC
|
||||
vcc = ESP.getVcc() / 1000.0;
|
||||
#endif
|
||||
@@ -529,6 +663,7 @@ void runEach30Seconds()
|
||||
\*********************************************************************************************/
|
||||
void checkSensors()
|
||||
{
|
||||
checkRAM(F("checkSensors"));
|
||||
bool isDeepSleep = isDeepSleepEnabled();
|
||||
//check all the devices and only run the sendtask if its time, or we if we used deep sleep mode
|
||||
for (byte x = 0; x < TASKS_MAX; x++)
|
||||
@@ -538,7 +673,7 @@ void checkSensors()
|
||||
(isDeepSleep || timeOutReached(timerSensor[x]))
|
||||
)
|
||||
{
|
||||
timerSensor[x] = millis() + Settings.TaskDeviceTimer[x] * 1000;
|
||||
setNextTimeInterval(timerSensor[x], Settings.TaskDeviceTimer[x] * 1000);
|
||||
if (timerSensor[x] == 0) // small fix if result is 0, else timer will be stopped...
|
||||
timerSensor[x] = 1;
|
||||
SensorSendTask(x);
|
||||
@@ -565,6 +700,7 @@ void checkSensors()
|
||||
\*********************************************************************************************/
|
||||
void SensorSendTask(byte TaskIndex)
|
||||
{
|
||||
checkRAM(F("SensorSendTask"));
|
||||
if (Settings.TaskDeviceEnabled[TaskIndex])
|
||||
{
|
||||
byte varIndex = TaskIndex * VARS_PER_TASK;
|
||||
@@ -620,7 +756,9 @@ void setSystemTimer(unsigned long timer, byte plugin, byte Par1, byte Par2, byte
|
||||
// plugin number and par1 form a unique key that can be used to restart a timer
|
||||
// first check if a timer is not already running for this request
|
||||
boolean reUse = false;
|
||||
byte firstAvailable = SYSTEM_TIMER_MAX;
|
||||
for (byte x = 0; x < SYSTEM_TIMER_MAX; x++)
|
||||
{
|
||||
if (systemTimers[x].timer != 0)
|
||||
{
|
||||
if ((systemTimers[x].plugin == plugin) && (systemTimers[x].Par1 == Par1))
|
||||
@@ -630,20 +768,25 @@ void setSystemTimer(unsigned long timer, byte plugin, byte Par1, byte Par2, byte
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else if(firstAvailable == SYSTEM_TIMER_MAX)
|
||||
{
|
||||
firstAvailable = x;
|
||||
}
|
||||
}
|
||||
if (!reUse)
|
||||
{
|
||||
// find a new free timer slot...
|
||||
for (byte x = 0; x < SYSTEM_TIMER_MAX; x++)
|
||||
if (systemTimers[x].timer == 0)
|
||||
{
|
||||
systemTimers[x].timer = millis() + timer;
|
||||
systemTimers[x].plugin = plugin;
|
||||
systemTimers[x].Par1 = Par1;
|
||||
systemTimers[x].Par2 = Par2;
|
||||
systemTimers[x].Par3 = Par3;
|
||||
break;
|
||||
}
|
||||
if (firstAvailable == SYSTEM_TIMER_MAX )
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F(NOTAVAILABLE_SYSTEM_TIMER_ERROR));
|
||||
}
|
||||
else
|
||||
{
|
||||
systemTimers[firstAvailable].timer = millis() + timer;
|
||||
systemTimers[firstAvailable].plugin = plugin;
|
||||
systemTimers[firstAvailable].Par1 = Par1;
|
||||
systemTimers[firstAvailable].Par2 = Par2;
|
||||
systemTimers[firstAvailable].Par3 = Par3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -705,6 +848,7 @@ void checkSystemTimers()
|
||||
bool runningBackgroundTasks=false;
|
||||
void backgroundtasks()
|
||||
{
|
||||
//checkRAM(F("backgroundtasks"));
|
||||
//always start with a yield
|
||||
yield();
|
||||
|
||||
@@ -715,23 +859,26 @@ void backgroundtasks()
|
||||
}
|
||||
runningBackgroundTasks=true;
|
||||
|
||||
tcpCleanup();
|
||||
#if defined(ESP8266)
|
||||
tcpCleanup();
|
||||
#endif
|
||||
|
||||
if (Settings.UseSerial)
|
||||
if (Serial.available())
|
||||
if (!PluginCall(PLUGIN_SERIAL_IN, 0, dummyString))
|
||||
serial();
|
||||
if(!UseRTOSMultitasking){
|
||||
if (Settings.UseSerial)
|
||||
if (Serial.available())
|
||||
if (!PluginCall(PLUGIN_SERIAL_IN, 0, dummyString))
|
||||
serial();
|
||||
WebServer.handleClient();
|
||||
checkUDP();
|
||||
}
|
||||
|
||||
// process DNS, only used if the ESP has no valid WiFi config
|
||||
if (wifiSetup)
|
||||
if (dnsServerActive)
|
||||
dnsServer.processNextRequest();
|
||||
|
||||
WebServer.handleClient();
|
||||
|
||||
checkUDP();
|
||||
|
||||
#ifdef FEATURE_ARDUINO_OTA
|
||||
ArduinoOTA.handle();
|
||||
if(Settings.ArduinoOTAEnable)
|
||||
ArduinoOTA.handle();
|
||||
|
||||
//once OTA is triggered, only handle that and dont do other stuff. (otherwise it fails)
|
||||
while (ArduinoOTAtriggered)
|
||||
|
||||
@@ -64,6 +64,7 @@ void setTimeZone(const TimeChangeRule& dstStart, const TimeChangeRule& stdStart,
|
||||
uint32_t calcTimeChangeForRule(const TimeChangeRule& r, int yr);
|
||||
String getTimeString(char delimiter, bool show_seconds=true);
|
||||
String getTimeString_ampm(char delimiter, bool show_seconds=true);
|
||||
long timeDiff(unsigned long prev, unsigned long next);
|
||||
|
||||
|
||||
#endif /* ESPEASY_TIMETYPES_H_ */
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
//********************************************************************************
|
||||
// Work-around for setting _useStaticIP
|
||||
// See reported issue: https://github.com/esp8266/Arduino/issues/4114
|
||||
//********************************************************************************
|
||||
#ifdef ESP32
|
||||
class WiFi_Access_Static_IP: public WiFiSTAClass {
|
||||
public:
|
||||
void set_use_static_ip(bool enabled) {
|
||||
_useStaticIp = enabled;
|
||||
}
|
||||
};
|
||||
#else
|
||||
class WiFi_Access_Static_IP: public ESP8266WiFiSTAClass {
|
||||
public:
|
||||
void set_use_static_ip(bool enabled) {
|
||||
_useStaticIp = enabled;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
void setUseStaticIP(bool enabled) {
|
||||
WiFi_Access_Static_IP tmp_wifi;
|
||||
tmp_wifi.set_use_static_ip(enabled);
|
||||
}
|
||||
|
||||
|
||||
void markGotIP() {
|
||||
lastGetIPmoment = millis();
|
||||
wifiStatus = ESPEASY_WIFI_GOT_IP;
|
||||
processedGetIP = false;
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Functions called on events.
|
||||
// Make sure not to call anything in these functions that result in delay() or yield()
|
||||
//********************************************************************************
|
||||
#ifdef ESP32
|
||||
void WiFiEvent(system_event_id_t event, system_event_info_t info) {
|
||||
switch(event) {
|
||||
case SYSTEM_EVENT_STA_CONNECTED:
|
||||
lastConnectMoment = millis();
|
||||
processedConnect = false;
|
||||
wifiStatus = ESPEASY_WIFI_CONNECTED;
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
lastDisconnectMoment = millis();
|
||||
if (timeDiff(lastConnectMoment, last_wifi_connect_attempt_moment) > 0) {
|
||||
// There was an unsuccessful connection attempt
|
||||
lastConnectedDuration = timeDiff(last_wifi_connect_attempt_moment, lastDisconnectMoment);
|
||||
} else {
|
||||
lastConnectedDuration = timeDiff(lastConnectMoment, lastDisconnectMoment);
|
||||
}
|
||||
processedDisconnect = false;
|
||||
lastDisconnectReason = static_cast<WiFiDisconnectReason>(info.disconnected.reason);
|
||||
wifiStatus = ESPEASY_WIFI_DISCONNECTED;
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
markGotIP();
|
||||
break;
|
||||
case SYSTEM_EVENT_AP_STACONNECTED:
|
||||
for (byte i = 0; i < 6; ++i) {
|
||||
lastMacConnectedAPmode[i] = info.sta_connected.mac[i];
|
||||
}
|
||||
processedConnectAPmode = false;
|
||||
break;
|
||||
case SYSTEM_EVENT_AP_STADISCONNECTED:
|
||||
for (byte i = 0; i < 6; ++i) {
|
||||
lastMacConnectedAPmode[i] = info.sta_disconnected.mac[i];
|
||||
}
|
||||
processedDisconnectAPmode = false;
|
||||
break;
|
||||
case SYSTEM_EVENT_SCAN_DONE:
|
||||
lastGetScanMoment = millis();
|
||||
// scan_done_status = info.scan_done.status;
|
||||
scan_done_number = info.scan_done.number;
|
||||
// scan_done_scan_id = info.scan_done.scan_id;
|
||||
processedScanDone = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
void onConnected(const WiFiEventStationModeConnected& event){
|
||||
lastConnectMoment = millis();
|
||||
processedConnect = false;
|
||||
wifiStatus = ESPEASY_WIFI_CONNECTED;
|
||||
last_channel = event.channel;
|
||||
last_ssid = event.ssid;
|
||||
bssid_changed = false;
|
||||
for (byte i=0; i < 6; ++i) {
|
||||
if (lastBSSID[i] != event.bssid[i]) {
|
||||
bssid_changed = true;
|
||||
lastBSSID[i] = event.bssid[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onDisconnect(const WiFiEventStationModeDisconnected& event){
|
||||
lastDisconnectMoment = millis();
|
||||
if (timeDiff(lastConnectMoment, last_wifi_connect_attempt_moment) > 0) {
|
||||
// There was an unsuccessful connection attempt
|
||||
lastConnectedDuration = timeDiff(last_wifi_connect_attempt_moment, lastDisconnectMoment);
|
||||
} else
|
||||
lastConnectedDuration = timeDiff(lastConnectMoment, lastDisconnectMoment);
|
||||
lastDisconnectReason = event.reason;
|
||||
wifiStatus = ESPEASY_WIFI_DISCONNECTED;
|
||||
processedDisconnect = false;
|
||||
}
|
||||
|
||||
void onGotIP(const WiFiEventStationModeGotIP& event){
|
||||
markGotIP();
|
||||
}
|
||||
|
||||
void onConnectedAPmode(const WiFiEventSoftAPModeStationConnected& event) {
|
||||
for (byte i = 0; i < 6; ++i) {
|
||||
lastMacConnectedAPmode[i] = event.mac[i];
|
||||
}
|
||||
processedConnectAPmode = false;
|
||||
}
|
||||
|
||||
void onDisonnectedAPmode(const WiFiEventSoftAPModeStationDisconnected& event) {
|
||||
for (byte i = 0; i < 6; ++i) {
|
||||
lastMacDisconnectedAPmode[i] = event.mac[i];
|
||||
}
|
||||
processedDisconnectAPmode = false;
|
||||
}
|
||||
|
||||
void onScanFinished(int networksFound) {
|
||||
lastGetScanMoment = millis();
|
||||
scan_done_number = networksFound;
|
||||
processedScanDone = false;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,822 @@
|
||||
|
||||
#define WIFI_AP_OFF_TIMER_DURATION 60000 // in milliSeconds
|
||||
|
||||
//********************************************************************************
|
||||
// Functions to process the data gathered from the events.
|
||||
// These functions are called from Setup() or Loop() and thus may call delay() or yield()
|
||||
//********************************************************************************
|
||||
void processConnect() {
|
||||
if (processedConnect) return;
|
||||
processedConnect = true;
|
||||
++wifi_reconnects;
|
||||
if (wifiStatus < ESPEASY_WIFI_CONNECTED) return;
|
||||
const long connect_duration = timeDiff(last_wifi_connect_attempt_moment, lastConnectMoment);
|
||||
String log = F("WIFI : Connected! AP: ");
|
||||
log += WiFi.SSID();
|
||||
log += F(" (");
|
||||
log += WiFi.BSSIDstr();
|
||||
log += F(") Ch: ");
|
||||
log += last_channel;
|
||||
if (connect_duration > 0 && connect_duration < 30000) {
|
||||
// Just log times when they make sense.
|
||||
log += F(" Duration: ");
|
||||
log += connect_duration;
|
||||
log += F(" ms");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
if (Settings.UseRules && bssid_changed) {
|
||||
String event = F("WiFi#ChangedAccesspoint");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
if (useStaticIP()) {
|
||||
setupStaticIPconfig();
|
||||
markGotIP();
|
||||
}
|
||||
logConnectionStatus();
|
||||
}
|
||||
|
||||
void processDisconnect() {
|
||||
if (processedDisconnect) return;
|
||||
processedDisconnect = true;
|
||||
if (Settings.UseRules) {
|
||||
String event = F("WiFi#Disconnected");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
String log = F("WIFI : Disconnected! Reason: '");
|
||||
log += getLastDisconnectReason();
|
||||
log += F("'");
|
||||
if (lastConnectedDuration > 0) {
|
||||
log += F(" Connected for ");
|
||||
log += format_msec_duration(lastConnectedDuration);
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
logConnectionStatus();
|
||||
}
|
||||
|
||||
|
||||
void processGotIP() {
|
||||
if (processedGetIP)
|
||||
return;
|
||||
IPAddress ip = WiFi.localIP();
|
||||
if (!useStaticIP())
|
||||
if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0)
|
||||
return;
|
||||
processedGetIP = true;
|
||||
const IPAddress gw = WiFi.gatewayIP();
|
||||
const IPAddress subnet = WiFi.subnetMask();
|
||||
String log = F("WIFI : ");
|
||||
if (useStaticIP()) {
|
||||
log += F("Static IP: ");
|
||||
} else {
|
||||
log += F("DHCP IP: ");
|
||||
}
|
||||
log += formatIP(ip);
|
||||
log += F(" (");
|
||||
log += WifiGetHostname();
|
||||
log += F(") GW: ");
|
||||
log += formatIP(gw);
|
||||
log += F(" SN: ");
|
||||
log += formatIP(subnet);
|
||||
|
||||
const long dhcp_duration = timeDiff(lastConnectMoment, lastGetIPmoment);
|
||||
if (dhcp_duration > 0 && dhcp_duration < 30000) {
|
||||
// Just log times when they make sense.
|
||||
log += F(" duration: ");
|
||||
log += dhcp_duration;
|
||||
log += F(" ms");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
// fix octet?
|
||||
if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255)
|
||||
{
|
||||
ip[3] = Settings.IP_Octet;
|
||||
log = F("IP : Fixed IP octet:");
|
||||
log += formatIP(ip);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
WiFi.config(ip, gw, subnet);
|
||||
}
|
||||
|
||||
#ifdef FEATURE_MDNS
|
||||
|
||||
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();
|
||||
}
|
||||
mqtt_reconnect_count = 0;
|
||||
timermqtt_interval = 100;
|
||||
timermqtt = millis() + timermqtt_interval;
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
String event = F("WiFi#Connected");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
statusLED(true);
|
||||
// WiFi.scanDelete();
|
||||
wifiStatus = ESPEASY_WIFI_SERVICES_INITIALIZED;
|
||||
setWebserverRunning(true);
|
||||
wifi_connect_attempt = 0;
|
||||
if (wifiSetup) {
|
||||
// Wifi setup was active, Apparently these settings work.
|
||||
wifiSetup = false;
|
||||
SaveSettings();
|
||||
}
|
||||
logConnectionStatus();
|
||||
}
|
||||
|
||||
void processConnectAPmode() {
|
||||
if (processedConnectAPmode) return;
|
||||
processedConnectAPmode = true;
|
||||
String log = F("AP Mode: Client connected: ");
|
||||
log += formatMAC(lastMacConnectedAPmode);
|
||||
log += F(" Connected devices: ");
|
||||
log += WiFi.softAPgetStationNum();
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
timerAPoff = 0; // Disable timer to switch AP off
|
||||
setWebserverRunning(true);
|
||||
// Start DNS, only used if the ESP has no valid WiFi config
|
||||
// It will reply with it's own address on all DNS requests
|
||||
// (captive portal concept)
|
||||
if (!dnsServerActive) {
|
||||
dnsServerActive = true;
|
||||
dnsServer.start(DNS_PORT, "*", apIP);
|
||||
}
|
||||
}
|
||||
|
||||
void processDisconnectAPmode() {
|
||||
if (processedDisconnectAPmode) return;
|
||||
processedDisconnectAPmode = true;
|
||||
const int nrStationsConnected = WiFi.softAPgetStationNum();
|
||||
String log = F("AP Mode: Client disconnected: ");
|
||||
log += formatMAC(lastMacDisconnectedAPmode);
|
||||
log += F(" Connected devices: ");
|
||||
log += nrStationsConnected;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
if (nrStationsConnected == 0) {
|
||||
timerAPoff = millis() + WIFI_AP_OFF_TIMER_DURATION;
|
||||
}
|
||||
}
|
||||
|
||||
void processDisableAPmode() {
|
||||
if (timerAPoff == 0) return;
|
||||
if (WifiIsAP(WiFi.getMode())) {
|
||||
// disable AP after timeout.
|
||||
if (timeOutReached(timerAPoff)) {
|
||||
setAP(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processScanDone() {
|
||||
if (processedScanDone) return;
|
||||
processedScanDone = true;
|
||||
String log = F("WIFI : Scan finished, found: ");
|
||||
log += scan_done_number;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
int bestScanID = -1;
|
||||
int32_t bestRssi = -1000;
|
||||
uint8_t bestWiFiSettings = lastWiFiSettings;
|
||||
if (selectValidWiFiSettings()) {
|
||||
bool done = false;
|
||||
String lastWiFiSettingsSSID = getLastWiFiSettingsSSID();
|
||||
for (int settingNr = 0; !done && settingNr < 2; ++settingNr) {
|
||||
for (int i = 0; i < scan_done_number; ++i) {
|
||||
if (WiFi.SSID(i) == lastWiFiSettingsSSID) {
|
||||
int32_t rssi = WiFi.RSSI(i);
|
||||
if (bestRssi < rssi) {
|
||||
bestRssi = rssi;
|
||||
bestScanID = i;
|
||||
bestWiFiSettings = lastWiFiSettings;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!selectNextWiFiSettings()) done = true;
|
||||
}
|
||||
if (bestScanID >= 0) {
|
||||
log = F("WIFI : Selected: ");
|
||||
log += formatScanResult(bestScanID, " ");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
lastWiFiSettings = bestWiFiSettings;
|
||||
uint8_t * scanbssid = WiFi.BSSID(bestScanID);
|
||||
if (scanbssid) {
|
||||
for (int i = 0; i < 6 ; ++i) {
|
||||
lastBSSID[i] = *(scanbssid + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resetWiFi() {
|
||||
addLog(LOG_LEVEL_INFO, F("Reset WiFi."));
|
||||
setWifiMode(WIFI_OFF);
|
||||
setWifiMode(WIFI_STA);
|
||||
lastDisconnectMoment = millis();
|
||||
processedDisconnect = false;
|
||||
wifiStatus = ESPEASY_WIFI_DISCONNECTED;
|
||||
}
|
||||
|
||||
void WifiScanAsync() {
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : Start network scan"));
|
||||
#ifdef ESP32
|
||||
bool async = true;
|
||||
bool show_hidden = false;
|
||||
bool passive = false;
|
||||
uint32_t max_ms_per_chan = 300;
|
||||
WiFi.scanNetworks(async, show_hidden, passive, max_ms_per_chan);
|
||||
#else
|
||||
// 2.4.x only and it doesn't work like expected.
|
||||
// WiFi.scanNetworksAsync(onScanFinished);
|
||||
#endif
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// WiFi state
|
||||
//********************************************************************************
|
||||
// 0 Wifi off
|
||||
// 1 Start => STA
|
||||
// 2 Try connect => STA => successful, goto 7
|
||||
// 3 Connection fails => AP => no client in N seconds, goto 1
|
||||
// 4 Client connects => AP
|
||||
// 5 Credentials changed => STA_AP => goto 2
|
||||
// 6 Connect successful (AP on) => STA_AP => disable AP after N seconds, goto 8
|
||||
// 7 Connect successful => STA
|
||||
// 8 Disable AP after N seconds => STA
|
||||
//********************************************************************************
|
||||
|
||||
bool WifiIsAP(WiFiMode_t wifimode)
|
||||
{
|
||||
#if defined(ESP32)
|
||||
return (wifimode == WIFI_MODE_AP) || (wifimode == WIFI_MODE_APSTA);
|
||||
#else
|
||||
return (wifimode == WIFI_AP) || (wifimode == WIFI_AP_STA);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool WifiIsSTA(WiFiMode_t wifimode)
|
||||
{
|
||||
#if defined(ESP32)
|
||||
return ((wifimode & WIFI_MODE_STA) != 0);
|
||||
#else
|
||||
return ((wifimode & WIFI_STA) != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Set Wifi Mode
|
||||
//********************************************************************************
|
||||
void setSTA(bool enable) {
|
||||
switch(WiFi.getMode()) {
|
||||
case WIFI_OFF:
|
||||
if (enable) setWifiMode(WIFI_STA);
|
||||
break;
|
||||
case WIFI_STA:
|
||||
if (!enable) setWifiMode(WIFI_OFF);
|
||||
break;
|
||||
case WIFI_AP:
|
||||
if (enable) setWifiMode(WIFI_AP_STA);
|
||||
break;
|
||||
case WIFI_AP_STA:
|
||||
if (!enable) setWifiMode(WIFI_AP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void setAP(bool enable) {
|
||||
switch(WiFi.getMode()) {
|
||||
case WIFI_OFF:
|
||||
if (enable) setWifiMode(WIFI_AP);
|
||||
break;
|
||||
case WIFI_STA:
|
||||
if (enable) setWifiMode(WIFI_AP_STA);
|
||||
break;
|
||||
case WIFI_AP:
|
||||
if (!enable) setWifiMode(WIFI_OFF);
|
||||
break;
|
||||
case WIFI_AP_STA:
|
||||
if (!enable) setWifiMode(WIFI_STA);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (enable) {
|
||||
timerAPoff = millis() + WIFI_AP_OFF_TIMER_DURATION;
|
||||
// create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password!
|
||||
// setup ssid for AP Mode when needed
|
||||
String softAPSSID=WifiGetAPssid();
|
||||
String pwd = SecuritySettings.WifiAPKey;
|
||||
IPAddress subnet(DEFAULT_AP_SUBNET);
|
||||
if (!WiFi.softAPConfig(apIP, apIP, subnet)) {
|
||||
addLog(LOG_LEVEL_ERROR, "WIFI : [AP] softAPConfig failed!");
|
||||
}
|
||||
if (WiFi.softAP(softAPSSID.c_str(),pwd.c_str())) {
|
||||
String log("WIFI : AP Mode ssid will be ");
|
||||
log += softAPSSID;
|
||||
log += F(" with address ");
|
||||
log += WiFi.softAPIP().toString();
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
} else {
|
||||
String log("WIFI : Error while starting AP Mode with SSID: ");
|
||||
log += softAPSSID;
|
||||
log += F(" IP: ");
|
||||
log += apIP.toString();
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
}
|
||||
#ifdef ESP32
|
||||
|
||||
#else
|
||||
if(wifi_softap_dhcps_status() != DHCP_STARTED) {
|
||||
if(!wifi_softap_dhcps_start()) {
|
||||
addLog(LOG_LEVEL_ERROR, "WIFI : [AP] wifi_softap_dhcps_start failed!");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
timerAPoff = 0; // Disable timer to switch AP off
|
||||
if (dnsServerActive) {
|
||||
dnsServerActive = false;
|
||||
dnsServer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setWifiMode(WiFiMode_t wifimode) {
|
||||
if (WiFi.getMode() == wifimode) {
|
||||
return;
|
||||
}
|
||||
switch (wifimode) {
|
||||
case WIFI_OFF:
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : Switch off WiFi"));
|
||||
break;
|
||||
case WIFI_STA:
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : Set WiFi to STA"));
|
||||
break;
|
||||
case WIFI_AP:
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : Set WiFi to AP"));
|
||||
break;
|
||||
case WIFI_AP_STA:
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : Set WiFi to AP+STA"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
setUseStaticIP(useStaticIP());
|
||||
WiFi.mode(wifimode);
|
||||
delay(30); // Must allow for some time to init.
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Determine Wifi AP name to set. (also used for mDNS)
|
||||
//********************************************************************************
|
||||
String WifiGetAPssid()
|
||||
{
|
||||
String ssid(Settings.Name);
|
||||
ssid+=F("_");
|
||||
ssid+=Settings.Unit;
|
||||
return (ssid);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Determine hostname: basically WifiGetAPssid with spaces changed to -
|
||||
//********************************************************************************
|
||||
String WifiGetHostname()
|
||||
{
|
||||
String hostname(WifiGetAPssid());
|
||||
hostname.replace(F(" "), F("-"));
|
||||
hostname.replace(F("_"), F("-")); // See RFC952
|
||||
return (hostname);
|
||||
}
|
||||
|
||||
|
||||
bool useStaticIP() {
|
||||
return (Settings.IP[0] != 0 && Settings.IP[0] != 255);
|
||||
}
|
||||
|
||||
bool WiFiConnected() {
|
||||
// For ESP82xx, do not rely on WiFi.status() with event based wifi.
|
||||
return wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED;
|
||||
}
|
||||
|
||||
void WiFiConnectRelaxed() {
|
||||
if (WiFiConnected())
|
||||
return; //already connected, need to disconnect first
|
||||
if (prepareWiFi()) {
|
||||
if (selectValidWiFiSettings()) {
|
||||
tryConnectWiFi();
|
||||
return;
|
||||
}
|
||||
}
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP!"));
|
||||
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
|
||||
setAP(true);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Set Wifi config
|
||||
//********************************************************************************
|
||||
bool prepareWiFi() {
|
||||
if (!selectValidWiFiSettings()) {
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : No valid wifi settings"));
|
||||
return false;
|
||||
}
|
||||
setSTA(true);
|
||||
String log = "";
|
||||
char hostname[40];
|
||||
strncpy(hostname, WifiGetHostname().c_str(), sizeof(hostname));
|
||||
#if defined(ESP8266)
|
||||
wifi_station_set_hostname(hostname);
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
WiFi.setHostname(hostname);
|
||||
#endif
|
||||
return 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 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; // Allow for empty pass
|
||||
if (strlen(ssid) > 32) return false;
|
||||
if (strlen(pass) > 64) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wifiConnectTimeoutReached() {
|
||||
if (wifi_connect_attempt == 0) return true;
|
||||
if (timeDiff(last_wifi_connect_attempt_moment, lastDisconnectMoment) >0 ) {
|
||||
// Connection attempt was already ended.
|
||||
return true;
|
||||
}
|
||||
if (WifiIsAP(WiFi.getMode())) {
|
||||
// Initial setup of WiFi, may take much longer since accesspoint is still active.
|
||||
return timeOutReached(last_wifi_connect_attempt_moment + 20000);
|
||||
}
|
||||
// wait until it connects + add some device specific random offset to prevent
|
||||
// all nodes overloading the accesspoint when turning on at the same time.
|
||||
#if defined(ESP8266)
|
||||
const unsigned int randomOffset_in_sec = wifi_connect_attempt == 1 ? 0 : 1000 * ((ESP.getChipId() & 0xF));
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
const unsigned int randomOffset_in_sec = wifi_connect_attempt == 1 ? 0 : 1000 * ((ESP.getEfuseMac() & 0xF));
|
||||
#endif
|
||||
return timeOutReached(last_wifi_connect_attempt_moment + DEFAULT_WIFI_CONNECTION_TIMEOUT + randomOffset_in_sec);
|
||||
}
|
||||
|
||||
void setupStaticIPconfig() {
|
||||
setUseStaticIP(useStaticIP());
|
||||
if (!useStaticIP()) return;
|
||||
const IPAddress ip = Settings.IP;
|
||||
const IPAddress gw = Settings.Gateway;
|
||||
const IPAddress subnet = Settings.Subnet;
|
||||
const IPAddress dns = Settings.DNS;
|
||||
String log = F("IP : Static IP : ");
|
||||
log += formatIP(ip);
|
||||
log += F(" GW: ");
|
||||
log += formatIP(gw);
|
||||
log += F(" SN: ");
|
||||
log += formatIP(subnet);
|
||||
log += F(" DNS: ");
|
||||
log += formatIP(dns);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
WiFi.config(ip, gw, subnet, dns);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Simply start the WiFi connection sequence
|
||||
//********************************************************************************
|
||||
bool tryConnectWiFi() {
|
||||
if (wifiSetupConnect) {
|
||||
lastWiFiSettings = 0; // Force to load the first settings.
|
||||
wifi_connect_attempt = 0;
|
||||
}
|
||||
if (wifiStatus != ESPEASY_WIFI_DISCONNECTED) {
|
||||
if (!WifiIsAP(WiFi.getMode())) {
|
||||
// Only when not in AP mode.
|
||||
return(true); //already connected, need to disconnect first
|
||||
}
|
||||
}
|
||||
if (!wifiConnectTimeoutReached())
|
||||
return true; // timeout not reached yet, thus no need to retry again.
|
||||
if (!selectValidWiFiSettings()) {
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : No valid WiFi settings!"));
|
||||
return false;
|
||||
}
|
||||
if (wifi_connect_attempt != 0 && (wifi_connect_attempt % 2) == 0) {
|
||||
selectNextWiFiSettings();
|
||||
}
|
||||
if (wifi_connect_attempt > 5) {
|
||||
setAP(true);
|
||||
}
|
||||
const char* ssid = getLastWiFiSettingsSSID();
|
||||
const char* passphrase = getLastWiFiSettingsPassphrase();
|
||||
String log = F("WIFI : Connecting ");
|
||||
log += ssid;
|
||||
log += F(" attempt #");
|
||||
log += wifi_connect_attempt;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
setupStaticIPconfig();
|
||||
last_wifi_connect_attempt_moment = millis();
|
||||
switch (wifi_connect_attempt) {
|
||||
case 0:
|
||||
if (lastBSSID[0] == 0)
|
||||
WiFi.begin(ssid, passphrase);
|
||||
else
|
||||
WiFi.begin(ssid, passphrase, 0, &lastBSSID[0]);
|
||||
break;
|
||||
default:
|
||||
WiFi.begin(ssid, passphrase);
|
||||
}
|
||||
++wifi_connect_attempt;
|
||||
logConnectionStatus();
|
||||
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;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true; // Sent
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Disconnect from Wifi AP
|
||||
//********************************************************************************
|
||||
void WifiDisconnect()
|
||||
{
|
||||
#if defined(ESP32)
|
||||
WiFi.disconnect();
|
||||
#else
|
||||
ETS_UART_INTR_DISABLE();
|
||||
wifi_station_disconnect();
|
||||
ETS_UART_INTR_ENABLE();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Scan all Wifi Access Points
|
||||
//********************************************************************************
|
||||
void WifiScan()
|
||||
{
|
||||
// Direct Serial is allowed here, since this function will only be called from serial input.
|
||||
Serial.println(F("WIFI : SSID Scan start"));
|
||||
int n = WiFi.scanNetworks(false, true);
|
||||
if (n == 0)
|
||||
Serial.println(F("WIFI : No networks found"));
|
||||
else
|
||||
{
|
||||
Serial.print(F("WIFI : "));
|
||||
Serial.print(n);
|
||||
Serial.println(F(" networks found"));
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
// Print SSID and RSSI for each network found
|
||||
Serial.print(F("WIFI : "));
|
||||
Serial.print(i + 1);
|
||||
Serial.print(": ");
|
||||
Serial.println(formatScanResult(i, " "));
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
String formatScanResult(int i, const String& separator) {
|
||||
String result = WiFi.SSID(i);
|
||||
#ifndef ESP32
|
||||
if (WiFi.isHidden(i)) {
|
||||
result += F("#Hidden#");
|
||||
}
|
||||
#endif
|
||||
result += separator;
|
||||
result += WiFi.BSSIDstr(i);
|
||||
result += separator;
|
||||
result += F("Ch:");
|
||||
result += WiFi.channel(i);
|
||||
result += F(" (");
|
||||
result += WiFi.RSSI(i);
|
||||
result += F("dBm) ");
|
||||
switch (WiFi.encryptionType(i)) {
|
||||
#ifdef ESP32
|
||||
case WIFI_AUTH_OPEN: result += F("open"); break;
|
||||
case WIFI_AUTH_WEP: result += F("WEP"); break;
|
||||
case WIFI_AUTH_WPA_PSK: result += F("WPA/PSK"); break;
|
||||
case WIFI_AUTH_WPA2_PSK: result += F("WPA2/PSK"); break;
|
||||
case WIFI_AUTH_WPA_WPA2_PSK: result += F("WPA/WPA2/PSK"); break;
|
||||
case WIFI_AUTH_WPA2_ENTERPRISE: result += F("WPA2 Enterprise"); break;
|
||||
#else
|
||||
case ENC_TYPE_WEP: result += F("WEP"); break;
|
||||
case ENC_TYPE_TKIP: result += F("WPA/PSK"); break;
|
||||
case ENC_TYPE_CCMP: result += F("WPA2/PSK"); break;
|
||||
case ENC_TYPE_NONE: result += F("open"); break;
|
||||
case ENC_TYPE_AUTO: result += F("WPA/WPA2/PSK"); break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef ESP32
|
||||
String SDKwifiStatusToString(uint8_t sdk_wifistatus) {
|
||||
switch (sdk_wifistatus) {
|
||||
case STATION_IDLE: return F("STATION_IDLE");
|
||||
case STATION_CONNECTING: return F("STATION_CONNECTING");
|
||||
case STATION_WRONG_PASSWORD: return F("STATION_WRONG_PASSWORD");
|
||||
case STATION_NO_AP_FOUND: return F("STATION_NO_AP_FOUND");
|
||||
case STATION_CONNECT_FAIL: return F("STATION_CONNECT_FAIL");
|
||||
case STATION_GOT_IP: return F("STATION_GOT_IP");
|
||||
}
|
||||
return F("Unknown");
|
||||
}
|
||||
#endif
|
||||
|
||||
String ArduinoWifiStatusToString(uint8_t arduino_corelib_wifistatus) {
|
||||
String log;
|
||||
switch (arduino_corelib_wifistatus) {
|
||||
case WL_IDLE_STATUS: log += F("WL_IDLE_STATUS"); break;
|
||||
case WL_NO_SSID_AVAIL: log += F("WL_NO_SSID_AVAIL"); break;
|
||||
case WL_SCAN_COMPLETED: log += F("WL_SCAN_COMPLETED"); break;
|
||||
case WL_CONNECTED: log += F("WL_CONNECTED"); break;
|
||||
case WL_CONNECT_FAILED: log += F("WL_CONNECT_FAILED"); break;
|
||||
case WL_CONNECTION_LOST: log += F("WL_CONNECTION_LOST"); break;
|
||||
case WL_DISCONNECTED: log += F("WL_DISCONNECTED"); break;
|
||||
default: log += arduino_corelib_wifistatus; break;
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
String ESPeasyWifiStatusToString() {
|
||||
String log;
|
||||
switch (wifiStatus) {
|
||||
case ESPEASY_WIFI_DISCONNECTED: log += F("ESPEASY_WIFI_DISCONNECTED"); break;
|
||||
case ESPEASY_WIFI_CONNECTED: log += F("ESPEASY_WIFI_CONNECTED"); break;
|
||||
case ESPEASY_WIFI_GOT_IP: log += F("ESPEASY_WIFI_GOT_IP"); break;
|
||||
case ESPEASY_WIFI_SERVICES_INITIALIZED: log += F("ESPEASY_WIFI_SERVICES_INITIALIZED"); break;
|
||||
default: log += wifiStatus;
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
void logConnectionStatus() {
|
||||
const uint8_t arduino_corelib_wifistatus = WiFi.status();
|
||||
String log;
|
||||
#ifndef ESP32
|
||||
const uint8_t sdk_wifistatus = wifi_station_get_connect_status();
|
||||
if ((arduino_corelib_wifistatus == WL_CONNECTED) != (sdk_wifistatus == STATION_GOT_IP)) {
|
||||
log = F("WIFI : SDK station status differs from Arduino status. SDK-status: ");
|
||||
log += SDKwifiStatusToString(sdk_wifistatus);
|
||||
log += F(" Arduino status: ");
|
||||
log += ArduinoWifiStatusToString(arduino_corelib_wifistatus);
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
}
|
||||
#endif
|
||||
log = F("WIFI : Arduino wifi status: ");
|
||||
log += ArduinoWifiStatusToString(arduino_corelib_wifistatus);
|
||||
log += F(" ESPeasy internal wifi status: ");
|
||||
log += ESPeasyWifiStatusToString();
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Check if we are still connected to a Wifi AP
|
||||
//********************************************************************************
|
||||
void WifiCheck()
|
||||
{
|
||||
if(wifiSetup)
|
||||
return;
|
||||
|
||||
processDisableAPmode();
|
||||
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
if (timeOutReached(last_wifi_connect_attempt_moment + (1000 + wifi_connect_attempt * 200))) {
|
||||
WiFiConnectRelaxed();
|
||||
}
|
||||
}
|
||||
if (mqtt_reconnect_count > 10) {
|
||||
connectionCheckHandler();
|
||||
}
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Return subnet range of WiFi.
|
||||
//********************************************************************************
|
||||
bool getSubnetRange(IPAddress& low, IPAddress& high)
|
||||
{
|
||||
if (WifiIsAP(WiFi.getMode())) {
|
||||
// WiFi is active as accesspoint, do not check.
|
||||
return false;
|
||||
}
|
||||
if (wifiStatus < ESPEASY_WIFI_GOT_IP) {
|
||||
return false;
|
||||
}
|
||||
const IPAddress ip = WiFi.localIP();
|
||||
const IPAddress subnet = WiFi.subnetMask();
|
||||
low = ip;
|
||||
high = ip;
|
||||
// Compute subnet range.
|
||||
for (byte i=0; i < 4; ++i) {
|
||||
if (subnet[i] != 255) {
|
||||
low[i] = low[i] & subnet[i];
|
||||
high[i] = high[i] | ~subnet[i];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
String getLastDisconnectReason() {
|
||||
String reason = F("(");
|
||||
reason += lastDisconnectReason;
|
||||
reason += F(") ");
|
||||
switch (lastDisconnectReason) {
|
||||
case WIFI_DISCONNECT_REASON_UNSPECIFIED: reason += F("Unspecified"); break;
|
||||
case WIFI_DISCONNECT_REASON_AUTH_EXPIRE: reason += F("Auth expire"); break;
|
||||
case WIFI_DISCONNECT_REASON_AUTH_LEAVE: reason += F("Auth leave"); break;
|
||||
case WIFI_DISCONNECT_REASON_ASSOC_EXPIRE: reason += F("Assoc expire"); break;
|
||||
case WIFI_DISCONNECT_REASON_ASSOC_TOOMANY: reason += F("Assoc toomany"); break;
|
||||
case WIFI_DISCONNECT_REASON_NOT_AUTHED: reason += F("Not authed"); break;
|
||||
case WIFI_DISCONNECT_REASON_NOT_ASSOCED: reason += F("Not assoced"); break;
|
||||
case WIFI_DISCONNECT_REASON_ASSOC_LEAVE: reason += F("Assoc leave"); break;
|
||||
case WIFI_DISCONNECT_REASON_ASSOC_NOT_AUTHED: reason += F("Assoc not authed"); break;
|
||||
case WIFI_DISCONNECT_REASON_DISASSOC_PWRCAP_BAD: reason += F("Disassoc pwrcap bad"); break;
|
||||
case WIFI_DISCONNECT_REASON_DISASSOC_SUPCHAN_BAD: reason += F("Disassoc supchan bad"); break;
|
||||
case WIFI_DISCONNECT_REASON_IE_INVALID: reason += F("IE invalid"); break;
|
||||
case WIFI_DISCONNECT_REASON_MIC_FAILURE: reason += F("Mic failure"); break;
|
||||
case WIFI_DISCONNECT_REASON_4WAY_HANDSHAKE_TIMEOUT: reason += F("4way handshake timeout"); break;
|
||||
case WIFI_DISCONNECT_REASON_GROUP_KEY_UPDATE_TIMEOUT: reason += F("Group key update timeout"); break;
|
||||
case WIFI_DISCONNECT_REASON_IE_IN_4WAY_DIFFERS: reason += F("IE in 4way differs"); break;
|
||||
case WIFI_DISCONNECT_REASON_GROUP_CIPHER_INVALID: reason += F("Group cipher invalid"); break;
|
||||
case WIFI_DISCONNECT_REASON_PAIRWISE_CIPHER_INVALID: reason += F("Pairwise cipher invalid"); break;
|
||||
case WIFI_DISCONNECT_REASON_AKMP_INVALID: reason += F("AKMP invalid"); break;
|
||||
case WIFI_DISCONNECT_REASON_UNSUPP_RSN_IE_VERSION: reason += F("Unsupp RSN IE version"); break;
|
||||
case WIFI_DISCONNECT_REASON_INVALID_RSN_IE_CAP: reason += F("Invalid RSN IE cap"); break;
|
||||
case WIFI_DISCONNECT_REASON_802_1X_AUTH_FAILED: reason += F("802 1X auth failed"); break;
|
||||
case WIFI_DISCONNECT_REASON_CIPHER_SUITE_REJECTED: reason += F("Cipher suite rejected"); break;
|
||||
case WIFI_DISCONNECT_REASON_BEACON_TIMEOUT: reason += F("Beacon timeout"); break;
|
||||
case WIFI_DISCONNECT_REASON_NO_AP_FOUND: reason += F("No AP found"); break;
|
||||
case WIFI_DISCONNECT_REASON_AUTH_FAIL: reason += F("Auth fail"); break;
|
||||
case WIFI_DISCONNECT_REASON_ASSOC_FAIL: reason += F("Assoc fail"); break;
|
||||
case WIFI_DISCONNECT_REASON_HANDSHAKE_TIMEOUT: reason += F("Handshake timeout"); break;
|
||||
default: reason += F("Unknown"); break;
|
||||
}
|
||||
return reason;
|
||||
}
|
||||
+36
-5
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************************\
|
||||
* Initialize specific hardware setings (only global ones, others are set through devices)
|
||||
* Initialize specific hardware settings (only global ones, others are set through devices)
|
||||
\*********************************************************************************************/
|
||||
|
||||
void hardwareInit()
|
||||
@@ -26,6 +26,9 @@ void hardwareInit()
|
||||
break;
|
||||
}
|
||||
|
||||
if (Settings.Pin_Reset != -1)
|
||||
pinMode(Settings.Pin_Reset,INPUT_PULLUP);
|
||||
|
||||
// configure hardware pins according to eeprom settings.
|
||||
if (Settings.Pin_i2c_sda != -1)
|
||||
{
|
||||
@@ -37,7 +40,9 @@ void hardwareInit()
|
||||
String log = F("INIT : I2C custom clockstretchlimit:");
|
||||
log += Settings.WireClockStretchLimit;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
Wire.setClockStretchLimit(Settings.WireClockStretchLimit);
|
||||
#if defined(ESP8266)
|
||||
Wire.setClockStretchLimit(Settings.WireClockStretchLimit);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +54,7 @@ void hardwareInit()
|
||||
Wire.write(0x83); // command to set pointer
|
||||
Wire.write(17); // pointer value to status byte
|
||||
Wire.endTransmission();
|
||||
|
||||
|
||||
Wire.requestFrom(Settings.WDI2CAddress, (uint8_t)1);
|
||||
if (Wire.available())
|
||||
{
|
||||
@@ -62,7 +67,7 @@ void hardwareInit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// SPI Init
|
||||
if (Settings.InitSPI)
|
||||
{
|
||||
@@ -77,7 +82,8 @@ void hardwareInit()
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
|
||||
if (Settings.Pin_sd_cs > 0)
|
||||
#ifdef FEATURE_SD
|
||||
if (Settings.Pin_sd_cs >= 0)
|
||||
{
|
||||
if (SD.begin(Settings.Pin_sd_cs))
|
||||
{
|
||||
@@ -90,6 +96,31 @@ void hardwareInit()
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void checkResetFactoryPin(){
|
||||
static byte factoryResetCounter=0;
|
||||
if (Settings.Pin_Reset == -1)
|
||||
return;
|
||||
|
||||
if (digitalRead(Settings.Pin_Reset) == 0){ // active low reset pin
|
||||
factoryResetCounter++; // just count every second
|
||||
}
|
||||
else
|
||||
{ // reset pin released
|
||||
if (factoryResetCounter > 9) // factory reset and reboot
|
||||
ResetFactory();
|
||||
if (factoryResetCounter > 3) // normal reboot
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
ESP.restart();
|
||||
#endif
|
||||
|
||||
factoryResetCounter = 0; // count was < 3, reset counter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+890
-160
File diff suppressed because it is too large
Load Diff
+224
@@ -0,0 +1,224 @@
|
||||
|
||||
# ifndef MODBUS_H
|
||||
# define MODBUS_H
|
||||
|
||||
enum MODBUS_states_t {MODBUS_IDLE, MODBUS_RECEIVE, MODBUS_RECEIVE_PAYLOAD};
|
||||
enum MODBUS_registerTypes_t {signed16, unsigned16, signed32, unsigned32, signed64, unsigned64};
|
||||
|
||||
#define MODBUS_FUNCTION_READ 4
|
||||
|
||||
class Modbus
|
||||
{
|
||||
public:
|
||||
Modbus(void);
|
||||
bool handle();
|
||||
bool begin(uint8_t function, uint8_t ModbusID, uint16_t ModbusRegister, MODBUS_registerTypes_t type, char* IPaddress);
|
||||
double read() {
|
||||
if (resultReceived) {
|
||||
resultReceived = false;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
};
|
||||
bool available() {
|
||||
return resultReceived;
|
||||
};
|
||||
unsigned int getReadErrors() {
|
||||
return errcnt;
|
||||
};
|
||||
void resetReadErrors() {
|
||||
errcnt = 0;
|
||||
};
|
||||
void stop() {
|
||||
TXRXstate = MODBUS_IDLE;
|
||||
handle();
|
||||
};
|
||||
bool tryRead (uint8_t ModbusID, uint16_t M_register, MODBUS_registerTypes_t type, char* IPaddress, double &result);
|
||||
|
||||
private:
|
||||
WiFiClient *ModbusClient; // pointer to tcp client
|
||||
unsigned int errcnt;
|
||||
char sendBuffer[12] = {0, 1, 0, 0, 0, 6, 0x7e, 4, 0x9d, 7, 0, 1};
|
||||
String LogString = ""; // for debug logging
|
||||
unsigned long timeout; // send and read timeout
|
||||
MODBUS_states_t TXRXstate;// state for handle() state machine
|
||||
unsigned int RXavailable;
|
||||
unsigned int payLoad; // number of bytes to receive as payload. Payload may come as seperate frame.
|
||||
bool hasTimeout();
|
||||
MODBUS_registerTypes_t incomingValue; // how to interpret the incoming value
|
||||
double result; // incoming value, converted to double
|
||||
bool resultReceived; // incoming value is valid ?
|
||||
bool isBusy(void) {
|
||||
return TXRXstate != MODBUS_IDLE;
|
||||
};
|
||||
uint16_t currentRegister;
|
||||
uint8_t currentFunction;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
Modbus::Modbus() : ModbusClient(nullptr), errcnt(0), timeout(0),
|
||||
TXRXstate(MODBUS_IDLE), RXavailable(0), payLoad(0) {}
|
||||
|
||||
bool Modbus::begin(uint8_t function, uint8_t ModbusID, uint16_t ModbusRegister, MODBUS_registerTypes_t type, char* IPaddress)
|
||||
{
|
||||
currentRegister = ModbusRegister;
|
||||
currentFunction = function;
|
||||
incomingValue = type;
|
||||
resultReceived = false;
|
||||
ModbusClient = new WiFiClient();
|
||||
ModbusClient->setNoDelay(true);
|
||||
ModbusClient->setTimeout(200);
|
||||
timeout = millis();
|
||||
ModbusClient->flush();
|
||||
|
||||
if (ModbusClient->connected()) {
|
||||
LogString += F(" already connected. ");
|
||||
} else {
|
||||
LogString += F("connect: "); LogString += IPaddress;
|
||||
if ( !ModbusClient->connect(IPaddress, 502)) {
|
||||
LogString += F(" fail. ");
|
||||
TXRXstate = MODBUS_IDLE;
|
||||
errcnt++;
|
||||
if (LogString.length() > 1 ) addLog(LOG_LEVEL_DEBUG, LogString);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
LogString += F(" OK, sending read request: ");
|
||||
|
||||
sendBuffer[6] = ModbusID ;
|
||||
sendBuffer[7] = function;
|
||||
sendBuffer[8] = (ModbusRegister >> 8) ;
|
||||
sendBuffer[9] = (ModbusRegister & 0x00ff) ;
|
||||
if ((incomingValue == signed64) || (incomingValue == unsigned64))
|
||||
sendBuffer[11] = 4;
|
||||
if ((incomingValue == signed32) || (incomingValue == unsigned32))
|
||||
sendBuffer[11] = 2;
|
||||
if ((incomingValue == signed16) || (incomingValue == unsigned16))
|
||||
sendBuffer[11] = 1;
|
||||
ModbusClient->flush();
|
||||
ModbusClient->write(&sendBuffer[0], sizeof(sendBuffer));
|
||||
for (unsigned int i = 0; i < sizeof(sendBuffer); i++) {
|
||||
LogString += ((unsigned int)(sendBuffer[i]));
|
||||
LogString += (" ");
|
||||
}
|
||||
TXRXstate = MODBUS_RECEIVE;
|
||||
if (LogString.length() > 1 ) addLog(LOG_LEVEL_DEBUG, LogString);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Modbus::handle() {
|
||||
unsigned int RXavailable = 0;
|
||||
LogString = "";
|
||||
int64_t rxValue = 0;
|
||||
switch ( TXRXstate ) {
|
||||
|
||||
case MODBUS_IDLE:
|
||||
// clean up;
|
||||
if (ModbusClient) {
|
||||
ModbusClient->flush();
|
||||
ModbusClient->stop();
|
||||
delete (ModbusClient);
|
||||
delay(1);
|
||||
ModbusClient = nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case MODBUS_RECEIVE:
|
||||
if (hasTimeout()) break;
|
||||
if (ModbusClient->available() < 9) break;
|
||||
|
||||
LogString += F("reading bytes: ");
|
||||
for (int a = 0; a < 9; a++) {
|
||||
payLoad = ModbusClient->read();
|
||||
LogString += (payLoad); LogString += F(" ");
|
||||
}
|
||||
LogString += F("> ");
|
||||
if (payLoad > 8) {
|
||||
LogString += "Payload too large !? ";
|
||||
errcnt++;
|
||||
TXRXstate = MODBUS_IDLE;
|
||||
}
|
||||
|
||||
case MODBUS_RECEIVE_PAYLOAD:
|
||||
if (hasTimeout()) break;
|
||||
RXavailable = ModbusClient->available();
|
||||
if (payLoad != RXavailable) {
|
||||
TXRXstate = MODBUS_RECEIVE_PAYLOAD;
|
||||
break;
|
||||
}
|
||||
for (unsigned int i = 0; i < RXavailable; i++) {
|
||||
rxValue = rxValue << 8;
|
||||
char a = ModbusClient->read();
|
||||
rxValue = rxValue | a;
|
||||
LogString += ((int)a); LogString += (" ");
|
||||
}
|
||||
switch (incomingValue) {
|
||||
case signed16:
|
||||
result = (int16_t) rxValue;
|
||||
break;
|
||||
case unsigned16:
|
||||
result = (uint16_t) rxValue;
|
||||
break;
|
||||
case signed32:
|
||||
result = (int32_t) rxValue;
|
||||
break;
|
||||
case unsigned32:
|
||||
result = (uint32_t) rxValue;
|
||||
break;
|
||||
case signed64:
|
||||
result = (int64_t) rxValue;
|
||||
break;
|
||||
case unsigned64:
|
||||
result = (uint64_t) rxValue;
|
||||
break;
|
||||
}
|
||||
|
||||
LogString += "value: "; LogString += result;
|
||||
//if ((Settings.UseNTP) && (hour() == 0)) errcnt = 0;
|
||||
|
||||
TXRXstate = MODBUS_IDLE;
|
||||
|
||||
resultReceived = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
LogString += F("default. ");
|
||||
TXRXstate = MODBUS_IDLE;
|
||||
break;
|
||||
|
||||
}
|
||||
if (LogString.length() > 1 ) addLog(LOG_LEVEL_DEBUG, LogString);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Modbus::hasTimeout()
|
||||
{
|
||||
if ( (millis() - timeout) > 10000) { // too many bytes or timeout
|
||||
LogString += F("Modbus RX timeout. "); LogString += String(ModbusClient->available());
|
||||
errcnt++;
|
||||
TXRXstate = MODBUS_IDLE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// tryread can be called in a round robin fashion. It will initiate a read if Modbus is idle and update the result once it is available.
|
||||
// subsequent calls (if Modbus is busy etc. ) will return false and not update the result.
|
||||
// Use to read multiple values non blocking in an re-entrant function. Not tested yet.
|
||||
bool Modbus::tryRead (uint8_t ModbusID, uint16_t M_register, MODBUS_registerTypes_t type, char* IPaddress, double &result) {
|
||||
if (isBusy()) return false; // not done yet
|
||||
if (available()) {
|
||||
if ((currentFunction == MODBUS_FUNCTION_READ ) && (currentRegister == M_register)) {
|
||||
result = read(); // result belongs to this request.
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
begin(MODBUS_FUNCTION_READ, ModbusID, M_register, type, IPaddress); // idle and no result -> begin read request
|
||||
}
|
||||
return false;
|
||||
}
|
||||
+55
-21
@@ -2,22 +2,34 @@
|
||||
// Syslog
|
||||
// UDP system messaging
|
||||
// SSDP
|
||||
// #if LWIP_VERSION_MAJOR == 2
|
||||
#define IPADDR2STR(addr) (uint8_t)((uint32_t)addr & 0xFF), (uint8_t)(((uint32_t)addr >> 8) & 0xFF), (uint8_t)(((uint32_t)addr >> 16) & 0xFF), (uint8_t)(((uint32_t)addr >> 24) & 0xFF)
|
||||
// #endif
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Syslog client
|
||||
\*********************************************************************************************/
|
||||
void syslog(const char *message)
|
||||
void syslog(byte logLevel, const char *message)
|
||||
{
|
||||
if (Settings.Syslog_IP[0] != 0 && WiFi.status() == WL_CONNECTED)
|
||||
if (Settings.Syslog_IP[0] != 0 && wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED)
|
||||
{
|
||||
IPAddress broadcastIP(Settings.Syslog_IP[0], Settings.Syslog_IP[1], Settings.Syslog_IP[2], Settings.Syslog_IP[3]);
|
||||
portUDP.beginPacket(broadcastIP, 514);
|
||||
char str[256];
|
||||
str[0] = 0;
|
||||
byte prio = Settings.SyslogFacility * 8;
|
||||
if ( logLevel == LOG_LEVEL_ERROR )
|
||||
prio += 3; // syslog error
|
||||
else if ( logLevel == LOG_LEVEL_INFO )
|
||||
prio += 5; // syslog notice
|
||||
else
|
||||
prio += 7;
|
||||
|
||||
// An RFC3164 compliant message must be formated like : "<PRIO>[TimeStamp ]Hostname TaskName: Message"
|
||||
|
||||
// Using Settings.Name as the Hostname (Hostname must NOT content space)
|
||||
snprintf_P(str, sizeof(str), PSTR("<7>%s EspEasy: %s"), Settings.Name, message);
|
||||
snprintf_P(str, sizeof(str), PSTR("<%u>%s EspEasy: %s"), prio, Settings.Name, message);
|
||||
|
||||
// Using Setting.Unit to build a Hostname
|
||||
//snprintf_P(str, sizeof(str), PSTR("<7>EspEasy_%u ESP: %s"), Settings.Unit, message);
|
||||
@@ -35,11 +47,17 @@ void syslog(const char *message)
|
||||
/*********************************************************************************************\
|
||||
Check UDP messages (ESPEasy propiertary protocol)
|
||||
\*********************************************************************************************/
|
||||
boolean runningUPDCheck = false;
|
||||
void checkUDP()
|
||||
{
|
||||
if (Settings.UDPPort == 0)
|
||||
return;
|
||||
|
||||
if (runningUPDCheck)
|
||||
return;
|
||||
|
||||
runningUPDCheck = true;
|
||||
|
||||
// UDP events
|
||||
int packetSize = portUDP.parsePacket();
|
||||
if (packetSize)
|
||||
@@ -50,6 +68,7 @@ void checkUDP()
|
||||
if (portUDP.remotePort() == 123)
|
||||
{
|
||||
// unexpected NTP reply, drop for now...
|
||||
runningUPDCheck = false;
|
||||
return;
|
||||
}
|
||||
char packetBuffer[128];
|
||||
@@ -99,9 +118,9 @@ void checkUDP()
|
||||
}
|
||||
|
||||
char macaddress[20];
|
||||
sprintf_P(macaddress, PSTR("%02x:%02x:%02x:%02x:%02x:%02x"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
char ipaddress[16];
|
||||
sprintf_P(ipaddress, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
formatMAC(mac, macaddress);
|
||||
char ipaddress[20];
|
||||
formatIP(ip, ipaddress);
|
||||
char log[80];
|
||||
sprintf_P(log, PSTR("UDP : %s,%s,%u"), macaddress, ipaddress, unit);
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
@@ -120,6 +139,10 @@ void checkUDP()
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined(ESP32) // testing
|
||||
portUDP.flush();
|
||||
#endif
|
||||
runningUPDCheck = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -253,7 +276,7 @@ void sendSysInfoUDP(byte repeats)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined(ESP8266)
|
||||
/********************************************************************************************\
|
||||
Respond to HTTP XML requests for SSDP information
|
||||
\*********************************************************************************************/
|
||||
@@ -262,10 +285,8 @@ void SSDP_schema(WiFiClient &client) {
|
||||
return;
|
||||
}
|
||||
|
||||
IPAddress ip = WiFi.localIP();
|
||||
char str[20];
|
||||
sprintf_P(str, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
uint32_t chipId = ESP.getChipId();
|
||||
const IPAddress ip = WiFi.localIP();
|
||||
const uint32_t chipId = ESP.getChipId();
|
||||
char uuid[64];
|
||||
sprintf_P(uuid, PSTR("38323636-4558-4dda-9188-cda0e6%02x%02x%02x"),
|
||||
(uint16_t) ((chipId >> 16) & 0xff),
|
||||
@@ -285,7 +306,7 @@ void SSDP_schema(WiFiClient &client) {
|
||||
"<minor>0</minor>"
|
||||
"</specVersion>"
|
||||
"<URLBase>http://");
|
||||
ssdp_schema += str;
|
||||
ssdp_schema += formatIP(ip);
|
||||
ssdp_schema += F(":80/</URLBase>"
|
||||
"<device>"
|
||||
"<deviceType>urn:schemas-upnp-org:device:BinaryLight:1</deviceType>"
|
||||
@@ -421,7 +442,7 @@ void SSDP_send(byte method) {
|
||||
SSDP_INTERVAL,
|
||||
Settings.Build,
|
||||
uuid,
|
||||
IP2STR(&ip)
|
||||
IPADDR2STR(&ip)
|
||||
);
|
||||
|
||||
_server->append(buffer, len);
|
||||
@@ -573,6 +594,7 @@ void SSDP_update() {
|
||||
_server->flush();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check WiFi connection. Maximum timeout 500 msec.
|
||||
bool WiFiConnected(uint32_t timeout_ms) {
|
||||
@@ -582,12 +604,10 @@ bool WiFiConnected(uint32_t timeout_ms) {
|
||||
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) {
|
||||
// Apparently something needs network, perform check to see if it is ready now.
|
||||
// if (!tryConnectWiFi())
|
||||
// return false;
|
||||
while (!WiFiConnected()) {
|
||||
if (timeOutReached(timer)) {
|
||||
return false;
|
||||
}
|
||||
@@ -597,23 +617,37 @@ bool WiFiConnected(uint32_t timeout_ms) {
|
||||
}
|
||||
|
||||
bool hostReachable(const IPAddress& ip) {
|
||||
if (!WiFiConnected()) return false;
|
||||
// Only do 1 ping at a time to return early
|
||||
byte retry = 3;
|
||||
while (retry > 0) {
|
||||
#if defined(ESP8266)
|
||||
if (Ping.ping(ip, 1)) return true;
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
if (ping_start(ip, 4, 0, 0, 5)) return true;
|
||||
#endif
|
||||
delay(50);
|
||||
--retry;
|
||||
}
|
||||
String log = F("Host unreachable: ");
|
||||
log += ip;
|
||||
log += formatIP(ip);
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
if (ip[1] == 0 && ip[2] == 0 && ip[3] == 0) {
|
||||
// Work-around to fix connected but not able to communicate.
|
||||
addLog(LOG_LEVEL_ERROR, F("Wifi : Detected strange behavior, reconnect wifi."));
|
||||
WifiDisconnect();
|
||||
}
|
||||
logConnectionStatus();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hostReachable(const String& hostname) {
|
||||
if (!WiFiConnected()) return false;
|
||||
IPAddress remote_addr;
|
||||
if (WiFi.hostByName(hostname.c_str(), remote_addr))
|
||||
if (WiFi.hostByName(hostname.c_str(), remote_addr)) {
|
||||
return hostReachable(remote_addr);
|
||||
}
|
||||
String log = F("Hostname cannot be resolved: ");
|
||||
log += hostname;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
|
||||
+67
-12
@@ -54,6 +54,12 @@ void formatMAC(const uint8_t* mac, char (&strMAC)[20]) {
|
||||
sprintf_P(strMAC, PSTR("%02X:%02X:%02X:%02X:%02X:%02X"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
}
|
||||
|
||||
String formatMAC(const uint8_t* mac) {
|
||||
char str[20];
|
||||
formatMAC(mac, str);
|
||||
return String(str);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Workaround for removing trailing white space when String() converts a float with 0 decimals
|
||||
\*********************************************************************************************/
|
||||
@@ -67,12 +73,27 @@ String toString(float value, byte decimals)
|
||||
/*********************************************************************************************\
|
||||
Format a value to the set number of decimals
|
||||
\*********************************************************************************************/
|
||||
String formatUserVar(struct EventStruct *event, byte rel_index)
|
||||
{
|
||||
float f(UserVar[event->BaseVarIndex + rel_index]);
|
||||
if (!isValidFloat(f)) {
|
||||
String doFormatUserVar(byte TaskIndex, byte rel_index, bool mustCheck, bool& isvalid) {
|
||||
isvalid = true;
|
||||
const byte BaseVarIndex = TaskIndex * VARS_PER_TASK;
|
||||
const byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[TaskIndex]);
|
||||
if (Device[DeviceIndex].ValueCount <= rel_index) {
|
||||
isvalid = false;
|
||||
String log = F("No sensor value for TaskIndex: ");
|
||||
log += TaskIndex;
|
||||
log += F(" varnumber: ");
|
||||
log += rel_index;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return "";
|
||||
}
|
||||
if (Device[DeviceIndex].VType == SENSOR_TYPE_LONG) {
|
||||
return String((unsigned long)UserVar[BaseVarIndex] + ((unsigned long)UserVar[BaseVarIndex + 1] << 16));
|
||||
}
|
||||
float f(UserVar[BaseVarIndex + rel_index]);
|
||||
if (mustCheck && !isValidFloat(f)) {
|
||||
isvalid = false;
|
||||
String log = F("Invalid float value for TaskIndex: ");
|
||||
log += event->TaskIndex;
|
||||
log += TaskIndex;
|
||||
log += F(" varnumber: ");
|
||||
log += rel_index;
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
@@ -81,6 +102,25 @@ String formatUserVar(struct EventStruct *event, byte rel_index)
|
||||
return toString(f, ExtraTaskSettings.TaskDeviceValueDecimals[rel_index]);
|
||||
}
|
||||
|
||||
String formatUserVarNoCheck(byte TaskIndex, byte rel_index) {
|
||||
bool isvalid;
|
||||
return doFormatUserVar(TaskIndex, rel_index, false, isvalid);
|
||||
}
|
||||
|
||||
String formatUserVar(byte TaskIndex, byte rel_index, bool& isvalid) {
|
||||
return doFormatUserVar(TaskIndex, rel_index, true, isvalid);
|
||||
}
|
||||
|
||||
String formatUserVarNoCheck(struct EventStruct *event, byte rel_index)
|
||||
{
|
||||
return formatUserVarNoCheck(event->TaskIndex, rel_index);
|
||||
}
|
||||
|
||||
String formatUserVar(struct EventStruct *event, byte rel_index, bool& isvalid)
|
||||
{
|
||||
return formatUserVar(event->TaskIndex, rel_index, isvalid);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Wrap a string with given pre- and postfix string.
|
||||
\*********************************************************************************************/
|
||||
@@ -102,7 +142,15 @@ String to_json_object_value(const String& object, const String& value) {
|
||||
result = wrap_String(object, F("\""));
|
||||
result += F(":");
|
||||
if (value.length() == 0 || !isFloat(value)) {
|
||||
result += wrap_String(value, F("\""));
|
||||
if (value.indexOf('\n') == -1 && value.indexOf('"') == -1 && value.indexOf("Pragma") == -1) {
|
||||
result += wrap_String(value, F("\""));
|
||||
} else {
|
||||
String tmpValue(value);
|
||||
tmpValue.replace('\n', '^');
|
||||
tmpValue.replace('"', '\'');
|
||||
tmpValue.replace("Pragma", "Bugje!");
|
||||
result += wrap_String(tmpValue, F("\""));
|
||||
}
|
||||
} else {
|
||||
result += value;
|
||||
}
|
||||
@@ -277,9 +325,13 @@ void parseSystemVariables(String& s, boolean useURLencode)
|
||||
#endif
|
||||
repl(F("%CR%"), F("\r"), s, useURLencode);
|
||||
repl(F("%LF%"), F("\n"), s, useURLencode);
|
||||
repl(F("%SP%"), F(" "), s, useURLencode); //space
|
||||
SMART_REPL(F("%ip4%"),WiFi.localIP().toString().substring(WiFi.localIP().toString().lastIndexOf('.')+1)) //4th IP octet
|
||||
SMART_REPL(F("%ip%"),WiFi.localIP().toString())
|
||||
SMART_REPL(F("%rssi%"), String((WiFi.status() == WL_CONNECTED) ? WiFi.RSSI() : 0))
|
||||
SMART_REPL(F("%ssid%"), (WiFi.status() == WL_CONNECTED) ? WiFi.SSID() : F("--"))
|
||||
SMART_REPL(F("%rssi%"), String((wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? 0 : WiFi.RSSI()))
|
||||
SMART_REPL(F("%ssid%"), (wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? F("--") : WiFi.SSID())
|
||||
SMART_REPL(F("%bssid%"), (wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? F("00:00:00:00:00:00") : WiFi.BSSIDstr())
|
||||
SMART_REPL(F("%wi_ch%"), String((wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? 0 : WiFi.channel()))
|
||||
SMART_REPL(F("%unit%"), String(Settings.Unit))
|
||||
SMART_REPL(F("%mac%"), String(WiFi.macAddress()))
|
||||
#if defined(ESP8266)
|
||||
@@ -288,6 +340,7 @@ void parseSystemVariables(String& s, boolean useURLencode)
|
||||
|
||||
if (s.indexOf(F("%sys")) != -1) {
|
||||
SMART_REPL(F("%sysload%"), String(100 - (100 * loopCounterLast / loopCounterMax)))
|
||||
SMART_REPL(F("%sysheap%"), String(ESP.getFreeHeap()));
|
||||
SMART_REPL(F("%systm_hm%"), getTimeString(':', false))
|
||||
SMART_REPL(F("%systm_hm_am%"), getTimeString_ampm(':', false))
|
||||
SMART_REPL(F("%systime%"), getTimeString(':'))
|
||||
@@ -300,6 +353,7 @@ void parseSystemVariables(String& s, boolean useURLencode)
|
||||
SMART_REPL_TIME(F("%syshour%"), PSTR("%02d"), hour())
|
||||
SMART_REPL_TIME(F("%sysmin%"), PSTR("%02d"), minute())
|
||||
SMART_REPL_TIME(F("%syssec%"),PSTR("%02d"), second())
|
||||
SMART_REPL_TIME(F("%syssec_d%"),PSTR("%d"), ((hour()*60) + minute())*60 + second());
|
||||
SMART_REPL_TIME(F("%sysday%"), PSTR("%02d"), day())
|
||||
SMART_REPL_TIME(F("%sysmonth%"),PSTR("%02d"), month())
|
||||
SMART_REPL_TIME(F("%sysyear%"), PSTR("%04d"), year())
|
||||
@@ -311,6 +365,7 @@ void parseSystemVariables(String& s, boolean useURLencode)
|
||||
SMART_REPL(F("%lcltime%"), getDateTimeString('-',':',' '))
|
||||
SMART_REPL(F("%lcltime_am%"), getDateTimeString_ampm('-',':',' '))
|
||||
SMART_REPL(F("%uptime%"), String(wdcounter / 2))
|
||||
SMART_REPL(F("%unixtime%"), String(getUnixTime()))
|
||||
|
||||
repl(F("%tskname%"), ExtraTaskSettings.TaskDeviceName, s, useURLencode);
|
||||
if (s.indexOf("%vname") != -1) {
|
||||
@@ -328,10 +383,10 @@ void parseEventVariables(String& s, struct EventStruct *event, boolean useURLenc
|
||||
if (event->sensorType == SENSOR_TYPE_LONG) {
|
||||
SMART_REPL(F("%val1%"), String((unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)))
|
||||
} else {
|
||||
SMART_REPL(F("%val1%"), formatUserVar(event, 0))
|
||||
SMART_REPL(F("%val2%"), formatUserVar(event, 1))
|
||||
SMART_REPL(F("%val3%"), formatUserVar(event, 2))
|
||||
SMART_REPL(F("%val4%"), formatUserVar(event, 3))
|
||||
SMART_REPL(F("%val1%"), formatUserVarNoCheck(event, 0))
|
||||
SMART_REPL(F("%val2%"), formatUserVarNoCheck(event, 1))
|
||||
SMART_REPL(F("%val3%"), formatUserVarNoCheck(event, 2))
|
||||
SMART_REPL(F("%val4%"), formatUserVarNoCheck(event, 3))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+47
-15
@@ -72,6 +72,7 @@ void breakTime(unsigned long timeInput, struct timeStruct &tm) {
|
||||
|
||||
void setTime(unsigned long t) {
|
||||
sysTime = (uint32_t)t;
|
||||
applyTimeZone(t);
|
||||
nextSyncTime = (uint32_t)t + syncInterval;
|
||||
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
|
||||
if (Settings.UseRules)
|
||||
@@ -83,6 +84,10 @@ void setTime(unsigned long t) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getUnixTime() {
|
||||
return sysTime;
|
||||
}
|
||||
|
||||
unsigned long now() {
|
||||
// calculate number of seconds passed since last call to now()
|
||||
const long msec_passed = timePassedSince(prevMillis);
|
||||
@@ -94,10 +99,6 @@ unsigned long now() {
|
||||
unsigned long t = getNtpTime();
|
||||
if (t != 0) {
|
||||
setTime(t);
|
||||
applyTimeZone(t);
|
||||
} else {
|
||||
// Unable to sync, retry again in a minute
|
||||
nextSyncTime = sysTime + 60;
|
||||
}
|
||||
}
|
||||
uint32_t localSystime = toLocal(sysTime);
|
||||
@@ -197,19 +198,36 @@ void checkTime()
|
||||
|
||||
unsigned long getNtpTime()
|
||||
{
|
||||
if (!Settings.UseNTP || !WiFiConnected(100)) {
|
||||
if (!Settings.UseNTP || !WiFiConnected(10)) {
|
||||
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)
|
||||
String log = F("NTP : NTP host ");
|
||||
if (Settings.NTPHost[0] != 0) {
|
||||
WiFi.hostByName(Settings.NTPHost, timeServerIP);
|
||||
else
|
||||
WiFi.hostByName(ntpServerName, timeServerIP);
|
||||
log += Settings.NTPHost;
|
||||
// When single set host fails, retry again in a minute
|
||||
nextSyncTime = sysTime + 20;
|
||||
}
|
||||
else {
|
||||
// Have to do a lookup eacht time, since the NTP pool always returns another IP
|
||||
String ntpServerName = String(random(0, 3));
|
||||
ntpServerName += F(".pool.ntp.org");
|
||||
WiFi.hostByName(ntpServerName.c_str(), timeServerIP);
|
||||
log += ntpServerName;
|
||||
// When pool host fails, retry can be much sooner
|
||||
nextSyncTime = sysTime + 5;
|
||||
}
|
||||
|
||||
if (!hostReachable(timeServerIP))
|
||||
log += F(" (");
|
||||
log += timeServerIP.toString();
|
||||
log += F(")");
|
||||
|
||||
if (!hostReachable(timeServerIP)) {
|
||||
log += F(" unreachable");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WiFiUDP udp;
|
||||
udp.begin(123);
|
||||
@@ -217,8 +235,7 @@ unsigned long getNtpTime()
|
||||
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
|
||||
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
|
||||
|
||||
String log = F("NTP : NTP send to ");
|
||||
log += timeServerIP.toString();
|
||||
log += F(" queried");
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
while (udp.parsePacket() > 0) ; // discard any previously received packets
|
||||
@@ -253,6 +270,7 @@ unsigned long getNtpTime()
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
return secsSince1900 - 2208988800UL;
|
||||
}
|
||||
delay(10);
|
||||
}
|
||||
log = F("NTP : No reply");
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
@@ -268,7 +286,7 @@ unsigned long getNtpTime()
|
||||
// Return the time difference as a signed value, taking into account the timers may overflow.
|
||||
// Returned timediff is between -24.9 days and +24.9 days.
|
||||
// Returned value is positive when "next" is after "prev"
|
||||
long timeDiff(unsigned long prev, unsigned long next)
|
||||
long timeDiff(const unsigned long prev, const unsigned long next)
|
||||
{
|
||||
long signed_diff = 0;
|
||||
// To cast a value to a signed long, the difference may not exceed half the ULONG_MAX
|
||||
@@ -312,7 +330,21 @@ boolean timeOutReached(unsigned long timer)
|
||||
return passed >= 0;
|
||||
}
|
||||
|
||||
|
||||
void setNextTimeInterval(unsigned long& timer, const unsigned long step) {
|
||||
timer += step;
|
||||
const long passed = timePassedSince(timer);
|
||||
if (passed < 0) {
|
||||
// Event has not yet happened, which is fine.
|
||||
return;
|
||||
}
|
||||
if (static_cast<unsigned long>(passed) > step) {
|
||||
// No need to keep running behind, start again.
|
||||
timer = millis() + step;
|
||||
return;
|
||||
}
|
||||
// Try to get in sync again.
|
||||
timer = millis() + (step - passed);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
|
||||
+1329
-1093
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,560 @@
|
||||
#ifndef WEBSTATICDATA_h
|
||||
#define WEBSTATICDATA_h
|
||||
|
||||
#define PGMT( pgm_ptr ) ( reinterpret_cast< const __FlashStringHelper * >( pgm_ptr ) )
|
||||
|
||||
/*********************************************************************************************\
|
||||
* ESP Easy logo Favicon.ico 16x16 8 bit
|
||||
\*********************************************************************************************/
|
||||
// Generated using xxd: xxd -i favicon.ico > favicon.ino
|
||||
static const char favicon_8b_ico[] PROGMEM = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x00,
|
||||
0x20, 0x00, 0x68, 0x04, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00,
|
||||
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x12, 0x0b,
|
||||
0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xef, 0xc0, 0x89, 0x11, 0xfe, 0xfb, 0xf8, 0xac, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa,
|
||||
0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa,
|
||||
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf3,
|
||||
0xe9, 0xac, 0xef, 0xc0, 0x89, 0x11, 0xfe, 0xfb, 0xf8, 0xac, 0xf1, 0xc8,
|
||||
0x95, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xef, 0xc2,
|
||||
0x8a, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfc, 0xf3, 0xe9, 0xac, 0xff, 0xff,
|
||||
0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
|
||||
0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa,
|
||||
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd9, 0x69,
|
||||
0x00, 0xff, 0xd9, 0x69, 0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xc2,
|
||||
0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xd9, 0x69, 0x00, 0xff, 0xd9, 0x69, 0x00, 0xff, 0xef, 0xc2,
|
||||
0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
|
||||
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
|
||||
0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa,
|
||||
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63,
|
||||
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xc2,
|
||||
0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
|
||||
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa,
|
||||
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2,
|
||||
0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
|
||||
0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa,
|
||||
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63,
|
||||
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xc2,
|
||||
0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xc8,
|
||||
0x95, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
|
||||
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa,
|
||||
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63,
|
||||
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2,
|
||||
0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa,
|
||||
0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63,
|
||||
0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2,
|
||||
0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xd8, 0x63, 0x00, 0xff, 0xef, 0xbc,
|
||||
0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xbc, 0x80, 0xff, 0xd8, 0x63,
|
||||
0x00, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xf1,
|
||||
0xe6, 0xac, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xf1, 0xc8,
|
||||
0x95, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xc2,
|
||||
0x8a, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xef, 0xc2, 0x8a, 0xff, 0xf1, 0xc8, 0x95, 0xff, 0xfe, 0xfb,
|
||||
0xf8, 0xac, 0xef, 0xc0, 0x89, 0x11, 0xfb, 0xf1, 0xe6, 0xac, 0xfe, 0xfa,
|
||||
0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xfe, 0xfa,
|
||||
0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfa,
|
||||
0xf5, 0xff, 0xfe, 0xfa, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfb,
|
||||
0xf8, 0xac, 0xef, 0xc0, 0x89, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
unsigned int favicon_8b_ico_len = 1150;
|
||||
|
||||
static const char githublogo[] PROGMEM = {
|
||||
"<button class='button link' onclick='setGithubClipboard()' style='padding: 0px 2px; position: relative; top: 4px;'>"
|
||||
"<svg width='24' height='24' viewBox='-1 -1 26 26' style='position: relative; top: 2px;'>"
|
||||
"<path d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12' stroke='white' fill='white'/></svg>"
|
||||
"</button>"
|
||||
"<script>"
|
||||
"function setGithubClipboard() { var clipboard = 'ESP Easy | Information |\\n -----|-----|\\n';"
|
||||
" max_loop = 100;"
|
||||
" for (var i = 1; i < max_loop; i++){"
|
||||
" var cur_id = 'copyText_' + i;"
|
||||
" var test = document.getElementById(cur_id);"
|
||||
" if (test == null){ i = max_loop + 1;"
|
||||
" } else {"
|
||||
"var separatorSymbol = '|';"
|
||||
"if (i % 2 == 0) {separatorSymbol += '\\n'}"
|
||||
" clipboard += test.innerHTML.replace(/<[Bb][Rr]\\s*\\/?>/gim,'\\n') + separatorSymbol; } }"
|
||||
"clipboard = clipboard.replace(/<\\/[Dd][Ii][Vv]\\s*\\/?>/gim,'\\n');"
|
||||
"clipboard = clipboard.replace(/<[^>]*>/gim,'');"
|
||||
"var tempInput = document.createElement('textarea');"
|
||||
"tempInput.style = 'position: absolute;"
|
||||
"left: -1000px; top: -1000px'; tempInput.innerHTML = clipboard;"
|
||||
"document.body.appendChild(tempInput);"
|
||||
"tempInput.select();"
|
||||
"document.execCommand('copy');"
|
||||
"document.body.removeChild(tempInput);"
|
||||
"alert('Copied: \"' + clipboard + '\" to clipboard!') }"
|
||||
"</script>"
|
||||
};
|
||||
|
||||
static const char pgDefaultCSS[] PROGMEM = {
|
||||
//color scheme: #07D #D50 #DB0 #A0D
|
||||
"* {font-family: sans-serif; font-size: 12pt; margin: 0px; padding: 0px; box-sizing: border-box; }"
|
||||
"h1 {font-size: 16pt; color: #07D; margin: 8px 0; font-weight: bold; }"
|
||||
"h2 {font-size: 12pt; margin: 0 -4px; padding: 6px; background-color: #444; color: #FFF; font-weight: bold; }"
|
||||
"h3 {font-size: 12pt; margin: 16px -4px 0 -4px; padding: 4px; background-color: #EEE; color: #444; font-weight: bold; }"
|
||||
"h6 {font-size: 10pt; color: #07D; }"
|
||||
// buttons
|
||||
".button {margin: 4px; padding: 4px 16px; background-color: #07D; color: #FFF; text-decoration: none; border-radius: 4px; border: none;}"
|
||||
".button.link { }"
|
||||
".button.help {padding: 2px 4px; border-style: solid; border-width: 1px; border-color: gray; border-radius: 50%; }"
|
||||
".button:hover {background: #369; }"
|
||||
// inputs, select, textarea general
|
||||
"input, select, textarea {margin: 4px; padding: 4px 8px; border-radius: 4px; background-color: #eee; border-style: solid; border-width: 1px; border-color: gray;}"
|
||||
// inputs
|
||||
"input:hover {background-color: #ccc; }"
|
||||
"input.wide {max-width: 500px; width:80%; }"
|
||||
"input.widenumber {max-width: 500px; width:100px; }"
|
||||
// select
|
||||
"#selectwidth {max-width: 500px; width:80%; padding: 4px 8px;}"
|
||||
"select:hover {background-color: #ccc; }"
|
||||
// custom checkboxes
|
||||
".container {display: block; padding-left: 35px; margin-left: 4px; margin-top: 0px; position: relative; cursor: pointer; font-size: 12pt; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }"
|
||||
// Hide the browser's default checkbox
|
||||
".container input {position: absolute; opacity: 0; cursor: pointer; }"
|
||||
// Create a custom checkbox
|
||||
".checkmark {position: absolute; top: 0; left: 0; height: 25px; width: 25px; background-color: #eee; border-style: solid; border-width: 1px; border-color: gray; border-radius: 4px;}"
|
||||
// On mouse-over, add a grey background color
|
||||
".container:hover input ~ .checkmark {background-color: #ccc; }"
|
||||
// When the checkbox is checked, add a blue background
|
||||
".container input:checked ~ .checkmark { background-color: #07D; }"
|
||||
// Create the checkmark/indicator (hidden when not checked)
|
||||
".checkmark:after {content: ''; position: absolute; display: none; }"
|
||||
// Show the checkmark when checked
|
||||
".container input:checked ~ .checkmark:after {display: block; }"
|
||||
// Style the checkmark/indicator
|
||||
".container .checkmark:after {left: 7px; top: 3px; width: 5px; height: 10px; border: solid white; border-width: 0 3px 3px 0; -webkit-transform: rotate(45deg); -ms-transform: rotate(45deg); transform: rotate(45deg); }"
|
||||
|
||||
// custom radio buttons
|
||||
".container2 {display: block; padding-left: 35px; margin-left: 9px; margin-bottom: 20px; position: relative; cursor: pointer; font-size: 12pt; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }"
|
||||
// Hide the browser's default radio button
|
||||
".container2 input {position: absolute; opacity: 0; cursor: pointer; }"
|
||||
// Create a custom radio button
|
||||
".dotmark {position: absolute; top: 0; left: 0; height: 26px; width: 26px; background-color: #eee; border-style: solid; border-width: 1px; border-color: gray; border-radius: 50%;}"
|
||||
// On mouse-over, add a grey background color
|
||||
".container2:hover input ~ .dotmark {background-color: #ccc; }"
|
||||
// When the radio button is checked, add a blue background
|
||||
".container2 input:checked ~ .dotmark { background-color: #07D;}"
|
||||
// Create the dot/indicator (hidden when not checked)
|
||||
".dotmark:after {content: ''; position: absolute; display: none; }"
|
||||
// Show the dot when checked
|
||||
".container2 input:checked ~ .dotmark:after {display: block; }"
|
||||
// Style the dot/indicator
|
||||
".container2 .dotmark:after {top: 8px; left: 8px; width: 8px; height: 8px; border-radius: 50%; background: white; }"
|
||||
|
||||
// toast messsage
|
||||
"#toastmessage {visibility: hidden; min-width: 250px; margin-left: -125px; background-color: #07D;"
|
||||
"color: #fff; text-align: center; border-radius: 4px; padding: 16px; position: fixed;"
|
||||
"z-index: 1; left: 282px; bottom: 30%; font-size: 17px; border-style: solid; border-width: 1px; border-color: gray;}"
|
||||
"#toastmessage.show {visibility: visible; -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s; animation: fadein 0.5s, fadeout 0.5s 2.5s; }"
|
||||
// fade in
|
||||
"@-webkit-keyframes fadein {from {bottom: 20%; opacity: 0;} to {bottom: 30%; opacity: 0.9;} }"
|
||||
"@keyframes fadein {from {bottom: 20%; opacity: 0;} to {bottom: 30%; opacity: 0.9;} }"
|
||||
// fade out
|
||||
"@-webkit-keyframes fadeout {from {bottom: 30%; opacity: 0.9;} to {bottom: 0; opacity: 0;} }"
|
||||
"@keyframes fadeout {from {bottom: 30%; opacity: 0.9;} to {bottom: 0; opacity: 0;} }"
|
||||
// web log viewer and log levels
|
||||
//low level? Not used? white
|
||||
".level_0 { color: #F1F1F1; }"
|
||||
//ERROR yellow
|
||||
".level_1 { color: #FCFF95; }"
|
||||
//INFO blue
|
||||
".level_2 { color: #9DCEFE; }"
|
||||
//DEBUG green
|
||||
".level_3 { color: #A4FC79; }"
|
||||
//DEBUG_MORE orange
|
||||
".level_4 { color: #F2AB39; }"
|
||||
//DEBUG_DEV dark orange
|
||||
".level_9 { color: #FF5500; }"
|
||||
//the cmd window
|
||||
".logviewer { color: #F1F1F1; background-color: #272727; font-family: 'Lucida Console', Monaco, monospace; "
|
||||
" height: 530px; max-width: 1000px; width: 80%; padding: 4px 8px; overflow: auto; border-style: solid; border-color: gray; }"
|
||||
// text textarea
|
||||
"textarea {max-width: 1000px; width:80%; padding: 4px 8px;}"
|
||||
"textarea:hover {background-color: #ccc; }"
|
||||
// tables
|
||||
"table.normal th {padding: 6px; background-color: #444; color: #FFF; border-color: #888; font-weight: bold; }"
|
||||
"table.normal td {padding: 4px; height: 30px;}"
|
||||
"table.normal tr {padding: 4px; }"
|
||||
"table.normal {color: #000; width: 100%; min-width: 420px; border-collapse: collapse; }"
|
||||
//every second row
|
||||
"table.multirow th {padding: 6px; background-color: #444; color: #FFF; border-color: #888; font-weight: bold; }"
|
||||
"table.multirow td {padding: 4px; text-align: center; height: 30px;}"
|
||||
"table.multirow tr {padding: 4px; }"
|
||||
"table.multirow tr:nth-child(even){background-color: #DEE6FF; }"
|
||||
"table.multirow {color: #000; width: 100%; min-width: 420px; border-collapse: collapse; }"
|
||||
// inside a form
|
||||
".note {color: #444; font-style: italic; }"
|
||||
//header with title and menu
|
||||
".headermenu {position: fixed; top: 0; left: 0; right: 0; height: 90px; padding: 8px 12px; background-color: #F8F8F8; border-bottom: 1px solid #DDD; z-index: 1;}"
|
||||
".apheader {padding: 8px 12px; background-color: #F8F8F8;}"
|
||||
".bodymenu {margin-top: 96px;}"
|
||||
// menu
|
||||
".menubar {position: inherit; top: 55px; }"
|
||||
".menu {float: left; padding: 4px 16px 8px 16px; color: #444; white-space: nowrap; border: solid transparent; border-width: 4px 1px 1px; border-radius: 4px 4px 0 0; text-decoration: none; }"
|
||||
".menu.active {color: #000; background-color: #FFF; border-color: #07D #DDD #FFF; }"
|
||||
".menu:hover {color: #000; background: #DEF; }"
|
||||
".menu_button {display: none;}"
|
||||
// symbols for enabled
|
||||
".on {color: green; }"
|
||||
".off {color: red; }"
|
||||
// others
|
||||
".div_l {float: left; }"
|
||||
".div_r {float: right; margin: 2px; padding: 1px 10px; border-radius: 4px; background-color: #080; color: white; }"
|
||||
".div_br {clear: both; }"
|
||||
// The alert message box
|
||||
".alert {padding: 20px; background-color: #f44336; color: white; margin-bottom: 15px; }"
|
||||
// The close button
|
||||
".closebtn {margin-left: 15px; color: white; font-weight: bold; float: right; font-size: 22px; line-height: 20px; cursor: pointer; transition: 0.3s; }"
|
||||
// When moving the mouse over the close button
|
||||
".closebtn:hover {color: black; }"
|
||||
"section{overflow-x: auto; width: 100%; }"
|
||||
// For screens with width less than 960 pixels
|
||||
"@media screen and (max-width: 960px) {"
|
||||
"header:hover .menubar {display: block;}"
|
||||
".menu_button {display: block; text-align: center;}"
|
||||
".bodymenu{ margin-top: 0px; }"
|
||||
".menubar{ display: none; top: 0px; position: relative; float: left; width: 100%;}"
|
||||
".headermenu{ position: relative; height: auto; float: left; width: 100%; padding: 5px; z-index: 1;}"
|
||||
".headermenu h1{ padding: 8px 12px; }"
|
||||
".headermenu a{ text-align: center; width: 100%; padding:7px 10px; height: auto; border: 0px; border-radius:0px; }; }"
|
||||
"\0"
|
||||
};
|
||||
|
||||
|
||||
// JavaScript blobs
|
||||
|
||||
|
||||
|
||||
static const char jsReboot[] PROGMEM = {
|
||||
"<script>"
|
||||
"i=document.getElementById('rbtmsg');"
|
||||
"i.innerHTML=\"Please reboot: <input id='reboot' class='button link' value='Reboot' type='submit' onclick='r()'>\";"
|
||||
"var x = new XMLHttpRequest();"
|
||||
|
||||
//done
|
||||
"function d(){"
|
||||
"i.innerHTML='';"
|
||||
"clearTimeout(t);"
|
||||
"}"
|
||||
|
||||
|
||||
//keep requesting mainpage until no more errors
|
||||
"function c(){"
|
||||
"i.innerHTML+='.';"
|
||||
"x.onload=d;"
|
||||
"x.open('GET', window.location.origin);"
|
||||
"x.send();"
|
||||
"}"
|
||||
|
||||
//rebooting
|
||||
"function b(){"
|
||||
"i.innerHTML='Rebooting..';"
|
||||
"t=setInterval(c,2000);"
|
||||
"}"
|
||||
|
||||
|
||||
//request reboot
|
||||
"function r(){"
|
||||
"i.innerHTML+=' (requesting)';"
|
||||
"x.onload=b;"
|
||||
"x.open('GET', window.location.origin+'/?cmd=reboot');"
|
||||
"x.send();"
|
||||
"}"
|
||||
|
||||
"</script>"
|
||||
};
|
||||
|
||||
static const char jsToastMessageBegin[] PROGMEM = {
|
||||
"<script>"
|
||||
"function toasting() {"
|
||||
"var x = document.getElementById('toastmessage');"
|
||||
"x.innerHTML = '"
|
||||
};
|
||||
|
||||
static const char jsToastMessageEnd[] PROGMEM = {
|
||||
"'; x.className = 'show';"
|
||||
" setTimeout(function(){x.innerHTML = '';"
|
||||
" x.className = x.className.replace('show', '');"
|
||||
" }, 2000);"
|
||||
"} </script>"
|
||||
};
|
||||
|
||||
static const char jsClipboardCopyPart1[] PROGMEM = {
|
||||
"<script>function setClipboard() { var clipboard = '';"
|
||||
" max_loop = 100;"
|
||||
" for (var i = 1; i < max_loop; i++){"
|
||||
" var cur_id = '"
|
||||
};
|
||||
|
||||
static const char jsClipboardCopyPart2[] PROGMEM = {
|
||||
"_' + i;"
|
||||
" var test = document.getElementById(cur_id);"
|
||||
" if (test == null){ i = max_loop + 1;"
|
||||
" } else {"
|
||||
" clipboard += test.innerHTML.replace(/<[Bb][Rr]\\s*\\/?>/gim,'\\n') + '"
|
||||
};
|
||||
|
||||
//Fix HTML
|
||||
static const char jsClipboardCopyPart3[] PROGMEM = {
|
||||
"'; } }"
|
||||
"clipboard = clipboard.replace(/<\\/[Dd][Ii][Vv]\\s*\\/?>/gim,'\\n');"
|
||||
"clipboard = clipboard.replace(/<[^>]*>/gim,'');"
|
||||
"var tempInput = document.createElement('textarea');"
|
||||
"tempInput.style = 'position: absolute;"
|
||||
"left: -1000px; top: -1000px'; tempInput.innerHTML = clipboard;"
|
||||
"document.body.appendChild(tempInput);"
|
||||
"tempInput.select();"
|
||||
"document.execCommand('copy');"
|
||||
"document.body.removeChild(tempInput);"
|
||||
"alert('Copied: \"' + clipboard + '\" to clipboard!') }"
|
||||
"</script>"
|
||||
};
|
||||
|
||||
|
||||
static const char jsUpdateSensorValuesDevicePage[] PROGMEM = {
|
||||
"<script defer>"
|
||||
"loopDeLoop(1000, 0);"
|
||||
|
||||
"function loopDeLoop(timeForNext, activeRequests) {"
|
||||
"var maximumRequests = 1;"
|
||||
"var c;"
|
||||
"var k;"
|
||||
"var err = '';"
|
||||
"var url = '/json';"
|
||||
"var check = 0;"
|
||||
"if (isNaN(activeRequests)){activeRequests = maximumRequests;}"
|
||||
"if (timeForNext == null){timeForNext = 1000;}"
|
||||
"var i = setInterval(function() {"
|
||||
"if (check > 0) {"
|
||||
"clearInterval(i);"
|
||||
"return;"
|
||||
"}"
|
||||
"++activeRequests;"
|
||||
// to handle requests pending...
|
||||
"if (activeRequests > maximumRequests) {"
|
||||
"check = 1;"
|
||||
"} else {"
|
||||
"fetch(url).then(function(response) {"
|
||||
"var valueEntry;"
|
||||
"if (response.status !== 200) {"
|
||||
"console.log('Looks like there was a problem. Status Code: ' + response.status);"
|
||||
"return;"
|
||||
"}"
|
||||
"response.json().then(function(data) {"
|
||||
"timeForNext = data.TTL;"
|
||||
"for (c = 0; c < data.Sensors.length; c++) {"
|
||||
"for (k = 0; k < data.Sensors[c].TaskValues.length; k++) {"
|
||||
"try {"
|
||||
"valueEntry = data.Sensors[c].TaskValues[k].Value;"
|
||||
"} catch (err) {"
|
||||
"valueEntry = err.name;"
|
||||
"} finally {"
|
||||
"if (valueEntry !== 'TypeError') {"
|
||||
//to fix trailing zeros (fixed decimals)
|
||||
"tempValue = data.Sensors[c].TaskValues[k].Value;"
|
||||
"decimalsValue = data.Sensors[c].TaskValues[k].NrDecimals;"
|
||||
"tempValue = parseFloat(tempValue).toFixed(decimalsValue);"
|
||||
"document.getElementById('value_' + (data.Sensors[c].TaskNumber - 1) + '_' + (data.Sensors[c].TaskValues[k].ValueNumber - 1)).innerHTML = tempValue;"
|
||||
"document.getElementById('valuename_' + (data.Sensors[c].TaskNumber - 1) + '_' + (data.Sensors[c].TaskValues[k].ValueNumber - 1)).innerHTML = data.Sensors[c].TaskValues[k].Name + ':';"
|
||||
"}"
|
||||
"}"
|
||||
"}"
|
||||
"}"
|
||||
"timeForNext = data.TTL;"
|
||||
//"console.log('Next fetch in: ' + timeForNext + 'mSec, active requests: ' + activeRequests);"
|
||||
"clearInterval(i);"
|
||||
"loopDeLoop(timeForNext, 0);"
|
||||
"return;"
|
||||
"});"
|
||||
"})"
|
||||
".catch(function(err) {"
|
||||
"console.log(err.message);"
|
||||
"timeForNext = 5000;"
|
||||
"clearInterval(i);"
|
||||
"loopDeLoop(timeForNext, 0);"
|
||||
"return;"
|
||||
"});"
|
||||
"check = 1;"
|
||||
"}}, timeForNext);"
|
||||
"}"
|
||||
"</script>"
|
||||
};
|
||||
|
||||
static const char jsFetchAndParseLog[] PROGMEM = {
|
||||
|
||||
"<script defer>"
|
||||
"function getBrowser() {"
|
||||
"var ua=navigator.userAgent,tem,M=ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\\/))\\/?\\s*(\\d+)/i) || [];"
|
||||
"if(/trident/i.test(M[1])){"
|
||||
"tem=/\\brv[ :]+(\\d+)/g.exec(ua) || [];"
|
||||
"return {name:'IE',version:(tem[1]||'')};"
|
||||
"}"
|
||||
"if(M[1]==='Chrome'){"
|
||||
"tem=ua.match(/\\bOPR|Edge\\/(\\d+)/);"
|
||||
"if(tem!=null) {return {name:'Opera', version:tem[1]};}"
|
||||
"}"
|
||||
"M=M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];"
|
||||
"if((tem=ua.match(/version\\/(\\d+)/i))!=null) {M.splice(1,1,tem[1]);}"
|
||||
"return {"
|
||||
"name: M[0],"
|
||||
"version: M[1]"
|
||||
"};"
|
||||
"}"
|
||||
"var browser=getBrowser();"
|
||||
"var currentBrowser = browser.name + browser.version;"
|
||||
//"console.log(browser.name + browser.version);"
|
||||
"if (browser.name = 'IE' && browser.version < 12) {"
|
||||
"textToDisplay = 'Error: ' + currentBrowser + ' is not supported! Please try a modern web browser.'"
|
||||
"} else {"
|
||||
"textToDisplay = 'Fetching log entries...';"
|
||||
"}"
|
||||
"document.getElementById('copyText_1').innerHTML = textToDisplay;"
|
||||
"loopDeLoop(1000, 0, 0);"
|
||||
|
||||
"var logLevel = new Array('Unused','Error','Info','Debug','Debug More','Undefined','Undefined','Undefined','Undefined','Debug Dev');"
|
||||
|
||||
"function loopDeLoop(timeForNext, activeRequests, reRunCount) {"
|
||||
"var maximumRequests = 1;"
|
||||
"var url = '/logjson';"
|
||||
"if (isNaN(activeRequests)){activeRequests = maximumRequests;}"
|
||||
"if (timeForNext == null){timeForNext = 1000;}"
|
||||
//to make sure we don't run to often... JS seems to like it that way.
|
||||
"if (timeForNext <= 500){"
|
||||
"scrolling_type = 'auto';"
|
||||
"} else {"
|
||||
"scrolling_type = 'smooth';"
|
||||
"}"
|
||||
//"console.log('Next fetch in: ' + timeForNext + 'mSec');"
|
||||
"var c;"
|
||||
"var logEntriesChunk;"
|
||||
"var currentIDtoScrollTo = '';"
|
||||
"var check = 0;"
|
||||
"var i = setInterval(function() {"
|
||||
// to handle runs that didn't find any json
|
||||
"if (check > 0) {"
|
||||
"clearInterval(i);"
|
||||
"return;"
|
||||
"}"
|
||||
"++activeRequests;"
|
||||
// to handle requests pending...
|
||||
"if (activeRequests > maximumRequests) {"
|
||||
"check = 1;"
|
||||
"} else {"
|
||||
"fetch(url).then(function(response) {"
|
||||
"if (response.status !== 200) {"
|
||||
"console.log('Looks like there was a problem. Status Code: ' + response.status);"
|
||||
"return;"
|
||||
"}"
|
||||
"response.json().then(function(data) {"
|
||||
"var logEntry;"
|
||||
"if (logEntriesChunk == null) {"
|
||||
"logEntriesChunk = '';"
|
||||
"}"
|
||||
"for (c = 0; c < data.Log.nrEntries + 1; c++) {"
|
||||
"try {"
|
||||
"logEntry = data.Log.Entries[c].timestamp;"
|
||||
"} catch (err) {"
|
||||
"logEntry = err.name;"
|
||||
"} finally {"
|
||||
"if (logEntry !== \"TypeError\") {"
|
||||
"currentIDtoScrollTo = data.Log.Entries[c].timestamp;"
|
||||
"logEntriesChunk += '<div class=level_' + data.Log.Entries[c].level + ' id=' + currentIDtoScrollTo + '><font color=\"gray\">' + data.Log.Entries[c].timestamp + ':</font> ' + data.Log.Entries[c].text + '</div>';"
|
||||
"}"
|
||||
"}"
|
||||
"}"
|
||||
"timeForNext = data.Log.TTL;"
|
||||
"if (timeForNext < 1000) {"
|
||||
"reRunCount++;"
|
||||
"} else {"
|
||||
"reRunCount = 3;"
|
||||
"}"
|
||||
//"console.log(reRunCount + ' : ' + logEntriesChunk.length);"
|
||||
"if (reRunCount > 2) {"
|
||||
"if (logEntriesChunk !== '') {"
|
||||
"if (document.getElementById('copyText_1').innerHTML == 'Fetching log entries...') {"
|
||||
"document.getElementById('copyText_1').innerHTML = '';"
|
||||
"}"
|
||||
"document.getElementById('copyText_1').innerHTML += logEntriesChunk;"
|
||||
"}"
|
||||
"logEntriesChunk = '';"
|
||||
"reRunCount = 0;"
|
||||
"autoscroll_on = document.getElementById('autoscroll').checked;"
|
||||
"if (autoscroll_on == true && currentIDtoScrollTo !== '') {"
|
||||
"document.getElementById(currentIDtoScrollTo).scrollIntoView({"
|
||||
"behavior: scrolling_type"
|
||||
"});"
|
||||
"}"
|
||||
"}"
|
||||
"document.getElementById('current_loglevel').innerHTML = 'Logging: ' + logLevel[data.Log.SettingsWebLogLevel] + ' (' + data.Log.SettingsWebLogLevel + ')';"
|
||||
//"console.log('Next fetch in: ' + timeForNext + 'mSec, active requests: ' + activeRequests);"
|
||||
"clearInterval(i);"
|
||||
"loopDeLoop(timeForNext, 0, reRunCount);"
|
||||
"return;"
|
||||
"})"
|
||||
"})"
|
||||
".catch(function(err) {"
|
||||
"document.getElementById('copyText_1').innerHTML += '<div>>> ' + err.message + ' <<</div>';"
|
||||
"autoscroll_on = document.getElementById('autoscroll').checked;"
|
||||
"document.getElementById('copyText_1').scrollTop = document.getElementById('copyText_1').scrollHeight;"
|
||||
"timeForNext = 5000;"
|
||||
"clearInterval(i);"
|
||||
"loopDeLoop(timeForNext, 0, 0);"
|
||||
"return;"
|
||||
"})};"
|
||||
"check = 1;"
|
||||
"}, timeForNext);"
|
||||
"}"
|
||||
"</script>"
|
||||
};
|
||||
|
||||
#endif // WEBSTATICDATA_h
|
||||
-462
@@ -1,462 +0,0 @@
|
||||
//********************************************************************************
|
||||
// Determine Wifi AP name to set. (also used for mDNS)
|
||||
//********************************************************************************
|
||||
String WifiGetAPssid()
|
||||
{
|
||||
String ssid(Settings.Name);
|
||||
ssid+=F("-");
|
||||
ssid+=Settings.Unit;
|
||||
return (ssid);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Determine hostname: basically WifiGetAPssid with spaces changed to -
|
||||
//********************************************************************************
|
||||
String WifiGetHostname()
|
||||
{
|
||||
String hostname(WifiGetAPssid());
|
||||
hostname.replace(F(" "), F("-"));
|
||||
return (hostname);
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Set Wifi AP Mode config
|
||||
//********************************************************************************
|
||||
void WifiAPconfig()
|
||||
{
|
||||
// create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password!
|
||||
// setup ssid for AP Mode when needed
|
||||
|
||||
String softAPSSID=WifiGetAPssid();
|
||||
String pwd = SecuritySettings.WifiAPKey;
|
||||
WiFi.softAP(softAPSSID.c_str(),pwd.c_str());
|
||||
// We start in STA mode
|
||||
WifiAPMode(false);
|
||||
|
||||
String log("WIFI : AP Mode ssid will be ");
|
||||
log=log+WifiGetAPssid();
|
||||
|
||||
log=log+F(" with address ");
|
||||
log=log+apIP.toString();
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool WifiIsAP()
|
||||
{
|
||||
byte wifimode = wifi_get_opmode();
|
||||
return(wifimode == 2 || wifimode == 3); //apmode is enabled
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Set Wifi AP Mode
|
||||
//********************************************************************************
|
||||
void WifiAPMode(boolean state)
|
||||
{
|
||||
if (WifiIsAP())
|
||||
{
|
||||
//want to disable?
|
||||
if (!state)
|
||||
{
|
||||
WiFi.mode(WIFI_STA);
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : AP Mode disabled"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//want to enable?
|
||||
if (state)
|
||||
{
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : AP Mode enabled"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Set Wifi config
|
||||
//********************************************************************************
|
||||
bool prepareWiFi() {
|
||||
String log = "";
|
||||
char hostname[40];
|
||||
strncpy(hostname, WifiGetHostname().c_str(), sizeof(hostname));
|
||||
wifi_station_set_hostname(hostname);
|
||||
|
||||
//use static ip?
|
||||
if (Settings.IP[0] != 0 && Settings.IP[0] != 255)
|
||||
{
|
||||
char str[20];
|
||||
sprintf_P(str, PSTR("%u.%u.%u.%u"), Settings.IP[0], Settings.IP[1], Settings.IP[2], Settings.IP[3]);
|
||||
log = F("IP : Static IP :");
|
||||
log += str;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
IPAddress ip = Settings.IP;
|
||||
IPAddress gw = Settings.Gateway;
|
||||
IPAddress subnet = Settings.Subnet;
|
||||
IPAddress dns = Settings.DNS;
|
||||
WiFi.config(ip, gw, subnet, dns);
|
||||
}
|
||||
return selectValidWiFiSettings();
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP!"));
|
||||
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
|
||||
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 WifiConnectAndWait(byte connectAttempts)
|
||||
{
|
||||
String log;
|
||||
|
||||
wifiConnected = false;
|
||||
wifi_connect_attempt = 0;
|
||||
for (byte tryConnect = 0; tryConnect < connectAttempts; tryConnect++)
|
||||
{
|
||||
if (tryConnectWiFi()) {
|
||||
do {
|
||||
if (checkWifiJustConnected())
|
||||
return true;
|
||||
delay(50);
|
||||
} while (!wifiConnectTimeoutReached());
|
||||
}
|
||||
// log = F("WIFI : Disconnecting!");
|
||||
// addLog(LOG_LEVEL_INFO, log);
|
||||
#if defined(ESP8266)
|
||||
ETS_UART_INTR_DISABLE();
|
||||
wifi_station_disconnect();
|
||||
ETS_UART_INTR_ENABLE();
|
||||
#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
|
||||
//********************************************************************************
|
||||
void WifiDisconnect()
|
||||
{
|
||||
WiFi.disconnect();
|
||||
wifiConnected = false;
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Scan all Wifi Access Points
|
||||
//********************************************************************************
|
||||
void WifiScan()
|
||||
{
|
||||
// Direct Serial is allowed here, since this function will only be called from serial input.
|
||||
Serial.println(F("WIFI : SSID Scan start"));
|
||||
int n = WiFi.scanNetworks();
|
||||
if (n == 0)
|
||||
Serial.println(F("WIFI : No networks found"));
|
||||
else
|
||||
{
|
||||
Serial.print(F("WIFI : "));
|
||||
Serial.print(n);
|
||||
Serial.println(F(" networks found"));
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
// Print SSID and RSSI for each network found
|
||||
Serial.print(F("WIFI : "));
|
||||
Serial.print(i + 1);
|
||||
Serial.print(": ");
|
||||
Serial.print(WiFi.SSID(i));
|
||||
Serial.print(" (");
|
||||
Serial.print(WiFi.RSSI(i));
|
||||
Serial.print(")");
|
||||
Serial.println("");
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Check if we are still connected to a Wifi AP
|
||||
//********************************************************************************
|
||||
void WifiCheck()
|
||||
{
|
||||
if(wifiSetup)
|
||||
return;
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
NC_Count++;
|
||||
//give it time to automaticly reconnect
|
||||
if (NC_Count > 2)
|
||||
{
|
||||
if (wifiConnected) {
|
||||
wifi_connect_attempt = 0;
|
||||
wifiConnected = false;
|
||||
WiFiConnectRelaxed();
|
||||
}
|
||||
C_Count=0;
|
||||
NC_Count = 0;
|
||||
}
|
||||
}
|
||||
//connected
|
||||
else
|
||||
{
|
||||
C_Count++;
|
||||
NC_Count = 0;
|
||||
if (C_Count > 2) // disable AP after timeout if a Wifi connection is established...
|
||||
{
|
||||
WifiAPMode(false);
|
||||
}
|
||||
}
|
||||
if (!wifiConnected) {
|
||||
if (tryConnectWiFi())
|
||||
checkWifiJustConnected();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_C001
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 001: Domoticz HTTP ######################################
|
||||
//#######################################################################################################
|
||||
@@ -6,6 +7,7 @@
|
||||
#define CPLUGIN_ID_001 1
|
||||
#define CPLUGIN_NAME_001 "Domoticz HTTP"
|
||||
|
||||
|
||||
boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
@@ -164,3 +166,4 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_C002
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 002: Domoticz MQTT ######################################
|
||||
//#######################################################################################################
|
||||
@@ -209,3 +210,4 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-1
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_C003
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 003: Nodo Telnet #######################################
|
||||
//#######################################################################################################
|
||||
@@ -54,7 +55,7 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
|
||||
String url = F("variableset ");
|
||||
url += event->idx;
|
||||
url += ",";
|
||||
url += formatUserVar(event, 0);
|
||||
url += formatUserVarNoCheck(event, 0);
|
||||
url += "\n";
|
||||
|
||||
// strcpy_P(log, PSTR("TELNT: Sending enter"));
|
||||
@@ -107,3 +108,4 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
||||
+4
-2
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_C004
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 004: ThingSpeak #########################################
|
||||
//#######################################################################################################
|
||||
@@ -75,7 +76,7 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
|
||||
postDataStr += F("&field");
|
||||
postDataStr += event->idx + x;
|
||||
postDataStr += "=";
|
||||
postDataStr += formatUserVar(event, x);
|
||||
postDataStr += formatUserVarNoCheck(event, x);
|
||||
}
|
||||
String hostName = F("api.thingspeak.com"); // PM_CZ: HTTP requests must contain host headers.
|
||||
if (ControllerSettings.UseDNS)
|
||||
@@ -110,7 +111,7 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
if (line.substring(0, 15) == F("HTTP/1.1 200 OK"))
|
||||
{
|
||||
strcpy_P(log, PSTR("HTTP : Succes!"));
|
||||
strcpy_P(log, PSTR("HTTP : Success!"));
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
success = true;
|
||||
}
|
||||
@@ -127,3 +128,4 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
||||
+4
-4
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_C005
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 005: OpenHAB MQTT #######################################
|
||||
//#######################################################################################################
|
||||
@@ -104,10 +105,8 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
String tmppubname = pubname;
|
||||
tmppubname.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]);
|
||||
if (event->sensorType == SENSOR_TYPE_LONG)
|
||||
value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
else
|
||||
value = formatUserVar(event, x);
|
||||
value = formatUserVarNoCheck(event, x);
|
||||
|
||||
MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
|
||||
String log = F("MQTT : ");
|
||||
log += tmppubname;
|
||||
@@ -121,3 +120,4 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-4
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_C006
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 006: PiDome MQTT ########################################
|
||||
//#######################################################################################################
|
||||
@@ -98,10 +99,7 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
String tmppubname = pubname;
|
||||
tmppubname.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]);
|
||||
if (event->sensorType == SENSOR_TYPE_LONG)
|
||||
value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
else
|
||||
value = formatUserVar(event, x);
|
||||
value = formatUserVarNoCheck(event, x);
|
||||
MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
|
||||
}
|
||||
break;
|
||||
@@ -109,3 +107,4 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
||||
+4
-2
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_C007
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 007: Emoncms ############################################
|
||||
//#######################################################################################################
|
||||
@@ -70,7 +71,7 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
|
||||
postDataStr += F("field");
|
||||
postDataStr += event->idx + i;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, i);
|
||||
postDataStr += formatUserVarNoCheck(event, i);
|
||||
}
|
||||
postDataStr += "}";
|
||||
postDataStr += F("&apikey=");
|
||||
@@ -105,7 +106,7 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
if (line.substring(0, 15) == F("HTTP/1.1 200 OK"))
|
||||
{
|
||||
strcpy_P(log, PSTR("HTTP : Succes!"));
|
||||
strcpy_P(log, PSTR("HTTP : Success!"));
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
success = true;
|
||||
}
|
||||
@@ -122,3 +123,4 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
||||
+10
-11
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_C008
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 008: Generic HTTP #######################################
|
||||
//#######################################################################################################
|
||||
@@ -21,7 +22,7 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
|
||||
Protocol[protocolCount].usesAccount = true;
|
||||
Protocol[protocolCount].usesPassword = true;
|
||||
Protocol[protocolCount].defaultPort = 80;
|
||||
Protocol[protocolCount].usesID = false;
|
||||
Protocol[protocolCount].usesID = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -43,10 +44,10 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
|
||||
byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
for (byte x = 0; x < valueCount; x++)
|
||||
{
|
||||
if (event->sensorType == SENSOR_TYPE_LONG)
|
||||
HTTPSend(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16));
|
||||
else
|
||||
HTTPSend(event, x, UserVar[event->BaseVarIndex + x], 0);
|
||||
bool isvalid;
|
||||
String formattedValue = formatUserVar(event, x, isvalid);
|
||||
if (isvalid)
|
||||
HTTPSend(event, x, formattedValue);
|
||||
if (valueCount > 1)
|
||||
{
|
||||
delayBackground(Settings.MessageDelay);
|
||||
@@ -66,7 +67,7 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
|
||||
//********************************************************************************
|
||||
// Generic HTTP get request
|
||||
//********************************************************************************
|
||||
boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
|
||||
boolean HTTPSend(struct EventStruct *event, byte varIndex, const String& formattedValue)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return false;
|
||||
@@ -108,10 +109,7 @@ boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned
|
||||
parseControllerVariables(url, event, true);
|
||||
|
||||
url.replace(F("%valname%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex]));
|
||||
if (longValue)
|
||||
url.replace(F("%value%"), String(longValue));
|
||||
else
|
||||
url.replace(F("%value%"), toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]));
|
||||
url.replace(F("%value%"), formattedValue);
|
||||
|
||||
// url.toCharArray(log, 80);
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, url);
|
||||
@@ -135,7 +133,7 @@ boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, line);
|
||||
if (line.startsWith(F("HTTP/1.1 200 OK")))
|
||||
{
|
||||
// strcpy_P(log, PSTR("HTTP : Succes!"));
|
||||
// strcpy_P(log, PSTR("HTTP : Success!"));
|
||||
// addLog(LOG_LEVEL_DEBUG, log);
|
||||
addLog(LOG_LEVEL_DEBUG, F("HTTP : Success!"));
|
||||
// success = true;
|
||||
@@ -151,3 +149,4 @@ boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned
|
||||
|
||||
return(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
+4
-8
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_C009
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 009: FHEM HTTP ##########################################
|
||||
//#######################################################################################################
|
||||
@@ -20,7 +21,7 @@
|
||||
- moved on/off translation for SENSOR_TYPE_SWITCH/DIMMER to FHEM module
|
||||
- v1.03
|
||||
- changed http request from GET to POST (RFC conform)
|
||||
- removed obsolet http get url code
|
||||
- removed obsolete http get url code
|
||||
- v1.04
|
||||
- added build options and node_type_id to JSON/device
|
||||
/******************************************************************************/
|
||||
@@ -102,13 +103,7 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
|
||||
val[F("deviceName")] = ExtraTaskSettings.TaskDeviceName;
|
||||
val[F("valueName")] = ExtraTaskSettings.TaskDeviceValueNames[x];
|
||||
val[F("type")] = event->sensorType;
|
||||
|
||||
if (event->sensorType == SENSOR_TYPE_LONG) {
|
||||
val[F("value")] = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
}
|
||||
else { // All other sensor types
|
||||
val[F("value")] = formatUserVar(event, x);
|
||||
}
|
||||
val[F("value")] = formatUserVarNoCheck(event, x);
|
||||
}
|
||||
|
||||
// Create json buffer
|
||||
@@ -197,3 +192,4 @@ void FHEMHTTPsend(String & url, String & buffer, byte index)
|
||||
client.flush();
|
||||
client.stop();
|
||||
}
|
||||
#endif
|
||||
|
||||
+10
-11
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_C010
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 010: Generic UDP ########################################
|
||||
//#######################################################################################################
|
||||
@@ -42,10 +43,10 @@ boolean CPlugin_010(byte function, struct EventStruct *event, String& string)
|
||||
byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
for (byte x = 0; x < valueCount; x++)
|
||||
{
|
||||
if (event->sensorType == SENSOR_TYPE_LONG)
|
||||
C010_Send(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16));
|
||||
else
|
||||
C010_Send(event, x, UserVar[event->BaseVarIndex + x], 0);
|
||||
bool isvalid;
|
||||
String formattedValue = formatUserVar(event, x, isvalid);
|
||||
if (isvalid)
|
||||
C010_Send(event, x, formattedValue);
|
||||
if (valueCount > 1)
|
||||
{
|
||||
delayBackground(Settings.MessageDelay);
|
||||
@@ -65,7 +66,7 @@ boolean CPlugin_010(byte function, struct EventStruct *event, String& string)
|
||||
//********************************************************************************
|
||||
// Generic UDP message
|
||||
//********************************************************************************
|
||||
void C010_Send(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
|
||||
void C010_Send(struct EventStruct *event, byte varIndex, const String& formattedValue)
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
@@ -82,14 +83,11 @@ void C010_Send(struct EventStruct *event, byte varIndex, float value, unsigned l
|
||||
msg += ControllerSettings.Publish;
|
||||
parseControllerVariables(msg, event, false);
|
||||
msg.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[varIndex]);
|
||||
if (longValue)
|
||||
msg.replace(F("%value%"), String(longValue));
|
||||
else
|
||||
msg.replace(F("%value%"), toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]));
|
||||
msg.replace(F("%value%"), formattedValue);
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
if (wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
ControllerSettings.beginPacket(portUDP);
|
||||
portUDP.write(msg.c_str());
|
||||
portUDP.write((uint8_t*)msg.c_str(),msg.length());
|
||||
portUDP.endPacket();
|
||||
}
|
||||
|
||||
@@ -97,3 +95,4 @@ void C010_Send(struct EventStruct *event, byte varIndex, float value, unsigned l
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-1
@@ -1,8 +1,9 @@
|
||||
#ifdef USES_C011
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 011: Generic HTTP #######################################
|
||||
//#######################################################################################################
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
// #ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define CPLUGIN_011
|
||||
#define CPLUGIN_ID_011 11
|
||||
@@ -283,3 +284,4 @@ void ReplaceTokenByValue(String& s, struct EventStruct *event)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+5
-4
@@ -1,8 +1,9 @@
|
||||
#ifdef USES_C012
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 012: Blynk #############################################
|
||||
//#######################################################################################################
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
// #ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define CPLUGIN_012
|
||||
#define CPLUGIN_ID_012 12
|
||||
@@ -33,7 +34,7 @@ boolean CPlugin_012(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
@@ -54,7 +55,7 @@ boolean CPlugin_012_send(struct EventStruct *event, int nrValues) {
|
||||
postDataStr = F("update/V") ;
|
||||
postDataStr += event->idx + i;
|
||||
postDataStr += F("?value=");
|
||||
postDataStr += formatUserVar(event, i);
|
||||
postDataStr += formatUserVarNoCheck(event, i);
|
||||
success = Blynk_get(postDataStr, event->ControllerIndex);
|
||||
}
|
||||
return success;
|
||||
@@ -63,7 +64,7 @@ boolean CPlugin_012_send(struct EventStruct *event, int nrValues) {
|
||||
|
||||
boolean Blynk_get(const String& command, byte controllerIndex, float *data )
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_C013
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 013: ESPEasy P2P network ################################
|
||||
//#######################################################################################################
|
||||
@@ -262,4 +263,4 @@ void C013_Receive(struct EventStruct *event) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,7 +31,7 @@ int mapVccToDomoticz() {
|
||||
|
||||
// Format including trailing semi colon
|
||||
String formatUserVarDomoticz(struct EventStruct *event, byte rel_index) {
|
||||
String text = formatUserVar(event, rel_index);
|
||||
String text = formatUserVarNoCheck(event, rel_index);
|
||||
text += F(";");
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -6,11 +6,13 @@ byte getValueCountFromSensorType(byte sensorType)
|
||||
{
|
||||
switch (sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
|
||||
case SENSOR_TYPE_NONE:
|
||||
return 0;
|
||||
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
case SENSOR_TYPE_DIMMER:
|
||||
return 1;
|
||||
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
|
||||
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
|
||||
return 1;
|
||||
case SENSOR_TYPE_TEMP_HUM:
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
|
||||
+7
-4
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_N001
|
||||
//#######################################################################################################
|
||||
//########################### Notification Plugin 001: Email ############################################
|
||||
//#######################################################################################################
|
||||
@@ -64,7 +65,7 @@ boolean NPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
return success;
|
||||
}
|
||||
|
||||
boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, const String& aSub, const String& aMesg) {
|
||||
boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, const String& aSub, String& aMesg) {
|
||||
// String& aDomain , String aTo, String aFrom, String aSub, String aMesg, String aHost, int aPort)
|
||||
boolean myStatus = false;
|
||||
|
||||
@@ -92,6 +93,7 @@ boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings,
|
||||
mailheader.replace(String(F("$ato")), notificationsettings.Receiver);
|
||||
mailheader.replace(String(F("$subject")), aSub);
|
||||
mailheader.replace(String(F("$espeasyversion")), String(BUILD));
|
||||
aMesg.replace("\r", "<br/>"); // re-write line breaks for Content-type: text/html
|
||||
|
||||
// Wait for Client to Start Sending
|
||||
// The MTA Exchange
|
||||
@@ -100,10 +102,10 @@ boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings,
|
||||
if (!NPlugin_001_MTA(client, "", F("220 "))) break;
|
||||
if (!NPlugin_001_MTA(client, String(F("EHLO ")) + notificationsettings.Domain, F("250 "))) break;
|
||||
if (!NPlugin_001_Auth(client, notificationsettings.User, notificationsettings.Pass)) break;
|
||||
if (!NPlugin_001_MTA(client, String(F("MAIL FROM:")) + notificationsettings.Sender + "", F("250 "))) break;
|
||||
if (!NPlugin_001_MTA(client, String(F("RCPT TO:")) + notificationsettings.Receiver + "", F("250 "))) break;
|
||||
if (!NPlugin_001_MTA(client, String(F("MAIL FROM:<")) + notificationsettings.Sender + ">", F("250 "))) break;
|
||||
if (!NPlugin_001_MTA(client, String(F("RCPT TO:<")) + notificationsettings.Receiver + ">", F("250 "))) break;
|
||||
if (!NPlugin_001_MTA(client, F("DATA"), F("354 "))) break;
|
||||
if (!NPlugin_001_MTA(client, mailheader + aMesg + String(F("\r\n.\r\n")), F("250 "))) break;
|
||||
if (!NPlugin_001_MTA(client, mailheader + aMesg + String(F("\r\n.\r\n")), F("250 "))) break;
|
||||
|
||||
myStatus = true;
|
||||
break;
|
||||
@@ -174,3 +176,4 @@ boolean NPlugin_001_MTA(WiFiClient& client, String aStr, const String &aWaitForP
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_N002
|
||||
//#######################################################################################################
|
||||
//########################### Notification Plugin 002: Buzzer ###########################################
|
||||
//#######################################################################################################
|
||||
@@ -45,11 +46,15 @@ boolean NPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
NotificationSettingsStruct NotificationSettings;
|
||||
LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettings));
|
||||
//this reserves IRAM and uninitalized RAM
|
||||
//this reserves IRAM and uninitialized RAM
|
||||
#ifndef ESP32
|
||||
// Buzzer not compatible with ESP32 due to lack of tone command.
|
||||
tone(NotificationSettings.Pin1, 500, 500);
|
||||
#endif
|
||||
success = true;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
||||
+128
-29
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P001
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 001: Input Switch #########################################
|
||||
//#######################################################################################################
|
||||
@@ -6,9 +7,11 @@
|
||||
#define PLUGIN_ID_001 1
|
||||
#define PLUGIN_NAME_001 "Switch input - Switch"
|
||||
#define PLUGIN_VALUENAME1_001 "Switch"
|
||||
Servo servo1;
|
||||
Servo servo2;
|
||||
|
||||
#if defined(ESP8266)
|
||||
Servo servo1;
|
||||
Servo servo2;
|
||||
#endif
|
||||
#define GPIO_MAX 17
|
||||
// Make sure the initial default is a switch (value 0)
|
||||
#define PLUGIN_001_TYPE_SWITCH 0
|
||||
#define PLUGIN_001_TYPE_DIMMER 3 // Due to some changes in previous versions, do not use 2.
|
||||
@@ -25,6 +28,8 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
boolean success = false;
|
||||
static boolean switchstate[TASKS_MAX];
|
||||
static boolean outputstate[TASKS_MAX];
|
||||
static int8_t PinMonitor[GPIO_MAX];
|
||||
static int8_t PinMonitorState[GPIO_MAX];
|
||||
|
||||
switch (function)
|
||||
{
|
||||
@@ -64,13 +69,13 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
options[1] = F("Dimmer");
|
||||
int optionValues[2] = { PLUGIN_001_TYPE_SWITCH, PLUGIN_001_TYPE_DIMMER };
|
||||
const byte switchtype = P001_getSwitchType(event);
|
||||
addFormSelector(string, F("Switch Type"), F("plugin_001_type"), 2, options, optionValues, switchtype);
|
||||
addFormSelector(F("Switch Type"), F("plugin_001_type"), 2, options, optionValues, switchtype);
|
||||
|
||||
if (switchtype == PLUGIN_001_TYPE_DIMMER)
|
||||
{
|
||||
char tmpString[128];
|
||||
sprintf_P(tmpString, PSTR("<TR><TD>Dim value:<TD><input type='text' name='plugin_001_dimvalue' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
|
||||
string += tmpString;
|
||||
addHtml(tmpString);
|
||||
}
|
||||
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
|
||||
@@ -79,9 +84,9 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
buttonOptions[1] = F("Push Button Active Low");
|
||||
buttonOptions[2] = F("Push Button Active High");
|
||||
int buttonOptionValues[3] = {PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH};
|
||||
addFormSelector(string, F("Switch Button Type"), F("plugin_001_button"), 3, buttonOptions, buttonOptionValues, choice);
|
||||
addFormSelector(F("Switch Button Type"), F("plugin_001_button"), 3, buttonOptions, buttonOptionValues, choice);
|
||||
|
||||
addFormCheckBox(string, F("Send Boot state"),F("plugin_001_boot"),
|
||||
addFormCheckBox(F("Send Boot state"),F("plugin_001_boot"),
|
||||
Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
|
||||
|
||||
success = true;
|
||||
@@ -106,6 +111,11 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
for (byte x=0; x < GPIO_MAX; x++){
|
||||
PinMonitor[x] = 0;
|
||||
PinMonitorState[x] = 0;
|
||||
}
|
||||
|
||||
if (Settings.TaskDevicePin1PullUp[event->TaskIndex])
|
||||
pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP);
|
||||
else
|
||||
@@ -126,6 +136,38 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_REQUEST:
|
||||
{
|
||||
String device = parseString(string, 1);
|
||||
String command = parseString(string, 2);
|
||||
String strPar1 = parseString(string, 3);
|
||||
int par1 = strPar1.toInt();
|
||||
if (device == F("gpio") && command == F("pinstate"))
|
||||
{
|
||||
string = digitalRead(par1);
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_UNCONDITIONAL_POLL:
|
||||
{
|
||||
// port monitoring, on request by rule command
|
||||
for (byte x=0; x < GPIO_MAX; x++)
|
||||
if (PinMonitor[x] != 0){
|
||||
byte state = digitalRead(x);
|
||||
if (PinMonitorState[x] != state){
|
||||
String eventString = F("GPIO#");
|
||||
eventString += x;
|
||||
eventString += F("=");
|
||||
eventString += state;
|
||||
rulesProcessing(eventString);
|
||||
PinMonitorState[x] = state;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_TEN_PER_SECOND:
|
||||
{
|
||||
const boolean state = Plugin_001_read_switch_state(event);
|
||||
@@ -197,11 +239,16 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
if (command == F("gpio"))
|
||||
{
|
||||
success = true;
|
||||
if (event->Par1 >= 0 && event->Par1 <= 16)
|
||||
if (event->Par1 >= 0 && event->Par1 <= PIN_D_MAX)
|
||||
{
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
digitalWrite(event->Par1, event->Par2);
|
||||
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
|
||||
if (event->Par2 == 2) {
|
||||
pinMode(event->Par1, INPUT);
|
||||
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_INPUT, 0);
|
||||
} else {
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
digitalWrite(event->Par1, event->Par2);
|
||||
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
|
||||
}
|
||||
log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Set to ")) + String(event->Par2);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
|
||||
@@ -211,10 +258,11 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
if (command == F("pwm"))
|
||||
{
|
||||
success = true;
|
||||
if (event->Par1 >= 0 && event->Par1 <= 16)
|
||||
if (event->Par1 >= 0 && event->Par1 <= PIN_D_MAX)
|
||||
{
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
|
||||
#if defined(ESP8266)
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
#endif
|
||||
if(event->Par3 != 0)
|
||||
{
|
||||
byte prev_mode;
|
||||
@@ -231,12 +279,22 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
curr_value += step_value;
|
||||
int16_t new_value;
|
||||
new_value = (uint16_t)(curr_value >> 12);
|
||||
analogWrite(event->Par1, new_value);
|
||||
#if defined(ESP8266)
|
||||
analogWrite(event->Par1, new_value);
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
analogWriteESP32(event->Par1, new_value);
|
||||
#endif
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
analogWrite(event->Par1, event->Par2);
|
||||
#if defined(ESP8266)
|
||||
analogWrite(event->Par1, event->Par2);
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
analogWriteESP32(event->Par1, event->Par2);
|
||||
#endif
|
||||
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_PWM, event->Par2);
|
||||
log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Set PWM to ")) + String(event->Par2);
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
@@ -247,7 +305,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
if (command == F("pulse"))
|
||||
{
|
||||
success = true;
|
||||
if (event->Par1 >= 0 && event->Par1 <= 16)
|
||||
if (event->Par1 >= 0 && event->Par1 <= PIN_D_MAX)
|
||||
{
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
digitalWrite(event->Par1, event->Par2);
|
||||
@@ -264,7 +322,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean time_in_msec = command == F("longpulse_ms");
|
||||
success = true;
|
||||
if (event->Par1 >= 0 && event->Par1 <= 16)
|
||||
if (event->Par1 >= 0 && event->Par1 <= PIN_D_MAX)
|
||||
{
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
digitalWrite(event->Par1, event->Par2);
|
||||
@@ -287,12 +345,16 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
case 1:
|
||||
|
||||
//IRAM: doing servo stuff uses 740 bytes IRAM. (doesnt matter how many instances)
|
||||
servo1.attach(event->Par2);
|
||||
servo1.write(event->Par3);
|
||||
#if defined(ESP8266)
|
||||
servo1.attach(event->Par2);
|
||||
servo1.write(event->Par3);
|
||||
#endif
|
||||
break;
|
||||
case 2:
|
||||
servo2.attach(event->Par2);
|
||||
servo2.write(event->Par3);
|
||||
#if defined(ESP8266)
|
||||
servo2.attach(event->Par2);
|
||||
servo2.write(event->Par3);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
setPinState(PLUGIN_ID_001, event->Par2, PIN_MODE_SERVO, event->Par3);
|
||||
@@ -310,6 +372,15 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
}
|
||||
|
||||
if (command == F("monitor"))
|
||||
{
|
||||
if (parseString(string, 2) == F("gpio"))
|
||||
{
|
||||
PinMonitor[event->Par2] = 1;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (command == F("inputswitchstate"))
|
||||
{
|
||||
success = true;
|
||||
@@ -317,7 +388,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
outputstate[event->Par1] = event->Par2;
|
||||
}
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
// FIXME: Absolutely no error checking in play_rtttl, until then keep it only in testing
|
||||
//play a tune via a RTTTL string, look at https://www.letscontrolit.com/forum/viewtopic.php?f=4&t=343&hilit=speaker&start=10 for more info.
|
||||
if (command == F("rtttl"))
|
||||
{
|
||||
@@ -325,10 +396,11 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
if (event->Par1 >= 0 && event->Par1 <= 16)
|
||||
{
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
char sng[1024] ="";
|
||||
string.replace("-","#");
|
||||
string.toCharArray(sng, 1024);
|
||||
play_rtttl(event->Par1, sng);
|
||||
// char sng[1024] ="";
|
||||
String tmpString=string;
|
||||
tmpString.replace("-","#");
|
||||
// tmpString.toCharArray(sng, 1024);
|
||||
play_rtttl(event->Par1, tmpString.c_str());
|
||||
setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2);
|
||||
log = String(F("SW : ")) + string;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
@@ -340,7 +412,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
if (command == F("tone"))
|
||||
{
|
||||
success = true;
|
||||
if (event->Par1 >= 0 && event->Par1 <= 16)
|
||||
if (event->Par1 >= 0 && event->Par1 <= PIN_D_MAX)
|
||||
{
|
||||
pinMode(event->Par1, OUTPUT);
|
||||
tone(event->Par1, event->Par2, event->Par3);
|
||||
@@ -350,7 +422,6 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -365,6 +436,33 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
#if defined(ESP32)
|
||||
void analogWriteESP32(int pin, int value)
|
||||
{
|
||||
// find existing channel if this pin has been used before
|
||||
int8_t ledChannel = -1;
|
||||
for(byte x = 0; x < 16; x++)
|
||||
if (ledChannelPin[x] == pin)
|
||||
ledChannel = x;
|
||||
|
||||
if(ledChannel == -1) // no channel set for this pin
|
||||
{
|
||||
for(byte x = 0; x < 16; x++) // find free channel
|
||||
if (ledChannelPin[x] == -1)
|
||||
{
|
||||
int freq = 5000;
|
||||
ledChannelPin[x] = pin; // store pin nr
|
||||
ledcSetup(x, freq, 10); // setup channel
|
||||
ledcAttachPin(pin, x); // attach to this pin
|
||||
ledChannel = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ledcWrite(ledChannel, value);
|
||||
}
|
||||
#endif
|
||||
|
||||
// TD-er: Needed to fix a mistake in earlier fixes.
|
||||
byte P001_getSwitchType(struct EventStruct *event) {
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
@@ -381,3 +479,4 @@ byte P001_getSwitchType(struct EventStruct *event) {
|
||||
}
|
||||
return choice;
|
||||
}
|
||||
#endif // USES_P001
|
||||
|
||||
+28
-11
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P002
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 002: Analog ###############################################
|
||||
//#######################################################################################################
|
||||
@@ -47,19 +48,24 @@ boolean Plugin_002(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
addFormCheckBox(string, F("Oversampling"), F("plugin_002_oversampling"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
|
||||
#if defined(ESP32)
|
||||
addHtml(F("<TR><TD>Analog Pin:<TD>"));
|
||||
addPinSelect(false, "taskdevicepin1", Settings.TaskDevicePin1[event->TaskIndex]);
|
||||
#endif
|
||||
|
||||
addFormSubHeader(string, F("Two Point Calibration"));
|
||||
addFormCheckBox(F("Oversampling"), F("plugin_002_oversampling"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
|
||||
|
||||
addFormCheckBox(string, F("Calibration Enabled"), F("plugin_002_cal"), Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
|
||||
addFormSubHeader(F("Two Point Calibration"));
|
||||
|
||||
addFormNumericBox(string, F("Point 1"), F("plugin_002_adc1"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][0], 0, 1023);
|
||||
string += F(" ≙ ");
|
||||
addTextBox(string, F("plugin_002_out1"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0], 3), 10);
|
||||
addFormCheckBox(F("Calibration Enabled"), F("plugin_002_cal"), Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
|
||||
|
||||
addFormNumericBox(string, F("Point 2"), F("plugin_002_adc2"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1], 0, 1023);
|
||||
string += F(" ≙ ");
|
||||
addTextBox(string, F("plugin_002_out2"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1], 3), 10);
|
||||
addFormNumericBox(F("Point 1"), F("plugin_002_adc1"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][0], 0, 1023);
|
||||
addHtml(F(" ≙ "));
|
||||
addTextBox(F("plugin_002_out1"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0], 3), 10);
|
||||
|
||||
addFormNumericBox(F("Point 2"), F("plugin_002_adc2"), Settings.TaskDevicePluginConfigLong[event->TaskIndex][1], 0, 1023);
|
||||
addHtml(F(" ≙ "));
|
||||
addTextBox(F("plugin_002_out2"), String(Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1], 3), 10);
|
||||
|
||||
success = true;
|
||||
break;
|
||||
@@ -85,7 +91,12 @@ boolean Plugin_002(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0]) //Oversampling?
|
||||
{
|
||||
Plugin_002_OversamplingValue += analogRead(A0);
|
||||
#if defined(ESP8266)
|
||||
Plugin_002_OversamplingValue += analogRead(A0);
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
Plugin_002_OversamplingValue += analogRead(Settings.TaskDevicePin1[event->TaskIndex]);
|
||||
#endif
|
||||
Plugin_002_OversamplingCount ++;
|
||||
}
|
||||
success = true;
|
||||
@@ -106,7 +117,12 @@ boolean Plugin_002(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
else
|
||||
{
|
||||
int16_t value = analogRead(A0);
|
||||
#if defined(ESP8266)
|
||||
int16_t value = analogRead(A0);
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
int16_t value = analogRead(Settings.TaskDevicePin1[event->TaskIndex]);
|
||||
#endif
|
||||
UserVar[event->BaseVarIndex] = (float)value;
|
||||
|
||||
log += value;
|
||||
@@ -135,3 +151,4 @@ boolean Plugin_002(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif // USES_P002
|
||||
|
||||
+6
-4
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P003
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 003: Pulse ###############################################
|
||||
//#######################################################################################################
|
||||
@@ -64,16 +65,16 @@ boolean Plugin_003(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
addFormNumericBox(string, F("Debounce Time (mSec)"), F("plugin_003")
|
||||
addFormNumericBox(F("Debounce Time (mSec)"), F("plugin_003")
|
||||
, Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
|
||||
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
|
||||
byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
|
||||
String options[4] = { F("Delta"), F("Delta/Total/Time"), F("Total"), F("Delta/Total") };
|
||||
addFormSelector(string, F("Counter Type"), F("plugin_003_countertype"), 4, options, NULL, choice );
|
||||
addFormSelector(F("Counter Type"), F("plugin_003_countertype"), 4, options, NULL, choice );
|
||||
|
||||
if (choice !=0)
|
||||
string += F("<span style=\"color:red\">Total count is not persistent!</span>");
|
||||
addHtml(F("<span style=\"color:red\">Total count is not persistent!</span>"));
|
||||
|
||||
String modeRaise[4];
|
||||
modeRaise[0] = F("LOW");
|
||||
@@ -86,7 +87,7 @@ boolean Plugin_003(byte function, struct EventStruct *event, String& string)
|
||||
modeValues[2] = RISING;
|
||||
modeValues[3] = FALLING;
|
||||
|
||||
addFormSelector(string, F("Mode Type"), F("plugin_003_raisetype"), 4, modeRaise, modeValues, choice2 );
|
||||
addFormSelector(F("Mode Type"), F("plugin_003_raisetype"), 4, modeRaise, modeValues, choice2 );
|
||||
|
||||
success = true;
|
||||
break;
|
||||
@@ -267,3 +268,4 @@ bool Plugin_003_pulseinit(byte Par1, byte Index, byte Mode)
|
||||
|
||||
return(true);
|
||||
}
|
||||
#endif // USES_P003
|
||||
|
||||
+158
-110
@@ -1,13 +1,21 @@
|
||||
#ifdef USES_P004
|
||||
// #######################################################################################################
|
||||
// #################################### Plugin 004: TempSensor Dallas DS18B20 ###########################
|
||||
// #######################################################################################################
|
||||
|
||||
// Maxim Integrated (ex Dallas) DS18B20 datasheet : https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf
|
||||
|
||||
#if defined(ESP32)
|
||||
#define ESP32noInterrupts() {portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;portENTER_CRITICAL(&mux)
|
||||
#define ESP32interrupts() portEXIT_CRITICAL(&mux);}
|
||||
#endif
|
||||
|
||||
#define PLUGIN_004
|
||||
#define PLUGIN_ID_004 4
|
||||
#define PLUGIN_NAME_004 "Environment - DS18b20"
|
||||
#define PLUGIN_VALUENAME1_004 "Temperature"
|
||||
|
||||
uint8_t Plugin_004_DallasPin;
|
||||
int8_t Plugin_004_DallasPin;
|
||||
|
||||
boolean Plugin_004(byte function, struct EventStruct * event, String& string)
|
||||
{
|
||||
@@ -47,47 +55,46 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
|
||||
{
|
||||
uint8_t savedAddress[8];
|
||||
byte resolutionChoice = 0;
|
||||
|
||||
// Scan the onewire bus and fill dropdown list with devicecount on this GPIO.
|
||||
Plugin_004_DallasPin = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
|
||||
// get currently saved address
|
||||
for (byte i = 0; i < 8; i++) {
|
||||
savedAddress[i] = ExtraTaskSettings.TaskDevicePluginConfigLong[i];
|
||||
if (Plugin_004_DallasPin != -1){
|
||||
// get currently saved address
|
||||
for (byte i = 0; i < 8; i++)
|
||||
savedAddress[i] = ExtraTaskSettings.TaskDevicePluginConfigLong[i];
|
||||
|
||||
// find all suitable devices
|
||||
addRowLabel(F("Device Address"));
|
||||
addSelector_Head(F("plugin_004_dev"), false);
|
||||
addSelector_Item("", -1, false, false, F(""));
|
||||
uint8_t tmpAddress[8];
|
||||
byte count = 0;
|
||||
Plugin_004_DS_reset();
|
||||
Plugin_004_DS_reset_search();
|
||||
while (Plugin_004_DS_search(tmpAddress))
|
||||
{
|
||||
String option = "";
|
||||
for (byte j = 0; j < 8; j++)
|
||||
{
|
||||
option += String(tmpAddress[j], HEX);
|
||||
if (j < 7) option += F("-");
|
||||
}
|
||||
bool selected = (memcmp(tmpAddress, savedAddress, 8) == 0) ? true : false;
|
||||
addSelector_Item(option, count, selected, false, F(""));
|
||||
count ++;
|
||||
}
|
||||
addSelector_Foot();
|
||||
|
||||
// Device Resolution select
|
||||
if (ExtraTaskSettings.TaskDevicePluginConfigLong[0] != 0)
|
||||
resolutionChoice = Plugin_004_DS_getResolution(savedAddress);
|
||||
else
|
||||
resolutionChoice = 9;
|
||||
String resultsOptions[4] = { "9", "10", "11", "12" };
|
||||
int resultsOptionValues[4] = { 9, 10, 11, 12 };
|
||||
addFormSelector(F("Device Resolution"), F("plugin_004_res"), 4, resultsOptions, resultsOptionValues, resolutionChoice);
|
||||
addHtml(F(" Bit"));
|
||||
}
|
||||
|
||||
// find all suitable devices
|
||||
addRowLabel(string, F("Device Address"));
|
||||
addSelector_Head(string, F("plugin_004_dev"), false);
|
||||
addSelector_Item(string, "", -1, false, false, F(""));
|
||||
uint8_t tmpAddress[8];
|
||||
byte count = 0;
|
||||
Plugin_004_DS_reset();
|
||||
Plugin_004_DS_reset_search();
|
||||
while (Plugin_004_DS_search(tmpAddress))
|
||||
{
|
||||
String option = "";
|
||||
for (byte j = 0; j < 8; j++)
|
||||
{
|
||||
option += String(tmpAddress[j], HEX);
|
||||
if (j < 7) option += F("-");
|
||||
}
|
||||
bool selected = (memcmp(tmpAddress, savedAddress, 8) == 0) ? true : false;
|
||||
addSelector_Item(string, option, count, selected, false, F(""));
|
||||
count ++;
|
||||
}
|
||||
addSelector_Foot(string);
|
||||
|
||||
// Device Resolution select
|
||||
if (ExtraTaskSettings.TaskDevicePluginConfigLong[0] != 0)
|
||||
resolutionChoice = Plugin_004_DS_getResolution(savedAddress);
|
||||
else
|
||||
resolutionChoice = 9;
|
||||
String resultsOptions[4] = { "9", "10", "11", "12" };
|
||||
int resultsOptionValues[4] = { 9, 10, 11, 12 };
|
||||
addFormSelector(string, F("Device Resolution"), F("plugin_004_res"), 4, resultsOptions, resultsOptionValues, resolutionChoice);
|
||||
string += F(" Bit");
|
||||
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -99,12 +106,14 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
|
||||
// save the address for selected device and store into extra tasksettings
|
||||
Plugin_004_DallasPin = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
// byte devCount =
|
||||
Plugin_004_DS_scan(getFormItemInt(F("plugin_004_dev")), addr);
|
||||
for (byte x = 0; x < 8; x++)
|
||||
ExtraTaskSettings.TaskDevicePluginConfigLong[x] = addr[x];
|
||||
|
||||
Plugin_004_DS_setResolution(addr, getFormItemInt(F("plugin_004_res")));
|
||||
if (Plugin_004_DallasPin != -1){
|
||||
Plugin_004_DS_scan(getFormItemInt(F("plugin_004_dev")), addr);
|
||||
for (byte x = 0; x < 8; x++)
|
||||
ExtraTaskSettings.TaskDevicePluginConfigLong[x] = addr[x];
|
||||
|
||||
Plugin_004_DS_setResolution(addr, getFormItemInt(F("plugin_004_res")));
|
||||
Plugin_004_DS_startConvertion(addr);
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -115,7 +124,19 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
|
||||
{
|
||||
if (x != 0)
|
||||
string += "-";
|
||||
string += String(ExtraTaskSettings.TaskDevicePluginConfigLong[x], HEX);
|
||||
// string += String(ExtraTaskSettings.TaskDevicePluginConfigLong[x], HEX);
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
case PLUGIN_INIT:
|
||||
{
|
||||
Plugin_004_DallasPin = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
if (Plugin_004_DallasPin != -1){
|
||||
uint8_t addr[8];
|
||||
Plugin_004_get_addr(addr, event->TaskIndex);
|
||||
Plugin_004_DS_startConvertion(addr);
|
||||
delay(800); //give it time to do intial conversion
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
@@ -125,14 +146,12 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
|
||||
{
|
||||
if (ExtraTaskSettings.TaskDevicePluginConfigLong[0] != 0){
|
||||
uint8_t addr[8];
|
||||
// Load ROM address from tasksettings
|
||||
LoadTaskSettings(event->TaskIndex);
|
||||
for (byte x = 0; x < 8; x++)
|
||||
addr[x] = ExtraTaskSettings.TaskDevicePluginConfigLong[x];
|
||||
Plugin_004_get_addr(addr, event->TaskIndex);
|
||||
|
||||
Plugin_004_DallasPin = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
float value = 0;
|
||||
String log = F("DS : Temperature: ");
|
||||
|
||||
if (Plugin_004_DS_readTemp(addr, &value))
|
||||
{
|
||||
UserVar[event->BaseVarIndex] = value;
|
||||
@@ -144,6 +163,7 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
|
||||
UserVar[event->BaseVarIndex] = NAN;
|
||||
log += F("Error!");
|
||||
}
|
||||
Plugin_004_DS_startConvertion(addr);
|
||||
|
||||
log += (" (");
|
||||
for (byte x = 0; x < 8; x++)
|
||||
@@ -162,28 +182,53 @@ boolean Plugin_004(byte function, struct EventStruct * event, String& string)
|
||||
return success;
|
||||
}
|
||||
|
||||
void Plugin_004_get_addr(uint8_t addr[], byte TaskIndex)
|
||||
{
|
||||
// Load ROM address from tasksettings
|
||||
LoadTaskSettings(TaskIndex);
|
||||
for (byte x = 0; x < 8; x++)
|
||||
addr[x] = ExtraTaskSettings.TaskDevicePluginConfigLong[x];
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Dallas Scan bus
|
||||
\*********************************************************************************************/
|
||||
byte Plugin_004_DS_scan(byte getDeviceROM, uint8_t* ROM)
|
||||
{
|
||||
byte tmpaddr[8];
|
||||
byte devCount = 0;
|
||||
Plugin_004_DS_reset();
|
||||
byte tmpaddr[8];
|
||||
byte devCount = 0;
|
||||
Plugin_004_DS_reset();
|
||||
|
||||
Plugin_004_DS_reset_search();
|
||||
while (Plugin_004_DS_search(tmpaddr))
|
||||
{
|
||||
if (getDeviceROM == devCount)
|
||||
for (byte i = 0; i < 8; i++)
|
||||
ROM[i] = tmpaddr[i];
|
||||
devCount++;
|
||||
}
|
||||
return devCount;
|
||||
Plugin_004_DS_reset_search();
|
||||
while (Plugin_004_DS_search(tmpaddr))
|
||||
{
|
||||
if (getDeviceROM == devCount)
|
||||
for (byte i = 0; i < 8; i++)
|
||||
ROM[i] = tmpaddr[i];
|
||||
devCount++;
|
||||
}
|
||||
return devCount;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Dallas Read temperature
|
||||
* Dallas Start Temperature Conversion, expected duration:
|
||||
* 9 bits resolution -> 93.75 ms
|
||||
* 10 bits resolution -> 187.5 ms
|
||||
* 11 bits resolution -> 375 ms
|
||||
* 12 bits resolution -> 750 ms
|
||||
\*********************************************************************************************/
|
||||
void Plugin_004_DS_startConvertion(uint8_t ROM[8])
|
||||
{
|
||||
Plugin_004_DS_reset();
|
||||
Plugin_004_DS_write(0x55); // Choose ROM
|
||||
for (byte i = 0; i < 8; i++)
|
||||
Plugin_004_DS_write(ROM[i]);
|
||||
Plugin_004_DS_write(0x44); // Take temperature mesurement
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Dallas Read temperature from scratchpad
|
||||
\*********************************************************************************************/
|
||||
boolean Plugin_004_DS_readTemp(uint8_t ROM[8], float * value)
|
||||
{
|
||||
@@ -194,43 +239,36 @@ boolean Plugin_004_DS_readTemp(uint8_t ROM[8], float * value)
|
||||
Plugin_004_DS_write(0x55); // Choose ROM
|
||||
for (byte i = 0; i < 8; i++)
|
||||
Plugin_004_DS_write(ROM[i]);
|
||||
Plugin_004_DS_write(0x44);
|
||||
|
||||
delay(800);
|
||||
|
||||
Plugin_004_DS_reset();
|
||||
Plugin_004_DS_write(0x55); // Choose ROM
|
||||
for (byte i = 0; i < 8; i++)
|
||||
Plugin_004_DS_write(ROM[i]);
|
||||
Plugin_004_DS_write(0xBE); // Read scratchpad
|
||||
|
||||
for (byte i = 0; i < 9; i++) // copy 8 bytes
|
||||
for (byte i = 0; i < 9; i++) // read 9 bytes
|
||||
ScratchPad[i] = Plugin_004_DS_read();
|
||||
|
||||
if (Plugin_004_DS_crc8(ScratchPad, 8) != ScratchPad[8])
|
||||
if (!Plugin_004_DS_crc8(ScratchPad))
|
||||
{
|
||||
*value = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((ROM[0] == 0x28 ) || (ROM[0] == 0x3b)) // DS18B20 or DS1825
|
||||
if ((ROM[0] == 0x28 ) || (ROM[0] == 0x3b) || (ROM[0] == 0x22)) // DS18B20 or DS1825 or DS1822
|
||||
{
|
||||
DSTemp = (ScratchPad[1] << 8) + ScratchPad[0];
|
||||
if (DSTemp == 0x550) // power-on reset value
|
||||
return false;
|
||||
*value = (float(DSTemp) * 0.0625);
|
||||
}
|
||||
else if (ROM[0] == 0x10) // DS1820 DS18S20
|
||||
{
|
||||
if (ScratchPad[0] == 0xaa) // power-on reset value
|
||||
return false;
|
||||
DSTemp = (ScratchPad[1] << 11) | ScratchPad[0] << 3;
|
||||
DSTemp = ((DSTemp & 0xfff0) << 3) - 16 +
|
||||
(
|
||||
((ScratchPad[7] - ScratchPad[6]) << 7) /
|
||||
ScratchPad[7]
|
||||
);
|
||||
(((ScratchPad[7] - ScratchPad[6]) << 7) / ScratchPad[7]);
|
||||
*value = float(DSTemp) * 0.0078125;
|
||||
}
|
||||
|
||||
return true;
|
||||
} // Plugin_004_DS_readTemp
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Dallas Get Resolution
|
||||
@@ -245,19 +283,15 @@ int Plugin_004_DS_getResolution(uint8_t ROM[8])
|
||||
Plugin_004_DS_reset();
|
||||
Plugin_004_DS_write(0x55); // Choose ROM
|
||||
for (byte i = 0; i < 8; i++)
|
||||
{
|
||||
Plugin_004_DS_write(ROM[i]);
|
||||
}
|
||||
|
||||
Plugin_004_DS_write(0xBE); // Read scratchpad
|
||||
|
||||
for (byte i = 0; i < 9; i++) // copy 8 bytes
|
||||
for (byte i = 0; i < 9; i++) // read 9 bytes
|
||||
ScratchPad[i] = Plugin_004_DS_read();
|
||||
|
||||
if (Plugin_004_DS_crc8(ScratchPad, 8) != ScratchPad[8])
|
||||
{
|
||||
if (!Plugin_004_DS_crc8(ScratchPad))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (ScratchPad[4])
|
||||
@@ -272,6 +306,7 @@ int Plugin_004_DS_getResolution(uint8_t ROM[8])
|
||||
return 10;
|
||||
|
||||
case 0x1F: // 9 bit
|
||||
default:
|
||||
return 9;
|
||||
}
|
||||
}
|
||||
@@ -291,44 +326,38 @@ boolean Plugin_004_DS_setResolution(uint8_t ROM[8], byte res)
|
||||
Plugin_004_DS_reset();
|
||||
Plugin_004_DS_write(0x55); // Choose ROM
|
||||
for (byte i = 0; i < 8; i++)
|
||||
{
|
||||
Plugin_004_DS_write(ROM[i]);
|
||||
}
|
||||
|
||||
Plugin_004_DS_write(0xBE); // Read scratchpad
|
||||
|
||||
for (byte i = 0; i < 9; i++) // copy 8 bytes
|
||||
for (byte i = 0; i < 9; i++) // read 9 bytes
|
||||
ScratchPad[i] = Plugin_004_DS_read();
|
||||
|
||||
if (Plugin_004_DS_crc8(ScratchPad, 8) != ScratchPad[8])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!Plugin_004_DS_crc8(ScratchPad))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
switch (res)
|
||||
{
|
||||
case 12:
|
||||
ScratchPad[4] = 0x7F; // 12 bit
|
||||
ScratchPad[4] = 0x7F; // 12 bits
|
||||
break;
|
||||
case 11:
|
||||
ScratchPad[4] = 0x5F; // 11 bit
|
||||
ScratchPad[4] = 0x5F; // 11 bits
|
||||
break;
|
||||
case 10:
|
||||
ScratchPad[4] = 0x3F; // 10 bit
|
||||
ScratchPad[4] = 0x3F; // 10 bits
|
||||
break;
|
||||
case 9:
|
||||
default:
|
||||
ScratchPad[4] = 0x1F; // 9 bit
|
||||
ScratchPad[4] = 0x1F; // 9 bits
|
||||
break;
|
||||
}
|
||||
|
||||
Plugin_004_DS_reset();
|
||||
Plugin_004_DS_write(0x55); // Choose ROM
|
||||
for (byte i = 0; i < 8; i++)
|
||||
{
|
||||
Plugin_004_DS_write(ROM[i]);
|
||||
}
|
||||
|
||||
Plugin_004_DS_write(0x4E); // Write to EEPROM
|
||||
Plugin_004_DS_write(ScratchPad[2]); // high alarm temp
|
||||
@@ -337,9 +366,7 @@ boolean Plugin_004_DS_setResolution(uint8_t ROM[8], byte res)
|
||||
|
||||
Plugin_004_DS_write(0x55); // Choose ROM
|
||||
for (byte i = 0; i < 8; i++)
|
||||
{
|
||||
Plugin_004_DS_write(ROM[i]);
|
||||
}
|
||||
|
||||
// save the newly written values to eeprom
|
||||
Plugin_004_DS_write(0x48);
|
||||
@@ -357,7 +384,9 @@ uint8_t Plugin_004_DS_reset()
|
||||
{
|
||||
uint8_t r;
|
||||
uint8_t retries = 125;
|
||||
// noInterrupts();
|
||||
#if defined(ESP32)
|
||||
ESP32noInterrupts();
|
||||
#endif
|
||||
pinMode(Plugin_004_DallasPin, INPUT);
|
||||
do // wait until the wire is high... just in case
|
||||
{
|
||||
@@ -373,7 +402,9 @@ uint8_t Plugin_004_DS_reset()
|
||||
delayMicroseconds(40);
|
||||
r = !digitalRead(Plugin_004_DallasPin);
|
||||
delayMicroseconds(420);
|
||||
// interrupts();
|
||||
#if defined(ESP32)
|
||||
ESP32interrupts();
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -555,14 +586,18 @@ uint8_t Plugin_004_DS_read_bit(void)
|
||||
{
|
||||
uint8_t r;
|
||||
|
||||
// noInterrupts();
|
||||
#if defined(ESP32)
|
||||
ESP32noInterrupts();
|
||||
#endif
|
||||
pinMode(Plugin_004_DallasPin, OUTPUT);
|
||||
digitalWrite(Plugin_004_DallasPin, LOW);
|
||||
delayMicroseconds(3);
|
||||
pinMode(Plugin_004_DallasPin, INPUT); // let pin float, pull up will raise
|
||||
delayMicroseconds(10);
|
||||
r = digitalRead(Plugin_004_DallasPin);
|
||||
// interrupts();
|
||||
#if defined(ESP32)
|
||||
ESP32interrupts();
|
||||
#endif
|
||||
delayMicroseconds(53);
|
||||
return r;
|
||||
}
|
||||
@@ -574,33 +609,45 @@ void Plugin_004_DS_write_bit(uint8_t v)
|
||||
{
|
||||
if (v & 1)
|
||||
{
|
||||
// noInterrupts();
|
||||
#if defined(ESP32)
|
||||
ESP32noInterrupts();
|
||||
#endif
|
||||
digitalWrite(Plugin_004_DallasPin, LOW);
|
||||
pinMode(Plugin_004_DallasPin, OUTPUT);
|
||||
delayMicroseconds(10);
|
||||
digitalWrite(Plugin_004_DallasPin, HIGH);
|
||||
// interrupts();
|
||||
#if defined(ESP32)
|
||||
ESP32interrupts();
|
||||
#endif
|
||||
delayMicroseconds(55);
|
||||
}
|
||||
else
|
||||
{
|
||||
// noInterrupts();
|
||||
#if defined(ESP32)
|
||||
ESP32noInterrupts();
|
||||
#endif
|
||||
digitalWrite(Plugin_004_DallasPin, LOW);
|
||||
pinMode(Plugin_004_DallasPin, OUTPUT);
|
||||
delayMicroseconds(65);
|
||||
digitalWrite(Plugin_004_DallasPin, HIGH);
|
||||
// interrupts();
|
||||
#if defined(ESP32)
|
||||
ESP32interrupts();
|
||||
#endif
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Plugin_004_DS_crc8(uint8_t * addr, uint8_t len)
|
||||
/*********************************************************************************************\
|
||||
* Dallas Calculate CRC8 and compare it of addr[0-7] and compares it to addr[8]
|
||||
\*********************************************************************************************/
|
||||
boolean Plugin_004_DS_crc8(uint8_t * addr)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
uint8_t crc = 0;
|
||||
uint8_t len = 8;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
uint8_t inbyte = *addr++;
|
||||
uint8_t inbyte = *addr++; // from 0 to 7
|
||||
for (uint8_t i = 8; i; i--)
|
||||
{
|
||||
uint8_t mix = (crc ^ inbyte) & 0x01;
|
||||
@@ -609,5 +656,6 @@ uint8_t Plugin_004_DS_crc8(uint8_t * addr, uint8_t len)
|
||||
inbyte >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
return crc == *addr; // addr 8
|
||||
}
|
||||
#endif // USES_P004
|
||||
|
||||
+3
-1
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P005
|
||||
//#######################################################################################################
|
||||
//######################## Plugin 005: Temperature and Humidity sensor DHT 11/22 ########################
|
||||
//#######################################################################################################
|
||||
@@ -50,7 +51,7 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
|
||||
const String options[] = { F("DHT 11"), F("DHT 22"), F("DHT 12"), F("Sonoff am2301"), F("Sonoff si7021") };
|
||||
int indices[] = { 11, 22, 12, 23, 70 };
|
||||
|
||||
addFormSelector(string, F("DHT Type"), F("plugin_005_dhttype"), 5, options, indices, Settings.TaskDevicePluginConfig[event->TaskIndex][0] );
|
||||
addFormSelector(F("DHT Type"), F("plugin_005_dhttype"), 5, options, indices, Settings.TaskDevicePluginConfig[event->TaskIndex][0] );
|
||||
|
||||
success = true;
|
||||
break;
|
||||
@@ -219,3 +220,4 @@ int Plugin_005_read_dht_dat(void)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif // USES_P005
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P006
|
||||
//#######################################################################################################
|
||||
//######################## Plugin 006 BMP0685 I2C Barometric Pressure Sensor ###########################
|
||||
//#######################################################################################################
|
||||
@@ -49,7 +50,7 @@ boolean Plugin_006(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
addFormNumericBox(string, F("Altitude [m]"), F("_p006_bmp085_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
|
||||
addFormNumericBox(F("Altitude [m]"), F("_p006_bmp085_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
@@ -287,3 +288,4 @@ float Plugin_006_pressureElevation(float atmospheric, int altitude) {
|
||||
/*********************************************************************/
|
||||
return atmospheric / pow(1.0 - (altitude/44330.0), 5.255);
|
||||
}
|
||||
#endif // USES_P006
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P007
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 007: ExtWiredAnalog #######################################
|
||||
//#######################################################################################################
|
||||
@@ -69,3 +70,4 @@ boolean Plugin_007(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif // USES_P007
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P008
|
||||
//#######################################################################################################
|
||||
//################################# Plugin 008: Wiegand RFID Tag Reader #################################
|
||||
//#######################################################################################################
|
||||
@@ -176,3 +177,4 @@ void Plugin_008_interrupt2()
|
||||
Plugin_008_keyBuffer = Plugin_008_keyBuffer << 1; // Left shift the number (effectively multiplying by 2)
|
||||
Plugin_008_bitCount++; // Increment the bit count
|
||||
}
|
||||
#endif // USES_P008
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user