mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-28 04:07:47 +00:00
Compare commits
624
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
492791a4ac | ||
|
|
52c7e5012e | ||
|
|
4dd733eb63 | ||
|
|
02a065d623 | ||
|
|
0afee4fafb | ||
|
|
b2c866edeb | ||
|
|
1a72444b0a | ||
|
|
f613bb4572 | ||
|
|
51059f0c18 | ||
|
|
dec6598f49 | ||
|
|
f8f6767bec | ||
|
|
5c475b98db | ||
|
|
58fb8dc42b | ||
|
|
cb2b11a41a | ||
|
|
ac4f3c4cd4 | ||
|
|
c651e29d2a | ||
|
|
d7e886a841 | ||
|
|
eec7647782 | ||
|
|
6f9d120ff0 | ||
|
|
28ddc2d9c0 | ||
|
|
cc54354ac3 | ||
|
|
3929390629 | ||
|
|
3a26ebf7b1 | ||
|
|
1685bead52 | ||
|
|
3a2fe35e5c | ||
|
|
29ce7f774f | ||
|
|
cc85327356 | ||
|
|
0851bb655e | ||
|
|
d4bc10d8f1 | ||
|
|
0672f32f4b | ||
|
|
a17f7b679c | ||
|
|
425bd85c83 | ||
|
|
3be005e1ee | ||
|
|
174f9e6e03 | ||
|
|
51a14a174f | ||
|
|
7cb1f453d3 | ||
|
|
23a6caab89 | ||
|
|
6b4300bd46 | ||
|
|
04a9069db0 | ||
|
|
dd636903c8 | ||
|
|
940b65e86a | ||
|
|
6344de0649 | ||
|
|
8ccd7c3e8d | ||
|
|
22371649a4 | ||
|
|
2a48d5033e | ||
|
|
f064da797d | ||
|
|
b0b8edf935 | ||
|
|
8cbd9a0822 | ||
|
|
93f9d11738 | ||
|
|
cf3e0a3f0a | ||
|
|
ccfd14dbd3 | ||
|
|
3034738ad4 | ||
|
|
178d1c46a2 | ||
|
|
cdfd1d986e | ||
|
|
4b7aa53692 | ||
|
|
7959a5133f | ||
|
|
941fb5c29c | ||
|
|
c43c9ea2b3 | ||
|
|
967103bcad | ||
|
|
efe637ec70 | ||
|
|
00450eb260 | ||
|
|
cc02fa4481 | ||
|
|
1c5f8af083 | ||
|
|
fccc31a7c6 | ||
|
|
b84d905a0b | ||
|
|
94aa951cba | ||
|
|
2a23dcd011 | ||
|
|
ab3a406706 | ||
|
|
e7a9ee7eee | ||
|
|
3edfdbf5f7 | ||
|
|
27bac2ca00 | ||
|
|
373f74e9f8 | ||
|
|
1220c565c8 | ||
|
|
1931fe9e53 | ||
|
|
0eab6293dc | ||
|
|
f0987dab41 | ||
|
|
51bd52603f | ||
|
|
47f1fa145a | ||
|
|
605055d95a | ||
|
|
af3e353181 | ||
|
|
c711d6ea51 | ||
|
|
20c23a2935 | ||
|
|
bbfe254232 | ||
|
|
882c888f6d | ||
|
|
0a754f072c | ||
|
|
1f084c51cc | ||
|
|
89df0932c5 | ||
|
|
429fd3e4d0 | ||
|
|
85e8d98da8 | ||
|
|
6d52a7e03a | ||
|
|
fa513b52f9 | ||
|
|
f98401524f | ||
|
|
4090b4f23c | ||
|
|
b89c00008d | ||
|
|
d57a617138 | ||
|
|
cefe6b4b7c | ||
|
|
2432740b41 | ||
|
|
44a934651c | ||
|
|
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 | ||
|
|
6787bc8c0e | ||
|
|
6845a03741 | ||
|
|
6a4284f189 | ||
|
|
cf644b45b1 | ||
|
|
e6fe1c63a9 | ||
|
|
df978036f0 | ||
|
|
7cb375833d | ||
|
|
41c57f1ef9 | ||
|
|
808b40bdba | ||
|
|
58b20615da | ||
|
|
13026b1cc4 | ||
|
|
7f3460e492 | ||
|
|
a222391f81 | ||
|
|
a8165531d5 | ||
|
|
3218ea9839 | ||
|
|
eca8901fca | ||
|
|
6635eafe91 | ||
|
|
fe4d1f952f | ||
|
|
1abd31b421 | ||
|
|
72fe49d905 | ||
|
|
9dd9f3befa | ||
|
|
471d76dbe6 | ||
|
|
4475a225cc | ||
|
|
8b047490c4 | ||
|
|
455f77d0ed | ||
|
|
836fc4a875 | ||
|
|
2aece1c143 | ||
|
|
70df225e7e | ||
|
|
19af52a3ef | ||
|
|
3d396575ff | ||
|
|
873f8474b5 | ||
|
|
826deaac89 | ||
|
|
cce621cff8 | ||
|
|
57eb38dbd0 | ||
|
|
fd2451bb07 | ||
|
|
c94e5cb903 | ||
|
|
27699f7192 | ||
|
|
2eff001b14 | ||
|
|
bd499c7a94 | ||
|
|
4da1e4fbdd | ||
|
|
1d14770ea7 | ||
|
|
8b7574d298 | ||
|
|
14d87d95f6 | ||
|
|
5a15288d80 | ||
|
|
869dff12ce | ||
|
|
cc0b3dac26 | ||
|
|
4208048fc1 | ||
|
|
06a2f47812 | ||
|
|
d3434eb4d2 | ||
|
|
bd2665041f | ||
|
|
1fd429a029 | ||
|
|
7b3a71bcc9 | ||
|
|
18e612dea2 | ||
|
|
f99593ed62 | ||
|
|
2f7e96fa5b | ||
|
|
25b4392dd5 | ||
|
|
ad4130a547 | ||
|
|
e4d4463eab | ||
|
|
991384822f | ||
|
|
b29f56c6f4 | ||
|
|
779514481d | ||
|
|
82ed319e59 | ||
|
|
0a752dd26f | ||
|
|
2e4af86a99 | ||
|
|
8112e0e67a | ||
|
|
89a9f842fd | ||
|
|
b4791d3421 | ||
|
|
885c5394a3 | ||
|
|
e35304e4e7 | ||
|
|
6561d577d4 | ||
|
|
92932fddb2 | ||
|
|
02d8834763 | ||
|
|
e82080dc52 | ||
|
|
89581fd0fb | ||
|
|
cfbf972c1b | ||
|
|
e25ea52edc | ||
|
|
3f84a961ad | ||
|
|
7d8e5e5175 | ||
|
|
3d39dec686 | ||
|
|
ff656593ec | ||
|
|
96bfaa27f5 | ||
|
|
bcca0514dd | ||
|
|
90b4e3438d | ||
|
|
139f8905d0 | ||
|
|
6c1806fae6 | ||
|
|
e6b581e7ff | ||
|
|
bb9f8fc809 | ||
|
|
4d9504bce0 | ||
|
|
ff3a769033 | ||
|
|
e3de56a7a8 | ||
|
|
873d639461 | ||
|
|
edb2a6d3f6 | ||
|
|
2682b0bd2f | ||
|
|
5097157a09 | ||
|
|
02ea957894 | ||
|
|
c2b0d76595 | ||
|
|
91b7cbe075 | ||
|
|
bff60a2e27 | ||
|
|
61831e5962 | ||
|
|
d105b47d44 | ||
|
|
449568bcc4 | ||
|
|
3144077103 | ||
|
|
8f056be0a8 | ||
|
|
e9cdc5693d | ||
|
|
64b38df187 | ||
|
|
377c50ec36 | ||
|
|
76f6dfdc59 | ||
|
|
3a6f7acd15 | ||
|
|
d65b126f84 | ||
|
|
90a2a799da | ||
|
|
feb419b6ae | ||
|
|
e83d8468b0 | ||
|
|
6eabaaa62d | ||
|
|
8299e38b24 | ||
|
|
b0169b4aa7 | ||
|
|
786ec4714a | ||
|
|
67a28a7f97 | ||
|
|
18b8e61d32 | ||
|
|
5821b0709c | ||
|
|
ec783fe03b | ||
|
|
4d749b19fd | ||
|
|
6a66440a5f | ||
|
|
1b23efe48c | ||
|
|
9a9d39763f | ||
|
|
9f94ef073c | ||
|
|
9122565431 | ||
|
|
000d2d7c77 | ||
|
|
64a0f79e02 | ||
|
|
c1b945e6c1 | ||
|
|
dbbe6b65dd | ||
|
|
92e4a8da9b | ||
|
|
4611ef5d87 | ||
|
|
807cc1796d | ||
|
|
4bca2c6361 | ||
|
|
40e2d7ec8e | ||
|
|
7318e87965 | ||
|
|
9c3a28439f | ||
|
|
82933ae170 | ||
|
|
503fd3555e | ||
|
|
127627a22c | ||
|
|
e59401e24f | ||
|
|
769f76d3dc | ||
|
|
4eb7cf0859 | ||
|
|
a464f638ad | ||
|
|
f31cce4182 | ||
|
|
a5cfe1beec | ||
|
|
f36fada375 | ||
|
|
d51bce97f5 | ||
|
|
0368aa4d43 | ||
|
|
3c4aa7564f | ||
|
|
f46b89f1bd | ||
|
|
4e2b78056a | ||
|
|
d94ce17fd4 | ||
|
|
cd2c59ba5b | ||
|
|
b6a6943668 | ||
|
|
a8fcb420e7 | ||
|
|
e1e894d540 | ||
|
|
d15311e70a | ||
|
|
3ed6564063 | ||
|
|
5f575c0224 | ||
|
|
34c1ba158f | ||
|
|
04ca424085 | ||
|
|
7a8f476e05 | ||
|
|
eef8391ffc | ||
|
|
d47751c31f | ||
|
|
e42ab85f4b | ||
|
|
b048d3f1f8 | ||
|
|
f94ab3a04a | ||
|
|
1b9375f83b | ||
|
|
a77798d18f | ||
|
|
3094cb5260 | ||
|
|
ec4dd09968 | ||
|
|
d68a5fb9d4 | ||
|
|
0e67480f46 | ||
|
|
c32f2cc89d | ||
|
|
ad489f0db2 | ||
|
|
d9267fa9c2 | ||
|
|
e82fb37870 | ||
|
|
635c149f12 | ||
|
|
26f00dcdec | ||
|
|
b2bb1d039b | ||
|
|
57e256a5fa | ||
|
|
c58e975b7e | ||
|
|
7d16ffa4a4 | ||
|
|
856e370ba0 | ||
|
|
4df9e7d065 | ||
|
|
edb3857e04 | ||
|
|
08312cbcb7 | ||
|
|
fb1cc219ee | ||
|
|
da7329891d | ||
|
|
953a53bb9a | ||
|
|
e9fac7926f | ||
|
|
810a0b2aa9 | ||
|
|
7f897bc856 | ||
|
|
5d9137d1d2 | ||
|
|
8de49cd38e | ||
|
|
0092ba92b5 | ||
|
|
fe1c44f6b3 | ||
|
|
e39d588530 | ||
|
|
7a4e3d954d | ||
|
|
9dc4fefa0b | ||
|
|
4ca318f5a6 | ||
|
|
695bb58d64 | ||
|
|
608a7212eb | ||
|
|
37a24933f5 | ||
|
|
a6b447600f | ||
|
|
5fbb900e5b | ||
|
|
aa5dee01fb | ||
|
|
4e2a5d3b3d | ||
|
|
1a44ed6578 | ||
|
|
e86667e37e | ||
|
|
0db1f78421 | ||
|
|
780c34846e | ||
|
|
a4dcc304a9 | ||
|
|
a938bc78c1 | ||
|
|
d2c7743197 | ||
|
|
f0fc20de57 | ||
|
|
d35a50be17 | ||
|
|
537d4cd1e9 | ||
|
|
62422f4924 | ||
|
|
04de145dbb | ||
|
|
21840d0b26 | ||
|
|
076ce0127b | ||
|
|
226c0a6f83 | ||
|
|
6ffa8d92a6 | ||
|
|
dae2cc2f4a | ||
|
|
555ccbe229 | ||
|
|
d277d22914 | ||
|
|
b5e4994392 | ||
|
|
cbdddf8c06 | ||
|
|
8b5d22a081 | ||
|
|
88fc0a8445 | ||
|
|
ec9187d038 | ||
|
|
51ede17d2a | ||
|
|
97ee69b371 | ||
|
|
f77ce9c8f7 | ||
|
|
99cc6f72af | ||
|
|
848f43b704 | ||
|
|
3a5ef5da81 | ||
|
|
3527b69718 | ||
|
|
54628bfca9 | ||
|
|
72ff745eff | ||
|
|
aed566b6db | ||
|
|
504ea0c813 | ||
|
|
4ca5ef3f72 | ||
|
|
dd9db3b557 | ||
|
|
9c531b30bc | ||
|
|
67c8477a61 | ||
|
|
cd30b81202 | ||
|
|
550881faa5 | ||
|
|
3d07466904 | ||
|
|
ed45945f21 | ||
|
|
f13abe8922 | ||
|
|
34b0a683a9 | ||
|
|
9ab10437b5 | ||
|
|
b0b7408522 | ||
|
|
b104942db9 | ||
|
|
a694b658b1 | ||
|
|
cb07a0d342 | ||
|
|
1ceaad04ec | ||
|
|
5cbf0c1e38 | ||
|
|
4951f294b9 | ||
|
|
ef0ef092f0 | ||
|
|
46d3ae6a2b | ||
|
|
ef1bf646ab | ||
|
|
f72a48ffc2 | ||
|
|
da54ddda78 | ||
|
|
03ee569510 | ||
|
|
c24205713d | ||
|
|
52d4cb804e | ||
|
|
ae077de72b | ||
|
|
86fa5ec6ae | ||
|
|
41c9d68422 | ||
|
|
e713da5d79 | ||
|
|
edc261ca2b | ||
|
|
8f4a52a6f1 | ||
|
|
af519748a6 | ||
|
|
c04b80b2f1 | ||
|
|
cdbc2498c1 | ||
|
|
78997b4329 | ||
|
|
2bece45712 | ||
|
|
10c73a001a | ||
|
|
790a946cf6 | ||
|
|
69c5be6489 | ||
|
|
233ca2bf43 | ||
|
|
3de400fc91 | ||
|
|
edeea02f71 | ||
|
|
6fae1f79d8 | ||
|
|
1222e04caf | ||
|
|
f38973aad6 | ||
|
|
b31b1d913f | ||
|
|
fa3d4af8cb | ||
|
|
29320aab90 | ||
|
|
3bc8609611 | ||
|
|
c43d6b3769 | ||
|
|
e9e2ea32ed | ||
|
|
24b7d1f438 | ||
|
|
4febf08501 | ||
|
|
7f4eae19f4 | ||
|
|
c13952d04c | ||
|
|
3032463917 | ||
|
|
f5e84a155e | ||
|
|
bbb97bfc7e | ||
|
|
e51f7683a5 | ||
|
|
e747756dd2 | ||
|
|
1ad6fd6ea0 | ||
|
|
d2ec15a4bf | ||
|
|
f23d9fa3d3 | ||
|
|
6df5840db9 | ||
|
|
5f79e4b922 | ||
|
|
e058507b9a | ||
|
|
3cea522ec4 | ||
|
|
5c4defdf6e | ||
|
|
e58ea2a3fe | ||
|
|
a93a078c0b | ||
|
|
0e0e7be95a | ||
|
|
2b7a61469f | ||
|
|
ce02c9e039 | ||
|
|
1e9dc1d14c | ||
|
|
75f1c6c140 | ||
|
|
9a6f7360da | ||
|
|
e3cd057ad8 | ||
|
|
fec069ba00 | ||
|
|
d835ef679c | ||
|
|
9144e7901b | ||
|
|
858ce397c3 | ||
|
|
78c9ff70be | ||
|
|
b2db97e808 | ||
|
|
4e537461f2 | ||
|
|
dc7bb12581 | ||
|
|
0c80cdc119 | ||
|
|
37210031b7 | ||
|
|
40eb3e7ceb | ||
|
|
d7134e6b87 | ||
|
|
8dc1924059 | ||
|
|
a7b77b6008 | ||
|
|
88320d25fc | ||
|
|
649305a2dd | ||
|
|
d49197a621 | ||
|
|
2371b0f315 | ||
|
|
9abdd097c9 | ||
|
|
f8849cb601 | ||
|
|
b293e8fee0 | ||
|
|
11b1c8505a | ||
|
|
9cb3ceed83 | ||
|
|
2ac1df9482 | ||
|
|
59b7768722 | ||
|
|
d4e5742b1c | ||
|
|
baa1df620f | ||
|
|
a310811919 | ||
|
|
e9dd5da690 | ||
|
|
f9c25489d1 | ||
|
|
46ee928b07 | ||
|
|
3af102f2ad | ||
|
|
ca53ec0263 | ||
|
|
5ca7c073f1 | ||
|
|
f815564dc7 | ||
|
|
b320c2a1e2 | ||
|
|
2b51a4d7c4 | ||
|
|
01d0723424 | ||
|
|
3f68154819 | ||
|
|
7b1c4483bb | ||
|
|
572d9c0714 | ||
|
|
b85010006b | ||
|
|
48643cf87e | ||
|
|
9ea594afeb | ||
|
|
aec539be43 | ||
|
|
749c8cd931 | ||
|
|
49a783c381 | ||
|
|
c9b81f7ab9 | ||
|
|
eb2dbb5b90 | ||
|
|
e49f31121c | ||
|
|
91c6e3af61 | ||
|
|
faeb921bcf | ||
|
|
9928f56ad3 | ||
|
|
61d27084c1 | ||
|
|
e5393a9fa4 | ||
|
|
1cbc49021a | ||
|
|
84f389b44e | ||
|
|
765775e22f | ||
|
|
02c97c4513 | ||
|
|
bd874c4a13 | ||
|
|
d87cd7eafe | ||
|
|
58bb62cc1a | ||
|
|
6b8ea6c15b | ||
|
|
a62dd5ce8f | ||
|
|
92889b6cf1 | ||
|
|
b5479575eb | ||
|
|
201d013230 | ||
|
|
6fead68f34 | ||
|
|
9a77b1727c | ||
|
|
2f26cd13bc | ||
|
|
f0d35527df | ||
|
|
3a9ef290e8 | ||
|
|
9cbaa4d7e7 | ||
|
|
af4ad9fbcb | ||
|
|
36a9bdae72 | ||
|
|
ebfa0a45a6 | ||
|
|
c2e70360c4 | ||
|
|
8bdfa656de | ||
|
|
952bf68b93 | ||
|
|
712a5e80d0 | ||
|
|
a44069ae26 | ||
|
|
13f73c0156 | ||
|
|
bb88225cab | ||
|
|
3089b288b2 | ||
|
|
6abea46eb5 | ||
|
|
ffa73aee59 | ||
|
|
f4b7e97997 | ||
|
|
b32212b061 | ||
|
|
66d0de684a | ||
|
|
cae3baf71e | ||
|
|
27db33f1bd | ||
|
|
23d5709957 | ||
|
|
b96e12f217 | ||
|
|
16eb08afa0 | ||
|
|
ad8e229c06 | ||
|
|
b9b7ceccb6 | ||
|
|
5c4bf52b66 | ||
|
|
34369d268e | ||
|
|
0ec7085022 | ||
|
|
913cd67eee | ||
|
|
3292051bae | ||
|
|
2586b94e28 | ||
|
|
d492347f31 | ||
|
|
b811b13483 | ||
|
|
56f9bc9c3a | ||
|
|
c149888bed | ||
|
|
82cea3db2e | ||
|
|
8aea298854 | ||
|
|
5617fbe0a0 | ||
|
|
6a643da8ee | ||
|
|
2f32799b67 | ||
|
|
ee568a76c1 | ||
|
|
beaf077b06 | ||
|
|
fd5da94f9c | ||
|
|
0694fcc5fb | ||
|
|
e36a9f163e | ||
|
|
17f0f6637a | ||
|
|
bc91939757 | ||
|
|
eb743f95cf | ||
|
|
0ec770fc51 | ||
|
|
ed4cdc3d90 | ||
|
|
9da5f465d1 | ||
|
|
8e72ace3b5 | ||
|
|
5230a4fe4f | ||
|
|
b236887718 | ||
|
|
2527cbe097 | ||
|
|
cbca4c3efa | ||
|
|
5b0e9d934c | ||
|
|
19429e8507 | ||
|
|
a67f92176f | ||
|
|
3922827fad | ||
|
|
0c637da19f | ||
|
|
48f168da9d | ||
|
|
3357eb287c | ||
|
|
5da1c54b70 | ||
|
|
c5bbdb401a | ||
|
|
f69b84d24b | ||
|
|
1250e09fef | ||
|
|
fbf22ba7af | ||
|
|
5c26d50227 | ||
|
|
47be037be9 | ||
|
|
bc4f7d390c | ||
|
|
9fe64834f9 | ||
|
|
4d943c2386 | ||
|
|
4b298d6e31 | ||
|
|
c0c65364e5 | ||
|
|
51b76682cf | ||
|
|
5f89698308 | ||
|
|
400ee82686 | ||
|
|
485f97bdc2 | ||
|
|
5821377b6c | ||
|
|
e6e3c1ddee | ||
|
|
a6ea35ef9c | ||
|
|
fe9a579dc3 | ||
|
|
017aad051e | ||
|
|
8a30659015 | ||
|
|
ed7f597b3d | ||
|
|
6700030d7c | ||
|
|
f45c7650de | ||
|
|
a36ee65865 | ||
|
|
b61c638f0a | ||
|
|
dfb5b8a4c5 | ||
|
|
09e5d6abcd | ||
|
|
2aafbb57a8 | ||
|
|
9d3dd49e9d | ||
|
|
744f22112b | ||
|
|
b38edfb672 | ||
|
|
a73875a2e2 | ||
|
|
0833029c82 | ||
|
|
71cf207bf7 | ||
|
|
f7ea185f80 | ||
|
|
3d3a035822 | ||
|
|
11a94aae25 | ||
|
|
af3bf5217d | ||
|
|
11f47f26e6 | ||
|
|
57c6fbbaab | ||
|
|
eee55a92d9 | ||
|
|
21398fbf8a |
+3
-2
@@ -1,9 +1,10 @@
|
||||
# cmd: "cd {PROJECT_PATH}; platformio"
|
||||
cmd: "platformio"
|
||||
name: "Build with error highlighting (dev_ESP8266_4096)"
|
||||
args:
|
||||
- run --environment dev_ESP8266_4096
|
||||
sh: true,
|
||||
cwd: .
|
||||
sh: true
|
||||
cwd: "{PROJECT_PATH}"
|
||||
# env:
|
||||
# VARIABLE1: "VALUE1"
|
||||
# VARIABLE2: "VALUE2"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
### Steps to reproduce
|
||||
How can we trigger this problem?
|
||||
|
||||
Does the problem presist after powering off and on? (just resetting isnt enough sometimes)
|
||||
Does the problem persists after powering off and on? (just resetting isn't enough sometimes)
|
||||
|
||||
### Expected behavior
|
||||
Tell us what should happen?
|
||||
|
||||
+12
@@ -1,6 +1,18 @@
|
||||
## 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
|
||||
|
||||
+6
-1
@@ -27,7 +27,12 @@ install:
|
||||
script:
|
||||
# - cppcheck --enable=warning src/*.ino -q --force -I src --include=src/ESPEasy.ino --error-exitcode=1
|
||||
# - ./memanalyzer.py ~/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-objdump
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -s
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run
|
||||
|
||||
# patch platformio core libs for PUYA bug (https://github.com/letscontrolit/ESPEasy/issues/650)
|
||||
- cd patches; ./check_puya_patch; cd ..
|
||||
- PLATFORMIO_BUILD_FLAGS="-D CONTINUOUS_INTEGRATION" platformio run -s --environment dev_ESP8266PUYA_1024
|
||||
|
||||
|
||||
before_deploy:
|
||||
- ./before_deploy
|
||||
|
||||
@@ -4,7 +4,10 @@ Build status: [)
|
||||
|
||||
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
|
||||
|
||||
|
||||
+25
-14
@@ -1,24 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION=$(git describe)
|
||||
echo "Creating release archives for $VERSION ..."
|
||||
#binaries
|
||||
|
||||
#ESP_Easy_v[version]-[build type]-dev[dev number]-ESP[chip type]-[size].bin
|
||||
#Naming convention:
|
||||
# ESP_Easy_[github version]_[plugin set]_[chip type]_[flash memory].bin
|
||||
|
||||
#cp .pioenvs/mini_512/firmware.bin dist/"ESPEasy_$VERSION""_mini_512.bin"
|
||||
|
||||
cp .pioenvs/normal_ESP8266_1024/firmware.bin dist/"ESP_Easy_$VERSION""_normal_ESP8266_1024.bin"
|
||||
cp .pioenvs/normal_ESP8266_4096/firmware.bin dist/"ESP_Easy_$VERSION""_normal_ESP8266_4096.bin"
|
||||
cp .pioenvs/normal_ESP8285_1024/firmware.bin dist/"ESP_Easy_$VERSION""_normal_ESP8285_1024.bin"
|
||||
for ENV in \
|
||||
normal_ESP8266_1024 \
|
||||
normal_ESP8266_4096 \
|
||||
normal_ESP8285_1024 \
|
||||
test_ESP8266_1024\
|
||||
test_ESP8266_4096\
|
||||
test_ESP8266_4096_VCC\
|
||||
test_ESP8285_1024\
|
||||
dev_ESP8266_1024\
|
||||
dev_ESP8266_4096\
|
||||
dev_ESP8285_1024\
|
||||
dev_ESP8266PUYA_1024\
|
||||
dev_ESP8266PUYA_1024_VCC;\
|
||||
do
|
||||
echo
|
||||
echo "### Deploying environment $ENV for version $VERSION"
|
||||
BIN=.pioenvs/$ENV/firmware.bin
|
||||
python2 crc2.py $BIN
|
||||
cp $BIN dist/"ESP_Easy_$VERSION""_$ENV.bin"
|
||||
done
|
||||
|
||||
cp .pioenvs/test_ESP8266_1024/firmware.bin dist/"ESP_Easy_$VERSION""_test_ESP8266_1024.bin"
|
||||
cp .pioenvs/test_ESP8266_4096/firmware.bin dist/"ESP_Easy_$VERSION""_test_ESP8266_4096.bin"
|
||||
cp .pioenvs/test_ESP8285_1024/firmware.bin dist/"ESP_Easy_$VERSION""_test_ESP8285_1024.bin"
|
||||
|
||||
cp .pioenvs/dev_ESP8266_1024/firmware.bin dist/"ESP_Easy_$VERSION""_dev_ESP8266_1024.bin"
|
||||
cp .pioenvs/dev_ESP8266_4096/firmware.bin dist/"ESP_Easy_$VERSION""_dev_ESP8266_4096.bin"
|
||||
cp .pioenvs/dev_ESP8285_1024/firmware.bin dist/"ESP_Easy_$VERSION""_dev_ESP8285_1024.bin"
|
||||
|
||||
#create a source structure that is the same as the original ESPEasy project (and works with the howto on the wiki)
|
||||
rm -rf dist/Source 2>/dev/null
|
||||
@@ -28,4 +36,7 @@ cp -r src dist/Source/
|
||||
cp platformio.ini dist/Source/
|
||||
|
||||
cd dist
|
||||
|
||||
echo
|
||||
echo "### Creating zip archive"
|
||||
zip ../ESPEasy_$VERSION.zip -r .
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
|
||||
import sys
|
||||
import binascii
|
||||
import struct
|
||||
import md5
|
||||
import os
|
||||
MD5DUMMY = "MD5_MD5_MD5_MD5_BoundariesOfTheSegmentsGoHere..." #48 chars
|
||||
FILENAMEDUMMY = "ThisIsTheDummyPlaceHolderForTheBinaryFilename..." #48 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) >48: # check that filename is <48 chars
|
||||
BinaryFileName=BinaryFileName[0:48] # truncate if necessary. 49th char in ESP is zero already
|
||||
else:
|
||||
BinaryFileName= BinaryFileName.ljust(48,'\0'); # pad with zeros.
|
||||
|
||||
|
||||
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
+1099
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
@@ -0,0 +1,456 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
@@ -0,0 +1,40 @@
|
||||
# ESP8266Ping
|
||||
Let the ESP8266 ping a remote machine.
|
||||
|
||||
With this library an ESP8266 can ping a remote machine and know if it's reachable.
|
||||
It provide some basic measurements on ping messages (avg response time).
|
||||
|
||||
## Usage
|
||||
|
||||
First, include the library in your sketch along with WiFi library:
|
||||
|
||||
```Arduino
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266Ping.h>
|
||||
```
|
||||
|
||||
Next, simply call the `Ping.ping()` function
|
||||
|
||||
```Arduino
|
||||
IPAddress ip (192, 168, 0, 1); // The remote ip to ping
|
||||
bool ret = Ping.ping(ip);
|
||||
```
|
||||
|
||||
`ret` will be true if the remote responded to pings, false if not reachable.
|
||||
The library supports hostname too, just pass a string instead of the ip address:
|
||||
|
||||
```Arduino
|
||||
bool ret = Ping.ping("www.google.com");
|
||||
```
|
||||
|
||||
Additionally, the function accept a second integer parameter `count` that specify how many pings has to be sent:
|
||||
|
||||
```Arduino
|
||||
bool ret = Ping.ping(ip_or_host, 10);
|
||||
```
|
||||
|
||||
After `Ping.ping()` has been called, the average response time (in milliseconds) can be retrieved with
|
||||
|
||||
```Arduino
|
||||
int avg_time_ms = Ping.averageTime();
|
||||
```
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This example show how to ping a remote machine using it's hostname
|
||||
*/
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266Ping.h>
|
||||
|
||||
const char* ssid = "ssid";
|
||||
const char* password = "passphrase";
|
||||
|
||||
const char* remote_host = "www.google.com";
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(10);
|
||||
|
||||
// We start by connecting to a WiFi network
|
||||
|
||||
Serial.println();
|
||||
Serial.println("Connecting to WiFi");
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Serial.print("WiFi connected with ip ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
Serial.print("Pinging host ");
|
||||
Serial.println(remote_host);
|
||||
|
||||
if(Ping.ping(remote_host)) {
|
||||
Serial.println("Success!!");
|
||||
} else {
|
||||
Serial.println("Error :(");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() { }
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* With this library an ESP8266 can ping a remote machine and know if it's reachable.
|
||||
* It provides some basic measurements on ping messages (avg response time).
|
||||
*/
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266Ping.h>
|
||||
|
||||
const char* ssid = "ssid";
|
||||
const char* password = "passphrase";
|
||||
|
||||
const IPAddress remote_ip(192, 168, 0, 1);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(10);
|
||||
|
||||
// We start by connecting to a WiFi network
|
||||
|
||||
Serial.println();
|
||||
Serial.println("Connecting to WiFi");
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(100);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Serial.print("WiFi connected with ip ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
Serial.print("Pinging ip ");
|
||||
Serial.println(remote_ip);
|
||||
|
||||
if(Ping.ping(remote_ip)) {
|
||||
Serial.println("Success!!");
|
||||
} else {
|
||||
Serial.println("Error :(");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() { }
|
||||
@@ -0,0 +1,26 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For ESP8266Ping
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Library (KEYWORD3)
|
||||
#######################################
|
||||
|
||||
ESP8266Ping KEYWORD3
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
Ping KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
ping KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
name=ESPEasy_ESP8266Ping
|
||||
version=1.0
|
||||
author=Daniele Colanardi
|
||||
maintainer=Daniele Colanardi <dancol90@gmail.com>
|
||||
sentence=Let the ESP8266 ping a remote machine.
|
||||
paragraph=With this library an ESP8266 can ping a remote machine and know if it's reachable. It provide some basic measurements on ping messages (avg response time). Lib name renamed to avoid conflicts in Arduino IDE.
|
||||
category=Communication
|
||||
url=
|
||||
architectures=esp8266
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
ESP8266Ping - Ping library for ESP8266
|
||||
Copyright (c) 2015 Daniele Colanardi. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ESP8266Ping_H
|
||||
#define ESP8266Ping_H
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <Arduino.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
extern "C" {
|
||||
#include <ping.h>
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DEBUG_PING
|
||||
#define DEBUG_PING(...) Serial.printf(__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_PING(...)
|
||||
#endif
|
||||
|
||||
class PingClass {
|
||||
public:
|
||||
PingClass();
|
||||
|
||||
bool ping(IPAddress dest, byte count = 5);
|
||||
bool ping(const char* host, byte count = 5);
|
||||
|
||||
int averageTime();
|
||||
|
||||
protected:
|
||||
static void _ping_sent_cb(void *opt, void *pdata);
|
||||
static void _ping_recv_cb(void *opt, void *pdata);
|
||||
|
||||
IPAddress _dest;
|
||||
ping_option _options;
|
||||
|
||||
static byte _expected_count, _errors, _success;
|
||||
static int _avg_time;
|
||||
};
|
||||
|
||||
#include "ESP8266Ping.impl.h"
|
||||
PingClass Ping;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
ESP8266Ping - Ping library for ESP8266
|
||||
Copyright (c) 2015 Daniele Colanardi. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
extern "C" void esp_schedule();
|
||||
extern "C" void esp_yield();
|
||||
|
||||
PingClass::PingClass() {}
|
||||
|
||||
bool PingClass::ping(IPAddress dest, byte count) {
|
||||
_expected_count = count;
|
||||
_errors = 0;
|
||||
_success = 0;
|
||||
|
||||
_avg_time = 0;
|
||||
|
||||
memset(&_options, 0, sizeof(struct ping_option));
|
||||
|
||||
// Repeat count (how many time send a ping message to destination)
|
||||
_options.count = count;
|
||||
// Time interval between two ping (seconds??)
|
||||
_options.coarse_time = 1;
|
||||
// Destination machine
|
||||
_options.ip = dest;
|
||||
|
||||
// Callbacks
|
||||
_options.recv_function = reinterpret_cast<ping_recv_function>(&PingClass::_ping_recv_cb);
|
||||
_options.sent_function = NULL; //reinterpret_cast<ping_sent_function>(&_ping_sent_cb);
|
||||
|
||||
// Let's go!
|
||||
if(ping_start(&_options)) {
|
||||
// Suspend till the process end
|
||||
esp_yield();
|
||||
}
|
||||
|
||||
return (_success > 0);
|
||||
}
|
||||
|
||||
bool PingClass::ping(const char* host, byte count) {
|
||||
IPAddress remote_addr;
|
||||
|
||||
if (WiFi.hostByName(host, remote_addr))
|
||||
return ping(remote_addr, count);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int PingClass::averageTime() {
|
||||
return _avg_time;
|
||||
}
|
||||
|
||||
void PingClass::_ping_recv_cb(void *opt, void *resp) {
|
||||
// Cast the parameters to get some usable info
|
||||
ping_resp* ping_resp = reinterpret_cast<struct ping_resp*>(resp);
|
||||
//ping_option* ping_opt = reinterpret_cast<struct ping_option*>(opt);
|
||||
|
||||
// Error or success?
|
||||
if (ping_resp->ping_err == -1)
|
||||
_errors++;
|
||||
else {
|
||||
_success++;
|
||||
_avg_time += ping_resp->resp_time;
|
||||
}
|
||||
|
||||
// Some debug info
|
||||
DEBUG_PING(
|
||||
"DEBUG: ping reply\n"
|
||||
"\ttotal_count = %d \n"
|
||||
"\tresp_time = %d \n"
|
||||
"\tseqno = %d \n"
|
||||
"\ttimeout_count = %d \n"
|
||||
"\tbytes = %d \n"
|
||||
"\ttotal_bytes = %d \n"
|
||||
"\ttotal_time = %d \n"
|
||||
"\tping_err = %d \n",
|
||||
ping_resp->total_count, ping_resp->resp_time, ping_resp->seqno,
|
||||
ping_resp->timeout_count, ping_resp->bytes, ping_resp->total_bytes,
|
||||
ping_resp->total_time, ping_resp->ping_err
|
||||
);
|
||||
|
||||
// Is it time to end?
|
||||
// Don't using seqno because it does not increase on error
|
||||
if (_success + _errors == _expected_count) {
|
||||
_avg_time = _avg_time / _expected_count;
|
||||
|
||||
DEBUG_PING("Avg resp time %d ms\n", _avg_time);
|
||||
|
||||
// Done, return to main functiom
|
||||
esp_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
byte PingClass::_expected_count = 0;
|
||||
byte PingClass::_errors = 0;
|
||||
byte PingClass::_success = 0;
|
||||
int PingClass::_avg_time = 0;
|
||||
@@ -93,8 +93,8 @@ bool ICACHE_FLASH_ATTR IRKelvinatorAC::getPower() {
|
||||
|
||||
// Set the temp. in deg C
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setTemp(uint8_t temp) {
|
||||
temp = max(KELVINATOR_MIN_TEMP, temp);
|
||||
temp = min(KELVINATOR_MAX_TEMP, temp);
|
||||
temp = max(static_cast<uint8_t>(KELVINATOR_MIN_TEMP), temp);
|
||||
temp = min(static_cast<uint8_t>(KELVINATOR_MAX_TEMP), temp);
|
||||
remote_state[1] = (remote_state[1] & 0xF0U) | (temp - KELVINATOR_MIN_TEMP);
|
||||
remote_state[9] = remote_state[1]; // Duplicate to the 2nd command chunk.
|
||||
}
|
||||
@@ -106,12 +106,12 @@ uint8_t ICACHE_FLASH_ATTR IRKelvinatorAC::getTemp() {
|
||||
|
||||
// Set the speed of the fan, 0-5, 0 is auto, 1-5 is the speed
|
||||
void ICACHE_FLASH_ATTR IRKelvinatorAC::setFan(uint8_t fan) {
|
||||
fan = min(KELVINATOR_FAN_MAX, fan); // Bounds check
|
||||
fan = min(static_cast<uint8_t>(KELVINATOR_FAN_MAX), fan); // Bounds check
|
||||
|
||||
// Only change things if we need to.
|
||||
if (fan != getFan()) {
|
||||
// Set the basic fan values.
|
||||
uint8_t fan_basic = min(KELVINATOR_BASIC_FAN_MAX, fan);
|
||||
uint8_t fan_basic = min(static_cast<uint8_t>(KELVINATOR_BASIC_FAN_MAX), fan);
|
||||
remote_state[0] = (remote_state[0] & KELVINATOR_BASIC_FAN_MASK) |
|
||||
(fan_basic << KELVINATOR_FAN_OFFSET);
|
||||
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
|
||||
|
||||
@@ -77,8 +77,8 @@ bool ICACHE_FLASH_ATTR IRMitsubishiAC::getPower() {
|
||||
|
||||
// Set the temp. in deg C
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::setTemp(uint8_t temp) {
|
||||
temp = max(MITSUBISHI_AC_MIN_TEMP, temp);
|
||||
temp = min(MITSUBISHI_AC_MAX_TEMP, temp);
|
||||
temp = max(static_cast<uint8_t>(MITSUBISHI_AC_MIN_TEMP), temp);
|
||||
temp = min(static_cast<uint8_t>(MITSUBISHI_AC_MAX_TEMP), temp);
|
||||
remote_state[7] = temp - MITSUBISHI_AC_MIN_TEMP;
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ void ICACHE_FLASH_ATTR IRMitsubishiAC::setMode(uint8_t mode) {
|
||||
|
||||
// Set the requested vane operation mode of the a/c unit.
|
||||
void ICACHE_FLASH_ATTR IRMitsubishiAC::setVane(uint8_t mode) {
|
||||
mode = max(mode, B111); // bounds check
|
||||
mode = max(mode, static_cast<uint8_t>(B111)); // bounds check
|
||||
mode |= B1000;
|
||||
mode <<= 3;
|
||||
remote_state[9] |= mode;
|
||||
|
||||
@@ -155,7 +155,7 @@ void ICACHE_FLASH_ATTR IRsend::sendNEC (unsigned long data, int nbits,
|
||||
// Footer
|
||||
mark(NEC_BIT_MARK);
|
||||
// Gap to next command.
|
||||
space(max(0, NEC_MIN_COMMAND_LENGTH - usecs.elapsed()));
|
||||
space(max(0ul, NEC_MIN_COMMAND_LENGTH - usecs.elapsed()));
|
||||
|
||||
// Optional command repeat sequence.
|
||||
for (unsigned int i = 0; i < repeat; i++) {
|
||||
@@ -164,7 +164,52 @@ void ICACHE_FLASH_ATTR IRsend::sendNEC (unsigned long data, int nbits,
|
||||
space(NEC_RPT_SPACE);
|
||||
mark(NEC_BIT_MARK);
|
||||
// Gap till next command.
|
||||
space(max(0, NEC_MIN_COMMAND_LENGTH - usecs.elapsed()));
|
||||
space(max(0ul, NEC_MIN_COMMAND_LENGTH - usecs.elapsed()));
|
||||
}
|
||||
}
|
||||
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +281,7 @@ void ICACHE_FLASH_ATTR IRsend::sendSony(unsigned long data, int nbits,
|
||||
// Footer
|
||||
// The Sony protocol requires us to wait 45ms from start of a code to the
|
||||
// start of the next one. A 10ms minimum gap is also required.
|
||||
space(max(10000, 45000 - usecs.elapsed()));
|
||||
space(max(10000u, 45000 - usecs.elapsed()));
|
||||
}
|
||||
// A space() is always performed last, so no need to turn off the LED.
|
||||
}
|
||||
@@ -367,7 +412,7 @@ void ICACHE_FLASH_ATTR IRsend::sendRCMM(uint32_t data, uint8_t nbits) {
|
||||
mark(RCMM_BIT_MARK);
|
||||
// Protocol requires us to wait at least RCMM_RPT_LENGTH usecs from the start
|
||||
// or RCMM_MIN_GAP usecs.
|
||||
space(max(RCMM_RPT_LENGTH - usecs.elapsed(), RCMM_MIN_GAP));
|
||||
space(max(RCMM_RPT_LENGTH - usecs.elapsed(), static_cast<uint32_t>(RCMM_MIN_GAP)));
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRsend::sendPanasonic(unsigned int address,
|
||||
@@ -415,7 +460,7 @@ void ICACHE_FLASH_ATTR IRsend::sendJVC(unsigned long data, int nbits,
|
||||
// Footer
|
||||
mark(JVC_BIT_MARK);
|
||||
// Wait till the end of the repeat time window before we send another code.
|
||||
space(max(0, JVC_RPT_LENGTH - usecs.elapsed()));
|
||||
space(max(0u, JVC_RPT_LENGTH - usecs.elapsed()));
|
||||
usecs.reset();
|
||||
}
|
||||
// No need to turn off the LED as we will always end with a space().
|
||||
@@ -647,7 +692,7 @@ void ICACHE_FLASH_ATTR IRsend::sendSherwood(unsigned long data, int nbits,
|
||||
unsigned int repeat) {
|
||||
// Sherwood remote codes appear to be NEC codes with a manditory repeat code.
|
||||
// i.e. repeat should be >= 1.
|
||||
sendNEC(data, nbits, max(1, repeat));
|
||||
sendNEC(data, nbits, max(1u, repeat));
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR IRsend::sendMitsubishiAC(unsigned char data[]) {
|
||||
@@ -911,7 +956,7 @@ bool ICACHE_FLASH_ATTR IRrecv::decode(decode_results *results,
|
||||
// Nr. of ticks.
|
||||
uint32_t IRrecv::ticksLow(uint32_t usecs, uint8_t tolerance) {
|
||||
// max() used to ensure the result can't drop below 0 before the cast.
|
||||
return((uint32_t) max(usecs * (1.0 - tolerance/100.)/USECPERTICK, 0));
|
||||
return((uint32_t) max(usecs * (1.0 - tolerance/100.)/USECPERTICK, 0.0));
|
||||
}
|
||||
|
||||
// Calculate the upper bound of the nr. of ticks.
|
||||
|
||||
@@ -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
|
||||
|
||||
Regular → Executable
+21
-11
@@ -1,11 +1,4 @@
|
||||
//www.DFRobot.com
|
||||
//last updated on 21/12/2011
|
||||
//Tim Starling Fix the reset bug (Thanks Tim)
|
||||
//wiki doc http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063)
|
||||
//Support Forum: http://www.dfrobot.com/forum/
|
||||
//Compatible with the Arduino IDE 1.0
|
||||
//Library version:1.1
|
||||
|
||||
// Based on the work by DFRobot
|
||||
|
||||
#include "LiquidCrystal_I2C.h"
|
||||
#include <inttypes.h>
|
||||
@@ -16,7 +9,7 @@
|
||||
#define printIIC(args) Wire.write(args)
|
||||
inline size_t LiquidCrystal_I2C::write(uint8_t value) {
|
||||
send(value, Rs);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -59,6 +52,11 @@ LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t l
|
||||
_backlightval = LCD_NOBACKLIGHT;
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::oled_init(){
|
||||
_oled = true;
|
||||
init_priv();
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::init(){
|
||||
init_priv();
|
||||
}
|
||||
@@ -134,6 +132,7 @@ void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
|
||||
void LiquidCrystal_I2C::clear(){
|
||||
command(LCD_CLEARDISPLAY);// clear display, set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
if (_oled) setCursor(0,0);
|
||||
}
|
||||
|
||||
void LiquidCrystal_I2C::home(){
|
||||
@@ -221,6 +220,15 @@ void LiquidCrystal_I2C::createChar(uint8_t location, uint8_t charmap[]) {
|
||||
}
|
||||
}
|
||||
|
||||
//createChar with PROGMEM input
|
||||
void LiquidCrystal_I2C::createChar(uint8_t location, const char *charmap) {
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i=0; i<8; i++) {
|
||||
write(pgm_read_byte_near(charmap++));
|
||||
}
|
||||
}
|
||||
|
||||
// Turn the (optional) backlight off/on
|
||||
void LiquidCrystal_I2C::noBacklight(void) {
|
||||
_backlightval=LCD_NOBACKLIGHT;
|
||||
@@ -309,6 +317,8 @@ void LiquidCrystal_I2C::printstr(const char c[]){
|
||||
|
||||
|
||||
// unsupported API functions
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
void LiquidCrystal_I2C::off(){}
|
||||
void LiquidCrystal_I2C::on(){}
|
||||
void LiquidCrystal_I2C::setDelay (int cmdDelay,int charDelay) {}
|
||||
@@ -318,5 +328,5 @@ uint8_t LiquidCrystal_I2C::init_bargraph(uint8_t graphtype){return 0;}
|
||||
void LiquidCrystal_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end){}
|
||||
void LiquidCrystal_I2C::draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_row_end){}
|
||||
void LiquidCrystal_I2C::setContrast(uint8_t new_val){}
|
||||
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
|
||||
Regular → Executable
+7
-2
@@ -1,4 +1,4 @@
|
||||
//DFRobot.com
|
||||
//YWROBOT
|
||||
#ifndef LiquidCrystal_I2C_h
|
||||
#define LiquidCrystal_I2C_h
|
||||
|
||||
@@ -77,14 +77,18 @@ public:
|
||||
void autoscroll();
|
||||
void noAutoscroll();
|
||||
void createChar(uint8_t, uint8_t[]);
|
||||
void createChar(uint8_t location, const char *charmap);
|
||||
// Example: const char bell[8] PROGMEM = {B00100,B01110,B01110,B01110,B11111,B00000,B00100,B00000};
|
||||
|
||||
void setCursor(uint8_t, uint8_t);
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
virtual size_t write(uint8_t);
|
||||
#else
|
||||
virtual void write(uint8_t);
|
||||
#endif
|
||||
void command(uint8_t);
|
||||
void init();
|
||||
void oled_init();
|
||||
|
||||
////compatibility API function aliases
|
||||
void blink_on(); // alias for blink()
|
||||
@@ -118,6 +122,7 @@ private:
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
uint8_t _numlines;
|
||||
bool _oled = false;
|
||||
uint8_t _cols;
|
||||
uint8_t _rows;
|
||||
uint8_t _backlightval;
|
||||
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
# LiquidCrystal_I2C
|
||||
LiquidCrystal Arduino library for the DFRobot I2C LCD displays
|
||||
@@ -1,69 +0,0 @@
|
||||
1,6c1
|
||||
< //www.DFRobot.com
|
||||
< //last updated on 26/11/2010
|
||||
< //Tim Starling Fix the reset bug (Thanks Tim)
|
||||
< //wiki doc http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063)
|
||||
< //Support Forum: http://www.dfrobot.com/forum/
|
||||
<
|
||||
---
|
||||
> // LiquidCrystal_I2C V2.0
|
||||
10d4
|
||||
< #include "WProgram.h"
|
||||
12c6
|
||||
<
|
||||
---
|
||||
> #include "Arduino.h"
|
||||
67c61
|
||||
< delay(50);
|
||||
---
|
||||
> delayMicroseconds(50000);
|
||||
77,90c71,84
|
||||
< // we start in 8bit mode, try to set 4 bit mode
|
||||
< write4bits(0x03 << 4);
|
||||
< delayMicroseconds(4500); // wait min 4.1ms
|
||||
<
|
||||
< // second try
|
||||
< write4bits(0x03 << 4);
|
||||
< delayMicroseconds(4500); // wait min 4.1ms
|
||||
<
|
||||
< // third go!
|
||||
< write4bits(0x03 << 4);
|
||||
< delayMicroseconds(150);
|
||||
<
|
||||
< // finally, set to 4-bit interface
|
||||
< write4bits(0x02 << 4);
|
||||
---
|
||||
> // we start in 8bit mode, try to set 4 bit mode
|
||||
> write4bits(0x03);
|
||||
> delayMicroseconds(4500); // wait min 4.1ms
|
||||
>
|
||||
> // second try
|
||||
> write4bits(0x03);
|
||||
> delayMicroseconds(4500); // wait min 4.1ms
|
||||
>
|
||||
> // third go!
|
||||
> write4bits(0x03);
|
||||
> delayMicroseconds(150);
|
||||
>
|
||||
> // finally, set to 4-bit interface
|
||||
> write4bits(0x02);
|
||||
225c219
|
||||
< inline void LiquidCrystal_I2C::write(uint8_t value) {
|
||||
---
|
||||
> inline size_t LiquidCrystal_I2C::write(uint8_t value) {
|
||||
226a221
|
||||
> return 0;
|
||||
235,238c230,233
|
||||
< uint8_t highnib=value&0xf0;
|
||||
< uint8_t lownib=(value<<4)&0xf0;
|
||||
< write4bits((highnib)|mode);
|
||||
< write4bits((lownib)|mode);
|
||||
---
|
||||
> uint8_t highnib=value>>4;
|
||||
> uint8_t lownib=value & 0x0F;
|
||||
> write4bits((highnib)|mode);
|
||||
> write4bits((lownib)|mode);
|
||||
248c243
|
||||
< Wire.send((int)(_data) | _backlightval);
|
||||
---
|
||||
> Wire.write((int)(_data) | _backlightval);
|
||||
Regular → Executable
+4
-4
@@ -1,4 +1,4 @@
|
||||
//DFRobot.com
|
||||
//YWROBOT
|
||||
//Compatible with the Arduino IDE 1.0
|
||||
//Library version:1.1
|
||||
#include <Wire.h>
|
||||
@@ -19,7 +19,7 @@ uint8_t check[8] = {0x0,0x1,0x3,0x16,0x1c,0x8,0x0};
|
||||
uint8_t cross[8] = {0x0,0x1b,0xe,0x4,0xe,0x1b,0x0};
|
||||
uint8_t retarrow[8] = { 0x1,0x1,0x5,0x9,0x1f,0x8,0x4};
|
||||
|
||||
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
|
||||
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
|
||||
|
||||
void setup()
|
||||
{
|
||||
@@ -52,7 +52,7 @@ void displayKeyCodes(void) {
|
||||
while (1) {
|
||||
lcd.clear();
|
||||
lcd.print("Codes 0x"); lcd.print(i, HEX);
|
||||
lcd.print("-0x"); lcd.print(i+16, HEX);
|
||||
lcd.print("-0x"); lcd.print(i+15, HEX);
|
||||
lcd.setCursor(0, 1);
|
||||
for (int j=0; j<16; j++) {
|
||||
lcd.printByte(i+j);
|
||||
@@ -67,4 +67,4 @@ void loop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Regular → Executable
+11
-3
@@ -1,20 +1,28 @@
|
||||
//DFRobot.com
|
||||
//YWROBOT
|
||||
//Compatible with the Arduino IDE 1.0
|
||||
//Library version:1.1
|
||||
#include <Wire.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
|
||||
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
|
||||
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
|
||||
|
||||
void setup()
|
||||
{
|
||||
lcd.init(); // initialize the lcd
|
||||
|
||||
lcd.init();
|
||||
// Print a message to the LCD.
|
||||
lcd.backlight();
|
||||
lcd.setCursor(3,0);
|
||||
lcd.print("Hello, world!");
|
||||
lcd.setCursor(2,1);
|
||||
lcd.print("Ywrobot Arduino!");
|
||||
lcd.setCursor(0,2);
|
||||
lcd.print("Arduino LCM IIC 2004");
|
||||
lcd.setCursor(2,3);
|
||||
lcd.print("Power By Ec-yuan!");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
Regular → Executable
+2
-2
@@ -1,14 +1,14 @@
|
||||
/*
|
||||
* Displays text sent over the serial port (e.g. from the Serial Monitor) on
|
||||
* an attached LCD.
|
||||
* DFRobot.com
|
||||
* YWROBOT
|
||||
*Compatible with the Arduino IDE 1.0
|
||||
*Library version:1.1
|
||||
*/
|
||||
#include <Wire.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
|
||||
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
|
||||
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
||||
Regular → Executable
Executable
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "LiquidCrystal_I2C",
|
||||
"keywords": "LCD, liquidcrystal, I2C",
|
||||
"description": "A library for DFRobot I2C LCD displays",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/marcoschwartz/LiquidCrystal_I2C.git"
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms":
|
||||
[
|
||||
"atmelavr",
|
||||
"espressif8266"
|
||||
]
|
||||
}
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
name=LiquidCrystal_I2C
|
||||
version=1.1.4
|
||||
author=Frank de Brabander
|
||||
maintainer=Marco Schwartz <marcolivier.schwartz@gmail.com>
|
||||
sentence=A library for I2C LCD displays.
|
||||
paragraph= The library allows to control I2C displays with functions extremely similar to LiquidCrystal library. THIS LIBRARY MIGHT NOT BE COMPATIBLE WITH EXISTING SKETCHES.
|
||||
category=Display
|
||||
url=https://github.com/marcoschwartz/LiquidCrystal_I2C
|
||||
architectures=avr
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "SensorSerialBuffer.h"
|
||||
#include "ESPeasySoftwareSerial.h"
|
||||
|
||||
|
||||
class CjkSDS011
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -22,6 +22,10 @@ SOFTWARE.
|
||||
|
||||
See more at http://blog.squix.ch
|
||||
*/
|
||||
|
||||
#ifndef DIALOG_PLAIN_FONT_H
|
||||
#define DIALOG_PLAIN_FONT_H
|
||||
|
||||
// OLED library version >= 3.0.0
|
||||
// Created by http://oleddisplay.squix.ch/ Consider a donation
|
||||
// In case of problems make sure that you are using the font file with the correct version!
|
||||
@@ -481,3 +485,6 @@ const char Dialog_plain_12[] PROGMEM = {
|
||||
0x00,0x00,0xFC,0x7F,0x40,0x04,0x20,0x08,0x20,0x08,0x60,0x0C,0xC0,0x07, // 254
|
||||
0x00,0x00,0xE0,0x40,0x04,0x47,0x00,0x38,0x84,0x07,0xE0 // 255
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,24 +27,32 @@
|
||||
|
||||
#include "OLEDDisplay.h"
|
||||
|
||||
OLEDDisplay::~OLEDDisplay() {
|
||||
end();
|
||||
}
|
||||
|
||||
bool OLEDDisplay::init() {
|
||||
if (!this->connect()) {
|
||||
DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Can't establish connection to display\n");
|
||||
return false;
|
||||
}
|
||||
if(this->buffer==NULL) {
|
||||
this->buffer = (uint8_t*) malloc(sizeof(uint8_t) * DISPLAY_BUFFER_SIZE);
|
||||
if(!this->buffer) {
|
||||
DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create display\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
|
||||
if(this->buffer_back==NULL) {
|
||||
this->buffer_back = (uint8_t*) malloc(sizeof(uint8_t) * DISPLAY_BUFFER_SIZE);
|
||||
if(!this->buffer_back) {
|
||||
DEBUG_OLEDDISPLAY("[OLEDDISPLAY][init] Not enough memory to create back buffer\n");
|
||||
free(this->buffer);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
sendInitCommands();
|
||||
@@ -54,10 +62,11 @@ bool OLEDDisplay::init() {
|
||||
}
|
||||
|
||||
void OLEDDisplay::end() {
|
||||
if (this->buffer) free(this->buffer);
|
||||
if (this->buffer) { free(this->buffer); this->buffer = NULL; }
|
||||
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
|
||||
if (this->buffer_back) free(this->buffer_back);
|
||||
if (this->buffer_back) { free(this->buffer_back); this->buffer_back = NULL; }
|
||||
#endif
|
||||
if (this->logBuffer != NULL) { free(this->logBuffer); this->logBuffer = NULL; }
|
||||
}
|
||||
|
||||
void OLEDDisplay::resetDisplay(void) {
|
||||
@@ -73,11 +82,11 @@ void OLEDDisplay::setColor(OLEDDISPLAY_COLOR color) {
|
||||
}
|
||||
|
||||
void OLEDDisplay::setPixel(int16_t x, int16_t y) {
|
||||
if (x >= 0 && x < 128 && y >= 0 && y < 64) {
|
||||
if (x >= 0 && x < this->width() && y >= 0 && y < this->height()) {
|
||||
switch (color) {
|
||||
case WHITE: buffer[x + (y / 8) * DISPLAY_WIDTH] |= (1 << (y & 7)); break;
|
||||
case BLACK: buffer[x + (y / 8) * DISPLAY_WIDTH] &= ~(1 << (y & 7)); break;
|
||||
case INVERSE: buffer[x + (y / 8) * DISPLAY_WIDTH] ^= (1 << (y & 7)); break;
|
||||
case WHITE: buffer[x + (y / 8) * this->width()] |= (1 << (y & 7)); break;
|
||||
case BLACK: buffer[x + (y / 8) * this->width()] &= ~(1 << (y & 7)); break;
|
||||
case INVERSE: buffer[x + (y / 8) * this->width()] ^= (1 << (y & 7)); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,21 +231,21 @@ void OLEDDisplay::fillCircle(int16_t x0, int16_t y0, int16_t radius) {
|
||||
}
|
||||
|
||||
void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) {
|
||||
if (y < 0 || y >= DISPLAY_HEIGHT) { return; }
|
||||
if (y < 0 || y >= this->height()) { return; }
|
||||
|
||||
if (x < 0) {
|
||||
length += x;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if ( (x + length) > DISPLAY_WIDTH) {
|
||||
length = (DISPLAY_WIDTH - x);
|
||||
if ( (x + length) > this->width()) {
|
||||
length = (this->width() - x);
|
||||
}
|
||||
|
||||
if (length <= 0) { return; }
|
||||
|
||||
uint8_t * bufferPtr = buffer;
|
||||
bufferPtr += (y >> 3) * DISPLAY_WIDTH;
|
||||
bufferPtr += (y >> 3) * this->width();
|
||||
bufferPtr += x;
|
||||
|
||||
uint8_t drawBit = 1 << (y & 7);
|
||||
@@ -255,15 +264,15 @@ void OLEDDisplay::drawHorizontalLine(int16_t x, int16_t y, int16_t length) {
|
||||
}
|
||||
|
||||
void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
|
||||
if (x < 0 || x >= DISPLAY_WIDTH) return;
|
||||
if (x < 0 || x >= this->width()) return;
|
||||
|
||||
if (y < 0) {
|
||||
length += y;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
if ( (y + length) > DISPLAY_HEIGHT) {
|
||||
length = (DISPLAY_HEIGHT - y);
|
||||
if ( (y + length) > this->height()) {
|
||||
length = (this->height() - y);
|
||||
}
|
||||
|
||||
if (length <= 0) return;
|
||||
@@ -273,7 +282,7 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
|
||||
uint8_t drawBit;
|
||||
uint8_t *bufferPtr = buffer;
|
||||
|
||||
bufferPtr += (y >> 3) * DISPLAY_WIDTH;
|
||||
bufferPtr += (y >> 3) * this->width();
|
||||
bufferPtr += x;
|
||||
|
||||
if (yOffset) {
|
||||
@@ -293,7 +302,7 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
|
||||
if (length < yOffset) return;
|
||||
|
||||
length -= yOffset;
|
||||
bufferPtr += DISPLAY_WIDTH;
|
||||
bufferPtr += this->width();
|
||||
}
|
||||
|
||||
if (length >= 8) {
|
||||
@@ -303,14 +312,14 @@ void OLEDDisplay::drawVerticalLine(int16_t x, int16_t y, int16_t length) {
|
||||
drawBit = (color == WHITE) ? 0xFF : 0x00;
|
||||
do {
|
||||
*bufferPtr = drawBit;
|
||||
bufferPtr += DISPLAY_WIDTH;
|
||||
bufferPtr += this->width();
|
||||
length -= 8;
|
||||
} while (length >= 8);
|
||||
break;
|
||||
case INVERSE:
|
||||
do {
|
||||
*bufferPtr = ~(*bufferPtr);
|
||||
bufferPtr += DISPLAY_WIDTH;
|
||||
bufferPtr += this->width();
|
||||
length -= 8;
|
||||
} while (length >= 8);
|
||||
break;
|
||||
@@ -340,7 +349,7 @@ void OLEDDisplay::drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16
|
||||
drawHorizontalLine(xRadius, y + height, width - doubleRadius + 1);
|
||||
drawCircleQuads(x + width - radius, yRadius, radius, 0b00001001);
|
||||
|
||||
uint16_t maxProgressWidth = (width - doubleRadius - 1) * progress / 100;
|
||||
uint16_t maxProgressWidth = (width - doubleRadius + 1) * progress / 100;
|
||||
|
||||
fillCircle(xRadius, yRadius, innerRadius);
|
||||
fillRect(xRadius + 1, y + 2, maxProgressWidth, height - 3);
|
||||
@@ -353,7 +362,7 @@ void OLEDDisplay::drawFastImage(int16_t xMove, int16_t yMove, int16_t width, int
|
||||
|
||||
void OLEDDisplay::drawXbm(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *xbm) {
|
||||
int16_t widthInXbm = (width + 7) / 8;
|
||||
uint8_t data;
|
||||
uint8_t data = 0;
|
||||
|
||||
for(int16_t y = 0; y < height; y++) {
|
||||
for(int16_t x = 0; x < width; x++ ) {
|
||||
@@ -388,11 +397,13 @@ void OLEDDisplay::drawStringInternal(int16_t xMove, int16_t yMove, char* text, u
|
||||
case TEXT_ALIGN_RIGHT:
|
||||
xMove -= textWidth;
|
||||
break;
|
||||
case TEXT_ALIGN_LEFT:
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't draw anything if it is not on the screen.
|
||||
if (xMove + textWidth < 0 || xMove > DISPLAY_WIDTH ) {return;}
|
||||
if (yMove + textHeight < 0 || yMove > DISPLAY_HEIGHT) {return;}
|
||||
if (xMove + textWidth < 0 || xMove > this->width() ) {return;}
|
||||
if (yMove + textHeight < 0 || yMove > this->width() ) {return;}
|
||||
|
||||
for (uint16_t j = 0; j < textLength; j++) {
|
||||
int16_t xPos = xMove + cursorX;
|
||||
@@ -545,9 +556,16 @@ void OLEDDisplay::normalDisplay(void) {
|
||||
sendCommand(NORMALDISPLAY);
|
||||
}
|
||||
|
||||
void OLEDDisplay::setContrast(char contrast) {
|
||||
void OLEDDisplay::setContrast(char contrast, char precharge, char comdetect) {
|
||||
sendCommand(SETPRECHARGE); //0xD9
|
||||
sendCommand(precharge); //0xF1 default, to lower the contrast, put 1-1F
|
||||
sendCommand(SETCONTRAST);
|
||||
sendCommand(contrast);
|
||||
sendCommand(contrast); // 0-255
|
||||
sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast)
|
||||
sendCommand(comdetect); //0x40 default, to lower the contrast, put 0
|
||||
sendCommand(DISPLAYALLON_RESUME);
|
||||
sendCommand(NORMALDISPLAY);
|
||||
sendCommand(DISPLAYON);
|
||||
}
|
||||
|
||||
void OLEDDisplay::flipScreenVertically() {
|
||||
@@ -596,6 +614,7 @@ bool OLEDDisplay::setLogBuffer(uint16_t lines, uint16_t chars){
|
||||
uint16_t size = lines * chars;
|
||||
if (size > 0) {
|
||||
this->logBufferLine = 0; // Lines printed
|
||||
this->logBufferFilled = 0; // Nothing stored yet
|
||||
this->logBufferMaxLines = lines; // Lines max printable
|
||||
this->logBufferSize = size; // Total number of characters the buffer can hold
|
||||
this->logBuffer = (char *) malloc(size * sizeof(uint8_t));
|
||||
@@ -670,7 +689,7 @@ void OLEDDisplay::sendInitCommands(void) {
|
||||
sendCommand(SETDISPLAYCLOCKDIV);
|
||||
sendCommand(0xF0); // Increase speed of the display max ~96Hz
|
||||
sendCommand(SETMULTIPLEX);
|
||||
sendCommand(0x3F);
|
||||
sendCommand(this->height() - 1);
|
||||
sendCommand(SETDISPLAYOFFSET);
|
||||
sendCommand(0x00);
|
||||
sendCommand(SETSTARTLINE);
|
||||
@@ -681,11 +700,13 @@ void OLEDDisplay::sendInitCommands(void) {
|
||||
sendCommand(SEGREMAP);
|
||||
sendCommand(COMSCANINC);
|
||||
sendCommand(SETCOMPINS);
|
||||
sendCommand(0x12);
|
||||
sendCommand(0x12); // according to the adafruit lib, sometimes this may need to be 0x02
|
||||
sendCommand(SETCONTRAST);
|
||||
sendCommand(0xCF);
|
||||
sendCommand(SETPRECHARGE);
|
||||
sendCommand(0xF1);
|
||||
sendCommand(SETVCOMDETECT); //0xDB, (additionally needed to lower the contrast)
|
||||
sendCommand(0x40); //0x40 default, to lower the contrast, put 0
|
||||
sendCommand(DISPLAYALLON_RESUME);
|
||||
sendCommand(NORMALDISPLAY);
|
||||
sendCommand(0x2e); // stop scroll
|
||||
@@ -694,8 +715,8 @@ void OLEDDisplay::sendInitCommands(void) {
|
||||
|
||||
void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *data, uint16_t offset, uint16_t bytesInData) {
|
||||
if (width < 0 || height < 0) return;
|
||||
if (yMove + height < 0 || yMove > DISPLAY_HEIGHT) return;
|
||||
if (xMove + width < 0 || xMove > DISPLAY_WIDTH) return;
|
||||
if (yMove + height < 0 || yMove > this->height()) return;
|
||||
if (xMove + width < 0 || xMove > this->width()) return;
|
||||
|
||||
uint8_t rasterHeight = 1 + ((height - 1) >> 3); // fast ceil(height / 8.0)
|
||||
int8_t yOffset = yMove & 7;
|
||||
@@ -717,13 +738,13 @@ void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t widt
|
||||
byte currentByte = pgm_read_byte(data + offset + i);
|
||||
|
||||
int16_t xPos = xMove + (i / rasterHeight);
|
||||
int16_t yPos = ((yMove >> 3) + (i % rasterHeight)) * DISPLAY_WIDTH;
|
||||
int16_t yPos = ((yMove >> 3) + (i % rasterHeight)) * this->width();
|
||||
|
||||
int16_t yScreenPos = yMove + yOffset;
|
||||
// int16_t yScreenPos = yMove + yOffset;
|
||||
int16_t dataPos = xPos + yPos;
|
||||
|
||||
if (dataPos >= 0 && dataPos < DISPLAY_BUFFER_SIZE &&
|
||||
xPos >= 0 && xPos < DISPLAY_WIDTH ) {
|
||||
xPos >= 0 && xPos < this->width() ) {
|
||||
|
||||
if (yOffset >= 0) {
|
||||
switch (this->color) {
|
||||
@@ -731,11 +752,11 @@ void inline OLEDDisplay::drawInternal(int16_t xMove, int16_t yMove, int16_t widt
|
||||
case BLACK: buffer[dataPos] &= ~(currentByte << yOffset); break;
|
||||
case INVERSE: buffer[dataPos] ^= currentByte << yOffset; break;
|
||||
}
|
||||
if (dataPos < (DISPLAY_BUFFER_SIZE - DISPLAY_WIDTH)) {
|
||||
if (dataPos < (DISPLAY_BUFFER_SIZE - this->width())) {
|
||||
switch (this->color) {
|
||||
case WHITE: buffer[dataPos + DISPLAY_WIDTH] |= currentByte >> (8 - yOffset); break;
|
||||
case BLACK: buffer[dataPos + DISPLAY_WIDTH] &= ~(currentByte >> (8 - yOffset)); break;
|
||||
case INVERSE: buffer[dataPos + DISPLAY_WIDTH] ^= currentByte >> (8 - yOffset); break;
|
||||
case WHITE: buffer[dataPos + this->width()] |= currentByte >> (8 - yOffset); break;
|
||||
case BLACK: buffer[dataPos + this->width()] &= ~(currentByte >> (8 - yOffset)); break;
|
||||
case INVERSE: buffer[dataPos + this->width()] ^= currentByte >> (8 - yOffset); break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -44,9 +44,13 @@
|
||||
|
||||
|
||||
// Display settings
|
||||
#define DISPLAY_WIDTH 128
|
||||
#define DISPLAY_HEIGHT 64
|
||||
#define DISPLAY_BUFFER_SIZE 1024
|
||||
#ifndef DISPLAY_WIDTH
|
||||
#define DISPLAY_WIDTH 128
|
||||
#endif
|
||||
#ifndef DISPLAY_HEIGHT
|
||||
#define DISPLAY_HEIGHT 64
|
||||
#endif
|
||||
#define DISPLAY_BUFFER_SIZE DISPLAY_WIDTH * DISPLAY_HEIGHT / 8
|
||||
|
||||
// Header Values
|
||||
#define JUMPTABLE_BYTES 4
|
||||
@@ -109,11 +113,17 @@ enum OLEDDISPLAY_TEXT_ALIGNMENT {
|
||||
|
||||
|
||||
class OLEDDisplay : public Print {
|
||||
private:
|
||||
const int _width, _height;
|
||||
|
||||
public:
|
||||
OLEDDisplay(const int width = DISPLAY_WIDTH, const int height = DISPLAY_HEIGHT) : _width(width), _height(height){ };
|
||||
virtual ~OLEDDisplay();
|
||||
|
||||
virtual ~OLEDDisplay() {}
|
||||
const int width(void) const { return _width; };
|
||||
const int height(void) const { return _height; };
|
||||
|
||||
// Initialize the display
|
||||
// Initialize the display
|
||||
bool init();
|
||||
|
||||
// Free the memory used by the display
|
||||
@@ -204,7 +214,9 @@ class OLEDDisplay : public Print {
|
||||
void normalDisplay(void);
|
||||
|
||||
// Set display contrast
|
||||
void setContrast(char contrast);
|
||||
// really low brightness & contrast: contrast = 10, precharge = 5, comdetect = 0
|
||||
// normal brightness & contrast: contrast = 100
|
||||
void setContrast(char contrast, char precharge = 241, char comdetect = 64);
|
||||
|
||||
// Turn the display upside down
|
||||
void flipScreenVertically();
|
||||
@@ -229,10 +241,10 @@ class OLEDDisplay : public Print {
|
||||
size_t write(uint8_t c);
|
||||
size_t write(const char* s);
|
||||
|
||||
uint8_t *buffer;
|
||||
uint8_t *buffer = NULL;
|
||||
|
||||
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
|
||||
uint8_t *buffer_back;
|
||||
uint8_t *buffer_back = NULL;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@@ -250,7 +262,7 @@ class OLEDDisplay : public Print {
|
||||
char *logBuffer = NULL;
|
||||
|
||||
// Send a command to the display (low level function)
|
||||
virtual void sendCommand(uint8_t com) {};
|
||||
virtual void sendCommand(uint8_t com) {(void)com;};
|
||||
|
||||
// Connect to the display
|
||||
virtual bool connect() { return false; };
|
||||
|
||||
@@ -251,31 +251,31 @@ void OLEDDisplayUi::drawFrame(){
|
||||
switch (this->state.frameState){
|
||||
case IN_TRANSITION: {
|
||||
float progress = (float) this->state.ticksSinceLastStateSwitch / (float) this->ticksPerTransition;
|
||||
int16_t x, y, x1, y1;
|
||||
int16_t x = 0, y = 0, x1 = 0, y1 = 0;
|
||||
switch(this->frameAnimationDirection){
|
||||
case SLIDE_LEFT:
|
||||
x = -128 * progress;
|
||||
x = -this->display->width() * progress;
|
||||
y = 0;
|
||||
x1 = x + 128;
|
||||
x1 = x + this->display->width();
|
||||
y1 = 0;
|
||||
break;
|
||||
case SLIDE_RIGHT:
|
||||
x = 128 * progress;
|
||||
x = this->display->width() * progress;
|
||||
y = 0;
|
||||
x1 = x - 128;
|
||||
x1 = x - this->display->width();
|
||||
y1 = 0;
|
||||
break;
|
||||
case SLIDE_UP:
|
||||
x = 0;
|
||||
y = -64 * progress;
|
||||
y = -this->display->height() * progress;
|
||||
x1 = 0;
|
||||
y1 = y + 64;
|
||||
y1 = y + this->display->height();
|
||||
break;
|
||||
case SLIDE_DOWN:
|
||||
x = 0;
|
||||
y = 64 * progress;
|
||||
y = this->display->height() * progress;
|
||||
x1 = 0;
|
||||
y1 = y - 64;
|
||||
y1 = y - this->display->height();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@ void OLEDDisplayUi::drawIndicator() {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t posOfHighlightFrame;
|
||||
uint8_t posOfHighlightFrame = 0;
|
||||
float indicatorFadeProgress = 0;
|
||||
|
||||
// if the indicator needs to be slided in we want to
|
||||
@@ -362,25 +362,25 @@ void OLEDDisplayUi::drawIndicator() {
|
||||
|
||||
uint16_t frameStartPos = (12 * frameCount / 2);
|
||||
const char *image;
|
||||
uint16_t x,y;
|
||||
uint16_t x = 0, y = 0;
|
||||
for (byte i = 0; i < this->frameCount; i++) {
|
||||
|
||||
switch (this->indicatorPosition){
|
||||
case TOP:
|
||||
y = 0 - (8 * indicatorFadeProgress);
|
||||
x = 64 - frameStartPos + 12 * i;
|
||||
x = (this->display->width() / 2) - frameStartPos + 12 * i;
|
||||
break;
|
||||
case BOTTOM:
|
||||
y = 56 + (8 * indicatorFadeProgress);
|
||||
x = 64 - frameStartPos + 12 * i;
|
||||
y = (this->display->height() - 8) + (8 * indicatorFadeProgress);
|
||||
x = (this->display->width() / 2) - frameStartPos + 12 * i;
|
||||
break;
|
||||
case RIGHT:
|
||||
x = 120 + (8 * indicatorFadeProgress);
|
||||
y = 32 - frameStartPos + 2 + 12 * i;
|
||||
x = (this->display->width() - 8) + (8 * indicatorFadeProgress);
|
||||
y = (this->display->height() / 2) - frameStartPos + 2 + 12 * i;
|
||||
break;
|
||||
case LEFT:
|
||||
x = 0 - (8 * indicatorFadeProgress);
|
||||
y = 32 - frameStartPos + 2 + 12 * i;
|
||||
y = (this->display->height() / 2) - frameStartPos + 2 + 12 * i;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef OLED_SSD1306_SH1106_IMAGES_H
|
||||
#define OLED_SSD1306_SH1106_IMAGES_H
|
||||
|
||||
#define espeasy_logo_width 36
|
||||
#define espeasy_logo_height 36
|
||||
const char espeasy_logo_bits[] PROGMEM= {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x60, 0x40, 0xc0, 0x00, 0x00, 0x70, 0xf0, 0xe0,
|
||||
0x01, 0x00, 0x78, 0xf8, 0xf0, 0x01, 0x00, 0x3c, 0x7c, 0xf8, 0x00, 0x00,
|
||||
0x1e, 0x3e, 0x7c, 0x00, 0x00, 0x0f, 0x1f, 0x3e, 0x00, 0x80, 0x87, 0x0f,
|
||||
0x1f, 0x00, 0xc0, 0xc3, 0x87, 0x0f, 0x00, 0xe0, 0xe1, 0xc3, 0x07, 0x00,
|
||||
0xf0, 0xf0, 0xe1, 0xc3, 0x00, 0x78, 0xf8, 0xf0, 0xe1, 0x01, 0x30, 0x7c,
|
||||
0xf8, 0xf0, 0x00, 0x00, 0x3e, 0x7c, 0x78, 0x00, 0x00, 0x1f, 0x3e, 0x3c,
|
||||
0x00, 0x80, 0x0f, 0x1f, 0x1e, 0x00, 0xc0, 0x87, 0x0f, 0x0f, 0x00, 0xe0,
|
||||
0xc3, 0x87, 0x07, 0x00, 0xf0, 0xe1, 0xc3, 0x03, 0x00, 0xf0, 0xf0, 0xe1,
|
||||
0x01, 0x00, 0x78, 0xf8, 0xf0, 0x00, 0x00, 0x30, 0x7c, 0x78, 0x00, 0x00,
|
||||
0x00, 0x3e, 0x3c, 0x00, 0x00, 0x00, 0x1f, 0x1e, 0x00, 0x00, 0x80, 0x0f,
|
||||
0x0f, 0x78, 0x00, 0xc0, 0x87, 0x07, 0xfc, 0x00, 0xe0, 0xc3, 0x03, 0xfc,
|
||||
0x01, 0xf0, 0xe1, 0x01, 0xfc, 0x01, 0xf8, 0xf0, 0x00, 0xfc, 0x00, 0x78,
|
||||
0x70, 0x00, 0x78, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
const char activeSymbole[] PROGMEM = {
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00011000,
|
||||
B00100100,
|
||||
B01000010,
|
||||
B01000010,
|
||||
B00100100,
|
||||
B00011000
|
||||
};
|
||||
|
||||
const char inactiveSymbole[] PROGMEM = {
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00011000,
|
||||
B00011000,
|
||||
B00000000,
|
||||
B00000000
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -38,7 +38,8 @@ class SSD1306Wire : public OLEDDisplay {
|
||||
uint8_t _scl;
|
||||
|
||||
public:
|
||||
SSD1306Wire(uint8_t _address, uint8_t _sda, uint8_t _scl) {
|
||||
SSD1306Wire(uint8_t _address, uint8_t _sda, uint8_t _scl, int width = DISPLAY_WIDTH, int height = DISPLAY_HEIGHT)
|
||||
: OLEDDisplay(width, height) {
|
||||
this->_address = _address;
|
||||
this->_sda = _sda;
|
||||
this->_scl = _scl;
|
||||
@@ -53,6 +54,7 @@ class SSD1306Wire : public OLEDDisplay {
|
||||
}
|
||||
|
||||
void display(void) {
|
||||
const int x_offset = (128 - this->width()) / 2;
|
||||
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
|
||||
uint8_t minBoundY = ~0;
|
||||
uint8_t maxBoundY = 0;
|
||||
@@ -63,9 +65,9 @@ class SSD1306Wire : public OLEDDisplay {
|
||||
|
||||
// Calculate the Y bounding box of changes
|
||||
// and copy buffer[pos] to buffer_back[pos];
|
||||
for (y = 0; y < (DISPLAY_HEIGHT / 8); y++) {
|
||||
for (x = 0; x < DISPLAY_WIDTH; x++) {
|
||||
uint16_t pos = x + y * DISPLAY_WIDTH;
|
||||
for (y = 0; y < (this->height() / 8); y++) {
|
||||
for (x = 0; x < this->width(); x++) {
|
||||
uint16_t pos = x + y * this->width();
|
||||
if (buffer[pos] != buffer_back[pos]) {
|
||||
minBoundY = _min(minBoundY, y);
|
||||
maxBoundY = _max(maxBoundY, y);
|
||||
@@ -80,11 +82,11 @@ class SSD1306Wire : public OLEDDisplay {
|
||||
// If the minBoundY wasn't updated
|
||||
// we can savely assume that buffer_back[pos] == buffer[pos]
|
||||
// holdes true for all values of pos
|
||||
if (minBoundY == ~0) return;
|
||||
if (minBoundY == (uint8_t)(~0)) return;
|
||||
|
||||
sendCommand(COLUMNADDR);
|
||||
sendCommand(minBoundX);
|
||||
sendCommand(maxBoundX);
|
||||
sendCommand(x_offset + minBoundX);
|
||||
sendCommand(x_offset + maxBoundX);
|
||||
|
||||
sendCommand(PAGEADDR);
|
||||
sendCommand(minBoundY);
|
||||
@@ -97,7 +99,7 @@ class SSD1306Wire : public OLEDDisplay {
|
||||
Wire.beginTransmission(_address);
|
||||
Wire.write(0x40);
|
||||
}
|
||||
Wire.write(buffer[x + y * DISPLAY_WIDTH]);
|
||||
Wire.write(buffer[x + y * this->width()]);
|
||||
k++;
|
||||
if (k == 16) {
|
||||
Wire.endTransmission();
|
||||
@@ -113,12 +115,12 @@ class SSD1306Wire : public OLEDDisplay {
|
||||
#else
|
||||
|
||||
sendCommand(COLUMNADDR);
|
||||
sendCommand(0x0);
|
||||
sendCommand(0x7F);
|
||||
sendCommand(x_offset);
|
||||
sendCommand(x_offset + (this->width() - 1));
|
||||
|
||||
sendCommand(PAGEADDR);
|
||||
sendCommand(0x0);
|
||||
sendCommand(0x7);
|
||||
sendCommand((this->height() / 8) - 1);
|
||||
|
||||
for (uint16_t i=0; i < DISPLAY_BUFFER_SIZE; i++) {
|
||||
Wire.beginTransmission(this->_address);
|
||||
|
||||
@@ -420,7 +420,7 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig
|
||||
|
||||
lastOutActivity = millis();
|
||||
|
||||
return rc == tlen + 4 + plength;
|
||||
return rc == tlen + 3 + llen + plength;
|
||||
}
|
||||
|
||||
boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
#define MQTTQOS1 (1 << 1)
|
||||
#define MQTTQOS2 (2 << 1)
|
||||
|
||||
#ifdef ESP8266
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
#include <functional>
|
||||
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
|
||||
#else
|
||||
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
PATCH=puya.patch
|
||||
|
||||
for DIR in ~/.platformio/packages/framework-arduinoespressif8266*/; do
|
||||
|
||||
#not applied yet? (in upstream or otherwise)
|
||||
if ! grep FLASH_QUIRK_WRITE_0_TO_1 $DIR/cores/esp8266/Esp.cpp >/dev/null; then
|
||||
echo "Patching $DIR"
|
||||
patch -p1 -d $DIR < $PATCH
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
cores/esp8266/Esp.cpp | 16 +++++++++++++++-
|
||||
1 file changed, 15 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp
|
||||
index f4c0b220..c5c32f74 100644
|
||||
--- a/cores/esp8266/Esp.cpp
|
||||
+++ b/cores/esp8266/Esp.cpp
|
||||
@@ -501,7 +501,21 @@ bool EspClass::flashEraseSector(uint32_t sector) {
|
||||
|
||||
bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size) {
|
||||
ets_isr_mask(FLASH_INT_MASK);
|
||||
- int rc = spi_flash_write(offset, (uint32_t*) data, size);
|
||||
+ int rc;
|
||||
+ uint32_t* ptr = data;
|
||||
+#ifdef FLASH_QUIRK_WRITE_0_TO_1
|
||||
+ static uint32_t read_buf[SPI_FLASH_SEC_SIZE / 4];
|
||||
+ rc = spi_flash_read(offset, read_buf, size);
|
||||
+ if (rc != 0) {
|
||||
+ ets_isr_unmask(FLASH_INT_MASK);
|
||||
+ return false;
|
||||
+ }
|
||||
+ for (size_t i = 0; i < size / 4; ++i) {
|
||||
+ read_buf[i] &= data[i];
|
||||
+ }
|
||||
+ ptr = read_buf;
|
||||
+#endif // FLASH_QUIRK_WRITE_0_TO_1
|
||||
+ rc = spi_flash_write(offset, ptr, size);
|
||||
ets_isr_unmask(FLASH_INT_MASK);
|
||||
return rc == 0;
|
||||
}
|
||||
--
|
||||
+482
-68
@@ -7,11 +7,11 @@
|
||||
|
||||
#minimal version for esps with 512K or less flash (only has minimal plugin set)
|
||||
; [env:mini_512]
|
||||
; platform = espressif8266
|
||||
; 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,84 +19,498 @@
|
||||
# -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_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}"'
|
||||
build_flags = -D BUILD_GIT='"${env.TRAVIS_TAG}"' ; ${compiler_warnings.build_flags}
|
||||
lib_deps = ""
|
||||
lib_ignore = ESP32_ping, ESP32WebServer
|
||||
lib_ldf_mode = chain
|
||||
upload_speed = 460800
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
platform = ${core_2_3_0.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
|
||||
|
||||
[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}
|
||||
|
||||
### NORMAL (STABLE) ######################################################################
|
||||
# normal version with stable plugins #
|
||||
##########################################################################################
|
||||
|
||||
# NORMAL: 1024k version --------------------------
|
||||
[env:normal_ESP8266_1024]
|
||||
platform = espressif8266
|
||||
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}
|
||||
|
||||
#normal version with stable plugins, 4096k version
|
||||
[env:normal_ESP8266_4096]
|
||||
platform = espressif8266
|
||||
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
|
||||
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
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
upload_speed=460800
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD_TESTING
|
||||
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} -D PLUGIN_BUILD_TESTING
|
||||
|
||||
#version with additional plugins (and dependend code) that are in test-stadium 4096k
|
||||
[env:test_ESP8266_4096]
|
||||
platform = espressif8266
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
upload_speed=460800
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.4m1m.ld -D PLUGIN_BUILD_TESTING
|
||||
|
||||
#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
|
||||
framework = arduino
|
||||
board = esp8285
|
||||
upload_speed=460800
|
||||
build_flags = ${common.build_flags} -Wl,-Tesp8266.flash.1m128.ld -D PLUGIN_BUILD_TESTING -DESP8285
|
||||
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_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 = ${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_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 = ${common.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 = ${common.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
|
||||
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 = ${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_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
|
||||
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
|
||||
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 = ${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_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 = ${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_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 = ${common.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
|
||||
|
||||
|
||||
|
||||
### DEV + PUYA ###########################################################################
|
||||
# special patched version for PUYA flash chips, see issue #650 at Github #
|
||||
##########################################################################################
|
||||
|
||||
# DEV+PUYA : 1024k version -----------------------
|
||||
[env:dev_ESP8266PUYA_1024]
|
||||
platform = ${common.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
|
||||
|
||||
# DEV+PUYA : 1024k version + FEATURE_ADC_VCC -----
|
||||
[env:dev_ESP8266PUYA_1024_VCC]
|
||||
platform = ${common.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 = ${common.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 = ${common.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 = ${common.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 --------------------
|
||||
#[env:hard_SONOFF_POW]
|
||||
#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 = ${Sonoff.board_flash_mode}
|
||||
#board = ${Sonoff.board}
|
||||
#build_flags = ${Sonoff.build_flags} -D PLUGIN_SET_SONOFF_POW
|
||||
|
||||
# ITEAD / SONOFF S20 version --------------------
|
||||
#[env:hard_SONOFF_S20]
|
||||
#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 = ${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 = ${common.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 = ${common.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
|
||||
|
||||
+358
-119
@@ -38,30 +38,146 @@ 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();
|
||||
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("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("timerset") ) == 0) return cmd_TimerSet;
|
||||
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:
|
||||
return cmd_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 +185,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 +197,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 +228,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 +247,20 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
event += x;
|
||||
SendUDPCommand(Par1, (char*)event.c_str(), event.length());
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef FEATURE_SD
|
||||
if (strcasecmp_P(Command, PSTR("sdcard")) == 0)
|
||||
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,56 +268,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("accessinfo")) == 0)
|
||||
case cmd_accessinfo:
|
||||
{
|
||||
success = true;
|
||||
Serial.print(F("Allowed IP range : "));
|
||||
Serial.println(describeAllowedIPrange());
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("clearaccessblock")) == 0)
|
||||
case cmd_clearaccessblock:
|
||||
{
|
||||
success = true;
|
||||
clearAccessBlock();
|
||||
Serial.print(F("Allowed IP range : "));
|
||||
Serial.println(describeAllowedIPrange());
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("meminfo")) == 0)
|
||||
case cmd_meminfo:
|
||||
{
|
||||
success = true;
|
||||
Serial.print(F("SecurityStruct : "));
|
||||
@@ -205,24 +335,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;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("wdconfig")) == 0)
|
||||
//quickly clear all tasks, without saving (used by test suite)
|
||||
case cmd_TaskClearAll:
|
||||
{
|
||||
success = true;
|
||||
for (byte t=0; t<TASKS_MAX; t++)
|
||||
taskClear(t, false);
|
||||
break;
|
||||
}
|
||||
|
||||
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
|
||||
@@ -236,22 +378,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;
|
||||
|
||||
@@ -271,28 +416,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))
|
||||
@@ -301,15 +449,17 @@ 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_TaskRun:
|
||||
{
|
||||
success = true;
|
||||
SensorSendTask(Par1 - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("TimerSet")) == 0)
|
||||
case cmd_TimerSet:
|
||||
{
|
||||
if (Par1>=1 && Par1<=RULES_TIMER_MAX)
|
||||
{
|
||||
@@ -325,24 +475,27 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F("TIMER: invalid timer number"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcasecmp_P(Command, PSTR("Delay")) == 0)
|
||||
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;
|
||||
@@ -350,9 +503,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;
|
||||
@@ -363,145 +517,210 @@ 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:
|
||||
{
|
||||
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);
|
||||
MQTTclient.publish(topic.c_str(), value.c_str(), Settings.MQTTRetainFlag);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
byte ipaddress[4];
|
||||
str2ip((char*)ip.c_str(), ipaddress);
|
||||
IPAddress UDP_IP(ipaddress[0], ipaddress[1], ipaddress[2], ipaddress[3]);
|
||||
portUDP.beginPacket(UDP_IP, port.toInt());
|
||||
#if defined(ESP8266)
|
||||
portUDP.write(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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
client.flush();
|
||||
client.stop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cmd_SendToUDP:
|
||||
{
|
||||
if (wifiStatus == ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
success = true;
|
||||
String strLine = Line;
|
||||
String ip = parseString(strLine, 2);
|
||||
String port = parseString(strLine, 3);
|
||||
int msgpos = getParamStartPos(strLine, 4);
|
||||
String message = strLine.substring(msgpos);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
#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);
|
||||
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);
|
||||
@@ -513,54 +732,70 @@ void ExecuteCommand(byte source, const char *Line)
|
||||
#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
|
||||
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();
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
#endif
|
||||
#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 (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];
|
||||
@@ -578,6 +813,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();
|
||||
|
||||
+86
-76
@@ -3,13 +3,11 @@
|
||||
//********************************************************************************
|
||||
void sendData(struct EventStruct *event)
|
||||
{
|
||||
LoadTaskSettings(event->TaskIndex);
|
||||
checkRAM(F("sendData"));
|
||||
LoadTaskSettings(event->TaskIndex);
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(event->TaskIndex);
|
||||
|
||||
if (Settings.GlobalSync && Settings.TaskDeviceGlobalSync[event->TaskIndex])
|
||||
SendUDPTaskData(0, event->TaskIndex, event->TaskIndex);
|
||||
|
||||
if (Settings.UseValueLogger && Settings.InitSPI && Settings.Pin_sd_cs >= 0)
|
||||
SendValueLogger(event->TaskIndex);
|
||||
|
||||
@@ -62,11 +60,7 @@ void sendData(struct EventStruct *event)
|
||||
boolean validUserVar(struct EventStruct *event) {
|
||||
for (int i = 0; i < VARS_PER_TASK; ++i) {
|
||||
const float f(UserVar[event->BaseVarIndex + i]);
|
||||
if (f == NAN) return false; //("NaN");
|
||||
if (f == INFINITY) return false; //("INFINITY");
|
||||
if (-f == INFINITY)return false; //("-INFINITY");
|
||||
if (isnan(f)) return false; //("isnan");
|
||||
if (isinf(f)) return false; //("isinf");
|
||||
if (!isValidFloat(f)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -80,8 +74,12 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
|
||||
char c_payload[384];
|
||||
|
||||
statusLED(true);
|
||||
|
||||
if (length>sizeof(c_payload)-1)
|
||||
int enabledMqttController = firstEnabledMQTTController();
|
||||
if (enabledMqttController < 0) {
|
||||
addLog(LOG_LEVEL_ERROR, F("MQTT : No enabled MQTT controller"));
|
||||
return;
|
||||
}
|
||||
if ((length + 1) > sizeof(c_payload))
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F("MQTT : Ignored too big message"));
|
||||
return;
|
||||
@@ -108,7 +106,7 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
|
||||
struct EventStruct TempEvent;
|
||||
TempEvent.String1 = c_topic;
|
||||
TempEvent.String2 = c_payload;
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[0]);
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[enabledMqttController]);
|
||||
CPlugin_ptr[ProtocolIndex](CPLUGIN_PROTOCOL_RECV, &TempEvent, dummyString);
|
||||
}
|
||||
|
||||
@@ -116,12 +114,14 @@ void callback(char* c_topic, byte* b_payload, unsigned int length) {
|
||||
/*********************************************************************************************\
|
||||
* Connect to MQTT message broker
|
||||
\*********************************************************************************************/
|
||||
void MQTTConnect()
|
||||
bool MQTTConnect(int controller_idx)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) return;
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(0, (byte*)&ControllerSettings, sizeof(ControllerSettings)); // todo index is now fixed to 0
|
||||
|
||||
LoadControllerSettings(controller_idx, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
if (!ControllerSettings.checkHostReachable(true))
|
||||
return false;
|
||||
if (MQTTclient.connected())
|
||||
MQTTclient.disconnect();
|
||||
if (ControllerSettings.UseDNS) {
|
||||
MQTTclient.setServer(ControllerSettings.getHost().c_str(), ControllerSettings.Port);
|
||||
} else {
|
||||
@@ -130,78 +130,79 @@ void MQTTConnect()
|
||||
MQTTclient.setCallback(callback);
|
||||
|
||||
// MQTT needs a unique clientname to subscribe to broker
|
||||
String clientid = Settings.Name; // clientid = %sysname%
|
||||
if (Settings.Unit != 0) // set unit number to zero if don't want to add to clientid
|
||||
{
|
||||
clientid += Settings.Unit;
|
||||
}
|
||||
String subscribeTo = "";
|
||||
String clientid = F("ESPClient_");
|
||||
clientid += WiFi.macAddress();
|
||||
|
||||
String LWTTopic = ControllerSettings.Subscribe;
|
||||
LWTTopic.replace(F("/#"), F("/status"));
|
||||
LWTTopic.replace(F("%sysname%"), Settings.Name);
|
||||
parseSystemVariables(LWTTopic, false);
|
||||
LWTTopic += F("/LWT"); // Extend the topic for status updates of connected/disconnected status.
|
||||
|
||||
for (byte x = 1; x < 3; x++)
|
||||
{
|
||||
String log = "";
|
||||
boolean MQTTresult = false;
|
||||
boolean MQTTresult = false;
|
||||
uint8_t willQos = 0;
|
||||
boolean willRetain = true;
|
||||
|
||||
if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0))
|
||||
MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser[0], SecuritySettings.ControllerPassword[0], LWTTopic.c_str(), 0, 1, "Connection Lost");
|
||||
else
|
||||
MQTTresult = MQTTclient.connect(clientid.c_str(), LWTTopic.c_str(), 0, 1, "Connection Lost");
|
||||
|
||||
if (MQTTresult)
|
||||
{
|
||||
log = F("MQTT : ClientID ");
|
||||
log += clientid;
|
||||
log += " connected to broker";
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
subscribeTo = ControllerSettings.Subscribe;
|
||||
subscribeTo.replace(F("%sysname%"), Settings.Name);
|
||||
MQTTclient.subscribe(subscribeTo.c_str());
|
||||
log = F("Subscribed to: ");
|
||||
log += subscribeTo;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
MQTTclient.publish(LWTTopic.c_str(), "Connected", 1);
|
||||
|
||||
statusLED(true);
|
||||
break; // end loop if succesfull
|
||||
}
|
||||
else
|
||||
{
|
||||
log = F("MQTT : ClientID ");
|
||||
log += clientid;
|
||||
log +=" failed to connected to broker";
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
}
|
||||
|
||||
delay(500);
|
||||
if ((SecuritySettings.ControllerUser[controller_idx] != 0) && (SecuritySettings.ControllerPassword[controller_idx] != 0)) {
|
||||
MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser[controller_idx], SecuritySettings.ControllerPassword[controller_idx],
|
||||
LWTTopic.c_str(), willQos, willRetain, "Connection Lost");
|
||||
} else {
|
||||
MQTTresult = MQTTclient.connect(clientid.c_str(), LWTTopic.c_str(), willQos, willRetain, "Connection Lost");
|
||||
}
|
||||
yield();
|
||||
|
||||
if (!MQTTresult) {
|
||||
addLog(LOG_LEVEL_ERROR, F("MQTT : Failed to connect to broker"));
|
||||
return false;
|
||||
}
|
||||
MQTTclient_should_reconnect = false;
|
||||
String log = F("MQTT : Connected to broker with client ID: ");
|
||||
log += clientid;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
String subscribeTo = ControllerSettings.Subscribe;
|
||||
parseSystemVariables(subscribeTo, false);
|
||||
MQTTclient.subscribe(subscribeTo.c_str());
|
||||
log = F("Subscribed to: ");
|
||||
log += subscribeTo;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
if (MQTTclient.publish(LWTTopic.c_str(), "Connected", 1)) {
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
String event = F("MQTT#Connected");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
statusLED(true);
|
||||
return true; // end loop if succesfull
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Check connection MQTT message broker
|
||||
\*********************************************************************************************/
|
||||
void MQTTCheck()
|
||||
bool MQTTCheck(int controller_idx)
|
||||
{
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[0]);
|
||||
if (!WiFiConnected(10))
|
||||
return false;
|
||||
byte ProtocolIndex = getProtocolIndex(Settings.Protocol[controller_idx]);
|
||||
if (Protocol[ProtocolIndex].usesMQTT)
|
||||
{
|
||||
if (!MQTTclient.connected() || WiFi.status() != WL_CONNECTED)
|
||||
if (MQTTclient_should_reconnect || !MQTTclient.connected())
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F("MQTT : Connection lost"));
|
||||
connectionFailures += 2;
|
||||
MQTTclient.disconnect();
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
delay(1000);
|
||||
MQTTConnect();
|
||||
if (MQTTclient_should_reconnect) {
|
||||
addLog(LOG_LEVEL_ERROR, F("MQTT : Intentional reconnect"));
|
||||
} else {
|
||||
addLog(LOG_LEVEL_ERROR, F("MQTT : Connection lost"));
|
||||
connectionFailures += 2;
|
||||
}
|
||||
}
|
||||
else if (connectionFailures)
|
||||
return MQTTConnect(controller_idx);
|
||||
} else if (connectionFailures) {
|
||||
connectionFailures--;
|
||||
}
|
||||
}
|
||||
// When no MQTT protocol is enabled, all is fine.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -226,6 +227,13 @@ 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))
|
||||
return true;
|
||||
addLog(LOG_LEVEL_DEBUG, F("MQTT : publish failed"));
|
||||
return false;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Send status info back to channel where request came from
|
||||
@@ -233,10 +241,12 @@ void SendStatus(byte source, String status)
|
||||
void MQTTStatus(String& status)
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(0, (byte*)&ControllerSettings, sizeof(ControllerSettings)); // todo index is now fixed to 0
|
||||
|
||||
String pubname = ControllerSettings.Subscribe;
|
||||
pubname.replace(F("/#"), F("/status"));
|
||||
pubname.replace(F("%sysname%"), Settings.Name);
|
||||
MQTTclient.publish(pubname.c_str(), status.c_str(),Settings.MQTTRetainFlag);
|
||||
int enabledMqttController = firstEnabledMQTTController();
|
||||
if (enabledMqttController >= 0) {
|
||||
LoadControllerSettings(enabledMqttController, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
String pubname = ControllerSettings.Subscribe;
|
||||
pubname.replace(F("/#"), F("/status"));
|
||||
parseSystemVariables(pubname, false);
|
||||
MQTTpublish(enabledMqttController, pubname.c_str(), status.c_str(),Settings.MQTTRetainFlag);
|
||||
}
|
||||
}
|
||||
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
|
||||
/*********************************************************************************************\
|
||||
Convert bearing in degree to bearing string
|
||||
\*********************************************************************************************/
|
||||
|
||||
String getBearing(int degrees)
|
||||
{
|
||||
const __FlashStringHelper* bearing[] = {
|
||||
F("N"),
|
||||
F("NNE"),
|
||||
F("NE"),
|
||||
F("ENE"),
|
||||
F("E"),
|
||||
F("ESE"),
|
||||
F("SE"),
|
||||
F("SSE"),
|
||||
F("S"),
|
||||
F("SSW"),
|
||||
F("SW"),
|
||||
F("WSW"),
|
||||
F("W"),
|
||||
F("WNW"),
|
||||
F("NW"),
|
||||
F("NNW")
|
||||
};
|
||||
int nr_directions = (int) (sizeof(bearing)/sizeof(bearing[0]));
|
||||
float stepsize = (360.0 / nr_directions);
|
||||
if (degrees < 0) { degrees += 360; } // Allow for bearing -360 .. 359
|
||||
int bearing_idx=int((degrees + (stepsize / 2.0)) / stepsize) % nr_directions;
|
||||
if (bearing_idx < 0)
|
||||
return("");
|
||||
else
|
||||
return(bearing[bearing_idx]);
|
||||
}
|
||||
|
||||
float CelsiusToFahrenheit(float celsius) {
|
||||
return celsius * (9.0 / 5.0) + 32;
|
||||
}
|
||||
|
||||
int m_secToBeaufort(float m_per_sec) {
|
||||
if (m_per_sec < 0.3) return 0;
|
||||
if (m_per_sec < 1.6) return 1;
|
||||
if (m_per_sec < 3.4) return 2;
|
||||
if (m_per_sec < 5.5) return 3;
|
||||
if (m_per_sec < 8.0) return 4;
|
||||
if (m_per_sec < 10.8) return 5;
|
||||
if (m_per_sec < 13.9) return 6;
|
||||
if (m_per_sec < 17.2) return 7;
|
||||
if (m_per_sec < 20.8) return 8;
|
||||
if (m_per_sec < 24.5) return 9;
|
||||
if (m_per_sec < 28.5) return 10;
|
||||
if (m_per_sec < 32.6) return 11;
|
||||
return 12;
|
||||
}
|
||||
|
||||
String centimeterToImperialLength(float cm) {
|
||||
return millimeterToImperialLength(cm * 10.0);
|
||||
}
|
||||
|
||||
String millimeterToImperialLength(float mm) {
|
||||
float inches = mm / 25.4;
|
||||
int feet = inches /12;
|
||||
inches = inches - (feet * 12);
|
||||
String result;
|
||||
result.reserve(10);
|
||||
if (feet != 0) {
|
||||
result += feet;
|
||||
result += '\'';
|
||||
}
|
||||
result += toString(inches,1);
|
||||
result += '"';
|
||||
return result;
|
||||
}
|
||||
|
||||
float minutesToDay(int minutes) {
|
||||
return minutes / 1440.0;
|
||||
}
|
||||
|
||||
String minutesToDayHour(int minutes) {
|
||||
int days = minutes / 1440;
|
||||
int hours = (minutes % 1440) / 60;
|
||||
char TimeString[6]; //5 digits plus the null char
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d%c"), days, 'd', hours, 'h');
|
||||
return TimeString;
|
||||
}
|
||||
|
||||
String 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;
|
||||
int mins = (minutes % 1440) % 60;
|
||||
char TimeString[20];
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d%c%02d%c"), days, 'd', hours, 'h', mins, 'm');
|
||||
return TimeString;
|
||||
}
|
||||
|
||||
String secondsToDayHourMinuteSecond(int seconds) {
|
||||
int sec = seconds % 60;
|
||||
int minutes = seconds / 60;
|
||||
int days = minutes / 1440;
|
||||
int hours = (minutes % 1440) / 60;
|
||||
int mins = (minutes % 1440) % 60;
|
||||
char TimeString[20];
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d%c%02d%c%02d"), days, 'd', hours, ':', mins, ':', sec);
|
||||
return TimeString;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
In memory convert float to long
|
||||
\*********************************************************************************************/
|
||||
unsigned long float2ul(float f)
|
||||
{
|
||||
unsigned long ul;
|
||||
memcpy(&ul, &f, 4);
|
||||
return ul;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
In memory convert long to float
|
||||
\*********************************************************************************************/
|
||||
float ul2float(unsigned long ul)
|
||||
{
|
||||
float f;
|
||||
memcpy(&f, &ul, 4);
|
||||
return f;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
To modify the stock configuration without changing the EspEasy.ino file :
|
||||
|
||||
1) rename this file to "Custom.h" (It is ignored by Git)
|
||||
2) define your own settings below
|
||||
3) define USE_CUSTOM_H as a build flags. ie : export PLATFORMIO_BUILD_FLAGS="'-DUSE_CUSTOM_H'"
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// make the compiler show a warning to confirm that this file is inlcuded
|
||||
#warning "**** Using Settings from Custom.h File ***"
|
||||
|
||||
/*
|
||||
|
||||
#######################################################################################################
|
||||
Your Own Default Settings
|
||||
#######################################################################################################
|
||||
|
||||
You can basically ovveride ALL macro defined in ESPEasy.ino.
|
||||
Don't forget to first #undef each existing #define that you add below.
|
||||
Here are some examples:
|
||||
*/
|
||||
|
||||
|
||||
#undef DEFAULT_NAME
|
||||
#define DEFAULT_NAME "MyEspEasyDevice" // Enter your device friendly name
|
||||
|
||||
#undef DEFAULT_SSID
|
||||
#define DEFAULT_SSID "MyHomeSSID" // Enter your network SSID
|
||||
|
||||
#undef DEFAULT_KEY
|
||||
#define DEFAULT_KEY "MySuperSecretPassword" // Enter your network WPA key
|
||||
|
||||
#undef DEFAULT_AP_KEY
|
||||
#define DEFAULT_AP_KEY "MyOwnConfigPassword" // Enter network WPA key for AP (config) mode
|
||||
|
||||
#ifdef BUILD_GIT
|
||||
#undef BUILD_GIT
|
||||
#endif
|
||||
|
||||
#define BUILD_GIT "MyBuildNum"
|
||||
File diff suppressed because it is too large
Load Diff
+134
-806
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,70 @@
|
||||
#ifndef ESPEASY_TIMETYPES_H_
|
||||
#define ESPEASY_TIMETYPES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct timeStruct {
|
||||
timeStruct() : Second(0), Minute(0), Hour(0), Wday(0), Day(0), Month(0), Year(0) {}
|
||||
uint8_t Second;
|
||||
uint8_t Minute;
|
||||
uint8_t Hour;
|
||||
uint8_t Wday; // day of week, sunday is day 1
|
||||
uint8_t Day;
|
||||
uint8_t Month;
|
||||
uint8_t Year; // offset from 1970;
|
||||
};
|
||||
|
||||
// convenient constants for TimeChangeRules
|
||||
enum week_t {Last=0, First, Second, Third, Fourth};
|
||||
enum dow_t {Sun=1, Mon, Tue, Wed, Thu, Fri, Sat};
|
||||
enum month_t {Jan=1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
|
||||
|
||||
// structure to describe rules for when daylight/summer time begins,
|
||||
// or when standard time begins.
|
||||
// For Daylight Saving Time Around the World, see:
|
||||
// - https://www.timeanddate.com/time/dst/2018.html
|
||||
// - https://en.wikipedia.org/wiki/Daylight_saving_time_by_country
|
||||
struct TimeChangeRule {
|
||||
TimeChangeRule() : week(0), dow(1), month(1), hour(0), offset(0) {}
|
||||
TimeChangeRule(uint8_t weeknr, uint8_t downr, uint8_t m, uint8_t h, uint16_t minutesoffset) :
|
||||
week(weeknr), dow(downr), month(m), hour(h), offset(minutesoffset) {}
|
||||
|
||||
// Construct time change rule from stored values optimized for minimum space.
|
||||
TimeChangeRule(uint16_t flash_stored_value, int16_t minutesoffset) : offset(minutesoffset) {
|
||||
hour = flash_stored_value & 0x001f;
|
||||
month = (flash_stored_value >> 5) & 0x000f;
|
||||
dow = (flash_stored_value >> 9) & 0x0007;
|
||||
week = (flash_stored_value >> 12) & 0x0007;
|
||||
}
|
||||
|
||||
uint16_t toFlashStoredValue() const {
|
||||
uint16_t value = hour;
|
||||
value = value | (month << 5);
|
||||
value = value | (dow << 9);
|
||||
value = value | (week << 12);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return (week <= 4) && (dow != 0) && (dow <= 7) &&
|
||||
(month != 0) && (month <= 12) && (hour <= 23) &&
|
||||
(offset > -720) && (offset < 900); // UTC-12h ... UTC+14h + 1h DSToffset
|
||||
}
|
||||
|
||||
uint8_t week; // First, Second, Third, Fourth, or Last week of the month
|
||||
uint8_t dow; // day of week, 1=Sun, 2=Mon, ... 7=Sat
|
||||
uint8_t month; // 1=Jan, 2=Feb, ... 12=Dec
|
||||
uint8_t hour; // 0-23
|
||||
int16_t offset; // offset from UTC in minutes
|
||||
};
|
||||
|
||||
// Forward declartions
|
||||
void applyTimeZone(uint32_t curTime = 0);
|
||||
void setTimeZone(const TimeChangeRule& dstStart, const TimeChangeRule& stdStart, uint32_t curTime = 0);
|
||||
uint32_t calcTimeChangeForRule(const TimeChangeRule& r, int yr);
|
||||
String getTimeString(char delimiter, bool show_seconds=true);
|
||||
String getTimeString_ampm(char delimiter, bool show_seconds=true);
|
||||
long timeDiff(unsigned long prev, unsigned long next);
|
||||
|
||||
|
||||
#endif /* ESPEASY_TIMETYPES_H_ */
|
||||
@@ -0,0 +1,68 @@
|
||||
//********************************************************************************
|
||||
// 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:
|
||||
lastGetIPmoment = millis();
|
||||
wifiStatus = ESPEASY_WIFI_GOT_IP;
|
||||
processedGetIP = 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);
|
||||
processedDisconnect = false;
|
||||
lastDisconnectReason = event.reason;
|
||||
wifiStatus = ESPEASY_WIFI_DISCONNECTED;
|
||||
}
|
||||
|
||||
void onGotIP(const WiFiEventStationModeGotIP& event){
|
||||
lastGetIPmoment = millis();
|
||||
wifiStatus = ESPEASY_WIFI_GOT_IP;
|
||||
processedGetIP = false;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,513 @@
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// 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;
|
||||
if (wifiStatus < ESPEASY_WIFI_CONNECTED) return;
|
||||
|
||||
String log = F("WIFI : Connected! AP: ");
|
||||
log += WiFi.SSID();
|
||||
log += F(" (");
|
||||
log += WiFi.BSSIDstr();
|
||||
log += F(") Ch: ");
|
||||
log += last_channel;
|
||||
const long connect_duration = timeDiff(last_wifi_connect_attempt_moment, lastConnectMoment);
|
||||
if (connect_duration > 0 && connect_duration < 30000) {
|
||||
// Just log times when they make sense.
|
||||
log += F(" Duration: ");
|
||||
log += connect_duration;
|
||||
log += F(" ms");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
if (Settings.UseRules && bssid_changed) {
|
||||
String event = F("WiFi#ChangedAccesspoint");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
wifi_connect_attempt = 0;
|
||||
processedConnect = true;
|
||||
}
|
||||
|
||||
void processDisconnect() {
|
||||
if (processedDisconnect) return;
|
||||
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);
|
||||
processedDisconnect = true;
|
||||
|
||||
if (Settings.deepSleep && Settings.deepSleepOnFail) {
|
||||
//only one attempt in deepsleep, to conserve battery
|
||||
addLog(LOG_LEVEL_ERROR, F("SLEEP: Connection failed, going back to sleep."));
|
||||
deepSleep(Settings.Delay);
|
||||
}
|
||||
|
||||
if (!intent_to_reboot)
|
||||
WiFiConnectRelaxed();
|
||||
}
|
||||
|
||||
|
||||
void processGotIP() {
|
||||
if (processedGetIP)
|
||||
return;
|
||||
if (wifiStatus < ESPEASY_WIFI_GOT_IP)
|
||||
return;
|
||||
IPAddress ip = WiFi.localIP();
|
||||
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();
|
||||
}
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
String event = F("WiFi#Connected");
|
||||
rulesProcessing(event);
|
||||
}
|
||||
statusLED(true);
|
||||
wifiStatus = ESPEASY_WIFI_SERVICES_INITIALIZED;
|
||||
processedGetIP = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Set Wifi AP Mode config
|
||||
//********************************************************************************
|
||||
void WifiAPconfig()
|
||||
{
|
||||
// create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password!
|
||||
// setup ssid for AP Mode when needed
|
||||
|
||||
String softAPSSID=WifiGetAPssid();
|
||||
String pwd = SecuritySettings.WifiAPKey;
|
||||
WiFi.softAP(softAPSSID.c_str(),pwd.c_str());
|
||||
// We start in STA mode
|
||||
WifiAPMode(false);
|
||||
|
||||
String log("WIFI : AP Mode ssid will be ");
|
||||
log=log+WifiGetAPssid();
|
||||
|
||||
log=log+F(" with address ");
|
||||
log=log+apIP.toString();
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
|
||||
|
||||
bool WifiIsAP()
|
||||
{
|
||||
#if defined(ESP8266)
|
||||
byte wifimode = wifi_get_opmode();
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
byte wifimode = WiFi.getMode();
|
||||
#endif
|
||||
return(wifimode == 2 || wifimode == 3); //apmode is enabled
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Set Wifi AP Mode
|
||||
//********************************************************************************
|
||||
void WifiAPMode(boolean state)
|
||||
{
|
||||
if (WifiIsAP())
|
||||
{
|
||||
//want to disable?
|
||||
if (!state)
|
||||
{
|
||||
WiFi.mode(WIFI_STA);
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : AP Mode disabled"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//want to enable?
|
||||
if (state)
|
||||
{
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : AP Mode enabled"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool useStaticIP() {
|
||||
return (Settings.IP[0] != 0 && Settings.IP[0] != 255);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Set Wifi config
|
||||
//********************************************************************************
|
||||
bool prepareWiFi() {
|
||||
if (!selectValidWiFiSettings())
|
||||
return false;
|
||||
|
||||
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
|
||||
|
||||
//use static ip?
|
||||
if (useStaticIP())
|
||||
{
|
||||
const IPAddress ip = Settings.IP;
|
||||
log = F("IP : Static IP :");
|
||||
log += ip;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
const IPAddress gw = Settings.Gateway;
|
||||
const IPAddress subnet = Settings.Subnet;
|
||||
const IPAddress dns = Settings.DNS;
|
||||
WiFi.config(ip, gw, subnet, dns);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Start connect to WiFi and check later to see if connected.
|
||||
//********************************************************************************
|
||||
void WiFiConnectRelaxed() {
|
||||
if (prepareWiFi()) {
|
||||
tryConnectWiFi();
|
||||
return;
|
||||
}
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP! (relaxed connect mode)"));
|
||||
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
|
||||
WifiAPMode(true);
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Manage WiFi credentials
|
||||
//********************************************************************************
|
||||
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;
|
||||
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 (wifiSetupConnect) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Simply start the WiFi connection sequence
|
||||
//********************************************************************************
|
||||
bool tryConnectWiFi() {
|
||||
if (wifiSetup && !wifiSetupConnect)
|
||||
return false;
|
||||
if (wifiStatus != ESPEASY_WIFI_DISCONNECTED)
|
||||
return(true); //already connected, need to disconnect first
|
||||
if (!wifiConnectTimeoutReached())
|
||||
return true; // timeout not reached yet, thus no need to retry again.
|
||||
if (!selectValidWiFiSettings()) {
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : No valid WiFi settings!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wifi_connect_attempt != 0 && ((wifi_connect_attempt % 3) == 0)) {
|
||||
// Change to other wifi settings.
|
||||
if (selectNextWiFiSettings())
|
||||
WiFi.disconnect();
|
||||
}
|
||||
if (wifi_connect_attempt > 6) {
|
||||
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
|
||||
WifiAPMode(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);
|
||||
|
||||
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;
|
||||
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()
|
||||
{
|
||||
WiFi.disconnect();
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// 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 (wifiStatus == ESPEASY_WIFI_DISCONNECTED)
|
||||
{
|
||||
NC_Count++;
|
||||
WiFiConnectRelaxed();
|
||||
}
|
||||
//connected
|
||||
else
|
||||
{
|
||||
C_Count++;
|
||||
NC_Count = 0;
|
||||
if (C_Count > 2) // disable AP after timeout if a Wifi connection is established...
|
||||
{
|
||||
WifiAPMode(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Return subnet range of WiFi.
|
||||
//********************************************************************************
|
||||
bool getSubnetRange(IPAddress& low, IPAddress& high)
|
||||
{
|
||||
if (WifiIsAP()) {
|
||||
// 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() {
|
||||
switch (lastDisconnectReason) {
|
||||
case WIFI_DISCONNECT_REASON_UNSPECIFIED: return F("Unspecified");
|
||||
case WIFI_DISCONNECT_REASON_AUTH_EXPIRE: return F("Auth expire");
|
||||
case WIFI_DISCONNECT_REASON_AUTH_LEAVE: return F("Auth leave");
|
||||
case WIFI_DISCONNECT_REASON_ASSOC_EXPIRE: return F("Assoc expire");
|
||||
case WIFI_DISCONNECT_REASON_ASSOC_TOOMANY: return F("Assoc toomany");
|
||||
case WIFI_DISCONNECT_REASON_NOT_AUTHED: return F("Not authed");
|
||||
case WIFI_DISCONNECT_REASON_NOT_ASSOCED: return F("Not assoced");
|
||||
case WIFI_DISCONNECT_REASON_ASSOC_LEAVE: return F("Assoc leave");
|
||||
case WIFI_DISCONNECT_REASON_ASSOC_NOT_AUTHED: return F("Assoc not authed");
|
||||
case WIFI_DISCONNECT_REASON_DISASSOC_PWRCAP_BAD: return F("Disassoc pwrcap bad");
|
||||
case WIFI_DISCONNECT_REASON_DISASSOC_SUPCHAN_BAD: return F("Disassoc supchan bad");
|
||||
case WIFI_DISCONNECT_REASON_IE_INVALID: return F("IE invalid");
|
||||
case WIFI_DISCONNECT_REASON_MIC_FAILURE: return F("Mic failure");
|
||||
case WIFI_DISCONNECT_REASON_4WAY_HANDSHAKE_TIMEOUT: return F("4way handshake timeout");
|
||||
case WIFI_DISCONNECT_REASON_GROUP_KEY_UPDATE_TIMEOUT: return F("Group key update timeout");
|
||||
case WIFI_DISCONNECT_REASON_IE_IN_4WAY_DIFFERS: return F("IE in 4way differs");
|
||||
case WIFI_DISCONNECT_REASON_GROUP_CIPHER_INVALID: return F("Group cipher invalid");
|
||||
case WIFI_DISCONNECT_REASON_PAIRWISE_CIPHER_INVALID: return F("Pairwise cipher invalid");
|
||||
case WIFI_DISCONNECT_REASON_AKMP_INVALID: return F("AKMP invalid");
|
||||
case WIFI_DISCONNECT_REASON_UNSUPP_RSN_IE_VERSION: return F("Unsupp RSN IE version");
|
||||
case WIFI_DISCONNECT_REASON_INVALID_RSN_IE_CAP: return F("Invalid RSN IE cap");
|
||||
case WIFI_DISCONNECT_REASON_802_1X_AUTH_FAILED: return F("802 1X auth failed");
|
||||
case WIFI_DISCONNECT_REASON_CIPHER_SUITE_REJECTED: return F("Cipher suite rejected");
|
||||
case WIFI_DISCONNECT_REASON_BEACON_TIMEOUT: return F("Beacon timeout");
|
||||
case WIFI_DISCONNECT_REASON_NO_AP_FOUND: return F("No AP found");
|
||||
case WIFI_DISCONNECT_REASON_AUTH_FAIL: return F("Auth fail");
|
||||
case WIFI_DISCONNECT_REASON_ASSOC_FAIL: return F("Assoc fail");
|
||||
case WIFI_DISCONNECT_REASON_HANDSHAKE_TIMEOUT: return F("Handshake timeout");
|
||||
}
|
||||
return F("Unknown");
|
||||
}
|
||||
+827
-1075
File diff suppressed because it is too large
Load Diff
+69
-173
@@ -2,56 +2,40 @@
|
||||
// Syslog
|
||||
// UDP system messaging
|
||||
// SSDP
|
||||
#if LWIP_VERSION_MAJOR == 2
|
||||
#define IP2STR(addr) (uint8_t)((uint32_t)addr & 0xFF), (uint8_t)(((uint32_t)addr >> 8) & 0xFF), (uint8_t)(((uint32_t)addr >> 16) & 0xFF), (uint8_t)(((uint32_t)addr >> 24) & 0xFF)
|
||||
#endif
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Syslog client
|
||||
\*********************************************************************************************/
|
||||
void syslog(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;
|
||||
snprintf_P(str, sizeof(str), PSTR("<7>ESP Unit: %u : %s"), Settings.Unit, message);
|
||||
// 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);
|
||||
|
||||
// Using Setting.Unit to build a Hostname
|
||||
//snprintf_P(str, sizeof(str), PSTR("<7>EspEasy_%u ESP: %s"), Settings.Unit, message);
|
||||
#if defined(ESP8266)
|
||||
portUDP.write(str);
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
portUDP.write((uint8_t*)str,strlen(str));
|
||||
#endif
|
||||
portUDP.endPacket();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Structs for UDP messaging
|
||||
\*********************************************************************************************/
|
||||
struct infoStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 3;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
byte deviceNumber;
|
||||
char taskName[26];
|
||||
char ValueNames[VARS_PER_TASK][26];
|
||||
};
|
||||
|
||||
struct dataStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 5;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
float Values[VARS_PER_TASK];
|
||||
};
|
||||
|
||||
//TODO: add sysinfoStruct
|
||||
|
||||
/*********************************************************************************************\
|
||||
Check UDP messages (ESPEasy propiertary protocol)
|
||||
\*********************************************************************************************/
|
||||
@@ -95,22 +79,10 @@ void checkUDP()
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packetBuffer[1] > 1 && packetBuffer[1] < 6)
|
||||
{
|
||||
String log = (F("UDP : Sensor msg "));
|
||||
for (byte x = 1; x < 6; x++)
|
||||
{
|
||||
log += " ";
|
||||
log += (int)packetBuffer[x];
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
}
|
||||
|
||||
// binary data!
|
||||
switch (packetBuffer[1])
|
||||
{
|
||||
|
||||
//TODO: use a nice struct for it
|
||||
case 1: // sysinfo message
|
||||
{
|
||||
byte mac[6];
|
||||
@@ -147,70 +119,13 @@ void checkUDP()
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: // sensor info pull request
|
||||
{
|
||||
SendUDPTaskInfo(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: // sensor info
|
||||
{
|
||||
if (Settings.GlobalSync)
|
||||
{
|
||||
struct infoStruct infoReply;
|
||||
memcpy((byte*)&infoReply, (byte*)&packetBuffer, sizeof(infoStruct));
|
||||
|
||||
// to prevent flash wear out (bugs in communication?) we can only write to an empty task
|
||||
// so it will write only once and has to be cleared manually through webgui
|
||||
if (Settings.TaskDeviceNumber[infoReply.destTaskIndex] == 0)
|
||||
{
|
||||
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
|
||||
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed
|
||||
for (byte x=0; x < CONTROLLER_MAX; x++)
|
||||
Settings.TaskDeviceSendData[x][infoReply.destTaskIndex] = false;
|
||||
strcpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy( ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x]);
|
||||
SaveTaskSettings(infoReply.destTaskIndex);
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: // sensor data pull request
|
||||
{
|
||||
SendUDPTaskData(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: // sensor data
|
||||
{
|
||||
if (Settings.GlobalSync)
|
||||
{
|
||||
struct dataStruct dataReply;
|
||||
memcpy((byte*)&dataReply, (byte*)&packetBuffer, sizeof(dataStruct));
|
||||
|
||||
// only if this task has a remote feed, update values
|
||||
if (Settings.TaskDeviceDataFeed[dataReply.destTaskIndex] != 0)
|
||||
{
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
{
|
||||
UserVar[dataReply.destTaskIndex * VARS_PER_TASK + x] = dataReply.Values[x];
|
||||
}
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(dataReply.destTaskIndex);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
struct EventStruct TempEvent;
|
||||
TempEvent.Data = (byte*)packetBuffer;
|
||||
TempEvent.Par1 = remoteIP[3];
|
||||
PluginCall(PLUGIN_UDP_IN, &TempEvent, dummyString);
|
||||
CPluginCall(CPLUGIN_UDP_IN, &TempEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -223,79 +138,12 @@ void checkUDP()
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send task info using UDP message
|
||||
\*********************************************************************************************/
|
||||
void SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
return;
|
||||
}
|
||||
struct infoStruct infoReply;
|
||||
infoReply.sourcelUnit = Settings.Unit;
|
||||
infoReply.sourceTaskIndex = sourceTaskIndex;
|
||||
infoReply.destTaskIndex = destTaskIndex;
|
||||
LoadTaskSettings(infoReply.sourceTaskIndex);
|
||||
infoReply.deviceNumber = Settings.TaskDeviceNumber[infoReply.sourceTaskIndex];
|
||||
strcpy(infoReply.taskName, ExtraTaskSettings.TaskDeviceName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x]);
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
infoReply.destUnit = x;
|
||||
sendUDP(x, (byte*)&infoReply, sizeof(infoStruct));
|
||||
delay(10);
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send task data using UDP message
|
||||
\*********************************************************************************************/
|
||||
void SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
return;
|
||||
}
|
||||
struct dataStruct dataReply;
|
||||
dataReply.sourcelUnit = Settings.Unit;
|
||||
dataReply.sourceTaskIndex = sourceTaskIndex;
|
||||
dataReply.destTaskIndex = destTaskIndex;
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
dataReply.Values[x] = UserVar[dataReply.sourceTaskIndex * VARS_PER_TASK + x];
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
dataReply.destUnit = x;
|
||||
sendUDP(x, (byte*) &dataReply, sizeof(dataStruct));
|
||||
delay(10);
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send event using UDP message
|
||||
\*********************************************************************************************/
|
||||
void SendUDPCommand(byte destUnit, char* data, byte dataLength)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
byte firstUnit = 1;
|
||||
@@ -319,7 +167,7 @@ void SendUDPCommand(byte destUnit, char* data, byte dataLength)
|
||||
\*********************************************************************************************/
|
||||
void sendUDP(byte unit, byte* data, byte size)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
if (unit != 255)
|
||||
@@ -365,7 +213,7 @@ void refreshNodeList()
|
||||
void sendSysInfoUDP(byte repeats)
|
||||
{
|
||||
char log[80];
|
||||
if (Settings.UDPPort == 0 || WiFi.status() != WL_CONNECTED)
|
||||
if (Settings.UDPPort == 0 || !WiFiConnected(100))
|
||||
return;
|
||||
|
||||
// TODO: make a nice struct of it and clean up
|
||||
@@ -425,7 +273,7 @@ void sendSysInfoUDP(byte repeats)
|
||||
Respond to HTTP XML requests for SSDP information
|
||||
\*********************************************************************************************/
|
||||
void SSDP_schema(WiFiClient &client) {
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -737,6 +585,54 @@ void SSDP_update() {
|
||||
while (_server->next())
|
||||
_server->flush();
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check WiFi connection. Maximum timeout 500 msec.
|
||||
bool WiFiConnected(uint32_t timeout_ms) {
|
||||
uint32_t timer = millis() + (timeout_ms > 500 ? 500 : timeout_ms);
|
||||
uint32_t min_delay = timeout_ms / 20;
|
||||
if (min_delay < 10) {
|
||||
yield(); // Allow at least once time for backgroundtasks
|
||||
min_delay = 10;
|
||||
}
|
||||
// Apparently something needs network, perform check to see if it is ready now.
|
||||
// if (!tryConnectWiFi())
|
||||
// return false;
|
||||
while (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
if (timeOutReached(timer)) {
|
||||
return false;
|
||||
}
|
||||
delay(min_delay); // Allow the backgroundtasks to continue procesing.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hostReachable(const IPAddress& ip) {
|
||||
// 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 += formatIP(ip);
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hostReachable(const String& hostname) {
|
||||
IPAddress remote_addr;
|
||||
if (WiFi.hostByName(hostname.c_str(), remote_addr))
|
||||
return hostReachable(remote_addr);
|
||||
String log = F("Hostname cannot be resolved: ");
|
||||
log += hostname;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
#define WiFi_Logo_width 60
|
||||
#define WiFi_Logo_height 36
|
||||
const char WiFi_Logo_bits[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
|
||||
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x83, 0x01, 0x80, 0xFF, 0xFF, 0xFF,
|
||||
0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00,
|
||||
0xC0, 0xFF, 0xFF, 0x7C, 0x00, 0x60, 0x0C, 0x00, 0xC0, 0x31, 0x46, 0x7C,
|
||||
0xFC, 0x77, 0x08, 0x00, 0xE0, 0x23, 0xC6, 0x3C, 0xFC, 0x67, 0x18, 0x00,
|
||||
0xE0, 0x23, 0xE4, 0x3F, 0x1C, 0x00, 0x18, 0x00, 0xE0, 0x23, 0x60, 0x3C,
|
||||
0x1C, 0x70, 0x18, 0x00, 0xE0, 0x03, 0x60, 0x3C, 0x1C, 0x70, 0x18, 0x00,
|
||||
0xE0, 0x07, 0x60, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C,
|
||||
0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00,
|
||||
0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x8F, 0x71, 0x3C,
|
||||
0x1C, 0x70, 0x18, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x08, 0x00,
|
||||
0xC0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x1F,
|
||||
0x00, 0x00, 0x06, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x07, 0x00,
|
||||
0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF,
|
||||
0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
|
||||
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const char activeSymbole[] PROGMEM = {
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00011000,
|
||||
B00100100,
|
||||
B01000010,
|
||||
B01000010,
|
||||
B00100100,
|
||||
B00011000
|
||||
};
|
||||
|
||||
const char inactiveSymbole[] PROGMEM = {
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00011000,
|
||||
B00011000,
|
||||
B00000000,
|
||||
B00000000
|
||||
};
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
#define WiFi_Logo_width 60
|
||||
#define WiFi_Logo_height 36
|
||||
const char WiFi_Logo_bits[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
|
||||
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x83, 0x01, 0x80, 0xFF, 0xFF, 0xFF,
|
||||
0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00,
|
||||
0xC0, 0xFF, 0xFF, 0x7C, 0x00, 0x60, 0x0C, 0x00, 0xC0, 0x31, 0x46, 0x7C,
|
||||
0xFC, 0x77, 0x08, 0x00, 0xE0, 0x23, 0xC6, 0x3C, 0xFC, 0x67, 0x18, 0x00,
|
||||
0xE0, 0x23, 0xE4, 0x3F, 0x1C, 0x00, 0x18, 0x00, 0xE0, 0x23, 0x60, 0x3C,
|
||||
0x1C, 0x70, 0x18, 0x00, 0xE0, 0x03, 0x60, 0x3C, 0x1C, 0x70, 0x18, 0x00,
|
||||
0xE0, 0x07, 0x60, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C,
|
||||
0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00,
|
||||
0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x8F, 0x71, 0x3C,
|
||||
0x1C, 0x70, 0x18, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x08, 0x00,
|
||||
0xC0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x1F,
|
||||
0x00, 0x00, 0x06, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x07, 0x00,
|
||||
0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF,
|
||||
0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
|
||||
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const char activeSymbole[] PROGMEM = {
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00011000,
|
||||
B00100100,
|
||||
B01000010,
|
||||
B01000010,
|
||||
B00100100,
|
||||
B00011000
|
||||
};
|
||||
|
||||
const char inactiveSymbole[] PROGMEM = {
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00000000,
|
||||
B00011000,
|
||||
B00011000,
|
||||
B00000000,
|
||||
B00000000
|
||||
};
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
/********************************************************************************************\
|
||||
Convert a char string to integer
|
||||
\*********************************************************************************************/
|
||||
//FIXME: change original code so it uses String and String.toInt()
|
||||
unsigned long str2int(char *string)
|
||||
{
|
||||
unsigned long temp = atof(string);
|
||||
return temp;
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
Check if valid float and convert string to float.
|
||||
\*********************************************************************************************/
|
||||
bool string2float(const String& string, float& floatvalue) {
|
||||
if (!isFloat(string)) return false;
|
||||
floatvalue = atof(string.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Convert a char string to IP byte array
|
||||
\*********************************************************************************************/
|
||||
boolean str2ip(const String& string, byte* IP) {
|
||||
return str2ip(string.c_str(), IP);
|
||||
}
|
||||
|
||||
boolean str2ip(const char *string, byte* IP)
|
||||
{
|
||||
IPAddress tmpip; // Default constructor => set to 0.0.0.0
|
||||
if (*string == 0 || tmpip.fromString(string)) {
|
||||
// Eiher empty string or a valid IP addres, so copy value.
|
||||
for (byte i = 0; i < 4; ++i)
|
||||
IP[i] = tmpip[i];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call this by first declaring a char array of size 20, like:
|
||||
// char strIP[20];
|
||||
// formatIP(ip, strIP);
|
||||
void formatIP(const IPAddress& ip, char (&strIP)[20]) {
|
||||
sprintf_P(strIP, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
}
|
||||
|
||||
String formatIP(const IPAddress& ip) {
|
||||
char strIP[20];
|
||||
formatIP(ip, strIP);
|
||||
return String(strIP);
|
||||
}
|
||||
|
||||
void formatMAC(const uint8_t* mac, char (&strMAC)[20]) {
|
||||
sprintf_P(strMAC, PSTR("%02X:%02X:%02X:%02X:%02X:%02X"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Workaround for removing trailing white space when String() converts a float with 0 decimals
|
||||
\*********************************************************************************************/
|
||||
String toString(float value, byte decimals)
|
||||
{
|
||||
String sValue = String(value, decimals);
|
||||
sValue.trim();
|
||||
return sValue;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Format a value to the set number of decimals
|
||||
\*********************************************************************************************/
|
||||
String formatUserVar(struct EventStruct *event, byte rel_index)
|
||||
{
|
||||
float f(UserVar[event->BaseVarIndex + rel_index]);
|
||||
if (!isValidFloat(f)) {
|
||||
String log = F("Invalid float value for TaskIndex: ");
|
||||
log += event->TaskIndex;
|
||||
log += F(" varnumber: ");
|
||||
log += rel_index;
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
f = 0;
|
||||
}
|
||||
return toString(f, ExtraTaskSettings.TaskDeviceValueDecimals[rel_index]);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Wrap a string with given pre- and postfix string.
|
||||
\*********************************************************************************************/
|
||||
String wrap_String(const String& string, const String& wrap) {
|
||||
String result;
|
||||
result.reserve(string.length() + 2* wrap.length());
|
||||
result = wrap;
|
||||
result += string;
|
||||
result += wrap;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Format an object value pair for use in JSON.
|
||||
\*********************************************************************************************/
|
||||
String to_json_object_value(const String& object, const String& value) {
|
||||
String result;
|
||||
result.reserve(object.length() + value.length() + 6);
|
||||
result = wrap_String(object, F("\""));
|
||||
result += F(":");
|
||||
if (value.length() == 0 || !isFloat(value)) {
|
||||
result += wrap_String(value, F("\""));
|
||||
} else {
|
||||
result += value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Parse a string and get the xth command or parameter
|
||||
\*********************************************************************************************/
|
||||
String parseString(String& string, byte indexFind)
|
||||
{
|
||||
String tmpString = string;
|
||||
tmpString += ",";
|
||||
tmpString.replace(" ", ",");
|
||||
String locateString = "";
|
||||
byte count = 0;
|
||||
int index = tmpString.indexOf(',');
|
||||
while (index > 0)
|
||||
{
|
||||
count++;
|
||||
locateString = tmpString.substring(0, index);
|
||||
tmpString = tmpString.substring(index + 1);
|
||||
index = tmpString.indexOf(',');
|
||||
if (count == indexFind)
|
||||
{
|
||||
locateString.toLowerCase();
|
||||
return locateString;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
Parse a string and get the xth command or parameter
|
||||
\*********************************************************************************************/
|
||||
int getParamStartPos(String& string, byte indexFind)
|
||||
{
|
||||
String tmpString = string;
|
||||
byte count = 0;
|
||||
tmpString.replace(" ", ",");
|
||||
for (unsigned int x = 0; x < tmpString.length(); x++)
|
||||
{
|
||||
if (tmpString.charAt(x) == ',')
|
||||
{
|
||||
count++;
|
||||
if (count == (indexFind - 1))
|
||||
return x + 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//escapes special characters in strings for use in html-forms
|
||||
void htmlEscape(String & html)
|
||||
{
|
||||
html.replace("&", "&");
|
||||
html.replace("\"", """);
|
||||
html.replace("'", "'");
|
||||
html.replace("<", "<");
|
||||
html.replace(">", ">");
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
replace other system variables like %sysname%, %systime%, %ip%
|
||||
\*********************************************************************************************/
|
||||
void parseControllerVariables(String& s, struct EventStruct *event, boolean useURLencode) {
|
||||
parseSystemVariables(s, useURLencode);
|
||||
parseEventVariables(s, event, useURLencode);
|
||||
parseStandardConversions(s, useURLencode);
|
||||
}
|
||||
|
||||
|
||||
void repl(const String& key, const String& val, String& s, boolean useURLencode)
|
||||
{
|
||||
if (useURLencode) {
|
||||
s.replace(key, URLEncode(val.c_str()));
|
||||
} else {
|
||||
s.replace(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
void parseSpecialCharacters(String& s, boolean useURLencode)
|
||||
{
|
||||
bool no_accolades = s.indexOf('{') == -1 || s.indexOf('}') == -1;
|
||||
bool no_html_entity = s.indexOf('&') == -1 || s.indexOf(';') == -1;
|
||||
if (no_accolades && no_html_entity)
|
||||
return; // Nothing to replace
|
||||
|
||||
{
|
||||
// Degree
|
||||
const char degree[3] = {0xc2, 0xb0, 0}; // Unicode degree symbol
|
||||
const char degreeC[4] = {0xe2, 0x84, 0x83, 0}; // Unicode degreeC symbol
|
||||
const char degree_C[4] = {0xc2, 0xb0, 'C', 0}; // Unicode degree symbol + captial C
|
||||
repl(F("{D}"), degree, s, useURLencode);
|
||||
repl(F("°"), degree, s, useURLencode);
|
||||
repl(degreeC, degree_C, s, useURLencode);
|
||||
}
|
||||
{
|
||||
// Angle quotes
|
||||
const char laquo[3] = {0xc2, 0xab, 0}; // Unicode left angle quotes symbol
|
||||
const char raquo[3] = {0xc2, 0xbb, 0}; // Unicode right angle quotes symbol
|
||||
repl(F("{<<}"), laquo, s, useURLencode);
|
||||
repl(F("«"), laquo, s, useURLencode);
|
||||
repl(F("{>>}"), raquo, s, useURLencode);
|
||||
repl(F("»"), raquo, s, useURLencode);
|
||||
}
|
||||
{
|
||||
// Greek letter Mu
|
||||
const char mu[3] = {0xc2, 0xb5, 0}; // Unicode greek letter mu
|
||||
repl(F("{u}"), mu, s, useURLencode);
|
||||
repl(F("µ"), mu, s, useURLencode);
|
||||
}
|
||||
{
|
||||
// Currency
|
||||
const char euro[4] = {0xe2, 0x82, 0xac, 0}; // Unicode euro symbol
|
||||
const char yen[3] = {0xc2, 0xa5, 0}; // Unicode yen symbol
|
||||
const char pound[3] = {0xc2, 0xa3, 0}; // Unicode pound symbol
|
||||
const char cent[3] = {0xc2, 0xa2, 0}; // Unicode cent symbol
|
||||
repl(F("{E}"), euro, s, useURLencode);
|
||||
repl(F("€"), euro, s, useURLencode);
|
||||
repl(F("{Y}"), yen, s, useURLencode);
|
||||
repl(F("¥"), yen, s, useURLencode);
|
||||
repl(F("{P}"), pound, s, useURLencode);
|
||||
repl(F("£"), pound, s, useURLencode);
|
||||
repl(F("{c}"), cent, s, useURLencode);
|
||||
repl(F("¢"), cent, s, useURLencode);
|
||||
}
|
||||
{
|
||||
// Math symbols
|
||||
const char sup1[3] = {0xc2, 0xb9, 0}; // Unicode sup1 symbol
|
||||
const char sup2[3] = {0xc2, 0xb2, 0}; // Unicode sup2 symbol
|
||||
const char sup3[3] = {0xc2, 0xb3, 0}; // Unicode sup3 symbol
|
||||
const char frac14[3] = {0xc2, 0xbc, 0}; // Unicode frac14 symbol
|
||||
const char frac12[3] = {0xc2, 0xbd, 0}; // Unicode frac12 symbol
|
||||
const char frac34[3] = {0xc2, 0xbe, 0}; // Unicode frac34 symbol
|
||||
const char plusmn[3] = {0xc2, 0xb1, 0}; // Unicode plusmn symbol
|
||||
const char times[3] = {0xc3, 0x97, 0}; // Unicode times symbol
|
||||
const char divide[3] = {0xc3, 0xb7, 0}; // Unicode divide symbol
|
||||
repl(F("{^1}"), sup1, s, useURLencode);
|
||||
repl(F("¹"), sup1, s, useURLencode);
|
||||
repl(F("{^2}"), sup2, s, useURLencode);
|
||||
repl(F("²"), sup2, s, useURLencode);
|
||||
repl(F("{^3}"), sup3, s, useURLencode);
|
||||
repl(F("³"), sup3, s, useURLencode);
|
||||
repl(F("{1_4}"), frac14, s, useURLencode);
|
||||
repl(F("¼"), frac14, s, useURLencode);
|
||||
repl(F("{1_2}"), frac12, s, useURLencode);
|
||||
repl(F("½"), frac12, s, useURLencode);
|
||||
repl(F("{3_4}"), frac34, s, useURLencode);
|
||||
repl(F("¾"), frac34, s, useURLencode);
|
||||
repl(F("{+-}"), plusmn, s, useURLencode);
|
||||
repl(F("±"), plusmn, s, useURLencode);
|
||||
repl(F("{x}"), times, s, useURLencode);
|
||||
repl(F("×"), times, s, useURLencode);
|
||||
repl(F("{..}"), divide, s, useURLencode);
|
||||
repl(F("÷"), divide, s, useURLencode);
|
||||
}
|
||||
}
|
||||
|
||||
// Simple macro to create the replacement string only when needed.
|
||||
#define SMART_REPL(T,S) if (s.indexOf(T) != -1) { repl((T), (S), s, useURLencode);}
|
||||
void parseSystemVariables(String& s, boolean useURLencode)
|
||||
{
|
||||
parseSpecialCharacters(s, useURLencode);
|
||||
if (s.indexOf('%') == -1)
|
||||
return; // Nothing to replace
|
||||
|
||||
#if FEATURE_ADC_VCC
|
||||
repl(F("%vcc%"), String(vcc), s, useURLencode);
|
||||
#endif
|
||||
repl(F("%CR%"), F("\r"), s, useURLencode);
|
||||
repl(F("%LF%"), F("\n"), s, useURLencode);
|
||||
SMART_REPL(F("%ip%"),WiFi.localIP().toString())
|
||||
SMART_REPL(F("%rssi%"), String((wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? 0 : WiFi.RSSI()))
|
||||
SMART_REPL(F("%ssid%"), (wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? F("--") : WiFi.SSID())
|
||||
SMART_REPL(F("%unit%"), String(Settings.Unit))
|
||||
SMART_REPL(F("%mac%"), String(WiFi.macAddress()))
|
||||
#if defined(ESP8266)
|
||||
SMART_REPL(F("%mac_int%"), String(ESP.getChipId())) // Last 24 bit of MAC address as integer, to be used in rules.
|
||||
#endif
|
||||
|
||||
if (s.indexOf(F("%sys")) != -1) {
|
||||
SMART_REPL(F("%sysload%"), String(100 - (100 * loopCounterLast / loopCounterMax)))
|
||||
SMART_REPL(F("%systm_hm%"), getTimeString(':', false))
|
||||
SMART_REPL(F("%systm_hm_am%"), getTimeString_ampm(':', false))
|
||||
SMART_REPL(F("%systime%"), getTimeString(':'))
|
||||
SMART_REPL(F("%systime_am%"), getTimeString_ampm(':'))
|
||||
repl(F("%sysname%"), Settings.Name, s, useURLencode);
|
||||
|
||||
// valueString is being used by the macro.
|
||||
char valueString[5];
|
||||
#define SMART_REPL_TIME(T,F,V) if (s.indexOf(T) != -1) { sprintf_P(valueString, (F), (V)); repl((T),valueString, s, useURLencode);}
|
||||
SMART_REPL_TIME(F("%syshour%"), PSTR("%02d"), hour())
|
||||
SMART_REPL_TIME(F("%sysmin%"), PSTR("%02d"), minute())
|
||||
SMART_REPL_TIME(F("%syssec%"),PSTR("%02d"), second())
|
||||
SMART_REPL_TIME(F("%sysday%"), PSTR("%02d"), day())
|
||||
SMART_REPL_TIME(F("%sysmonth%"),PSTR("%02d"), month())
|
||||
SMART_REPL_TIME(F("%sysyear%"), PSTR("%04d"), year())
|
||||
SMART_REPL_TIME(F("%sysyears%"),PSTR("%02d"), year()%100)
|
||||
SMART_REPL(F("%sysweekday%"), String(weekday()))
|
||||
SMART_REPL(F("%sysweekday_s%"), weekday_str())
|
||||
#undef SMART_REPL_TIME
|
||||
}
|
||||
SMART_REPL(F("%lcltime%"), getDateTimeString('-',':',' '))
|
||||
SMART_REPL(F("%lcltime_am%"), getDateTimeString_ampm('-',':',' '))
|
||||
SMART_REPL(F("%uptime%"), String(wdcounter / 2))
|
||||
SMART_REPL(F("%unixtime%"), String(getUnixTime()))
|
||||
|
||||
repl(F("%tskname%"), ExtraTaskSettings.TaskDeviceName, s, useURLencode);
|
||||
if (s.indexOf("%vname") != -1) {
|
||||
repl(F("%vname1%"), ExtraTaskSettings.TaskDeviceValueNames[0], s, useURLencode);
|
||||
repl(F("%vname2%"), ExtraTaskSettings.TaskDeviceValueNames[1], s, useURLencode);
|
||||
repl(F("%vname3%"), ExtraTaskSettings.TaskDeviceValueNames[2], s, useURLencode);
|
||||
repl(F("%vname4%"), ExtraTaskSettings.TaskDeviceValueNames[3], s, useURLencode);
|
||||
}
|
||||
}
|
||||
|
||||
void parseEventVariables(String& s, struct EventStruct *event, boolean useURLencode)
|
||||
{
|
||||
SMART_REPL(F("%id%"), String(event->idx))
|
||||
if (s.indexOf("%val") != -1) {
|
||||
if (event->sensorType == SENSOR_TYPE_LONG) {
|
||||
SMART_REPL(F("%val1%"), String((unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)))
|
||||
} else {
|
||||
SMART_REPL(F("%val1%"), formatUserVar(event, 0))
|
||||
SMART_REPL(F("%val2%"), formatUserVar(event, 1))
|
||||
SMART_REPL(F("%val3%"), formatUserVar(event, 2))
|
||||
SMART_REPL(F("%val4%"), formatUserVar(event, 3))
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef SMART_REPL
|
||||
|
||||
bool getConvertArgument(const String& marker, const String& s, float& argument, int& startIndex, int& endIndex) {
|
||||
startIndex = s.indexOf(marker);
|
||||
if (startIndex == -1) return false;
|
||||
|
||||
int startIndexArgument = startIndex + marker.length();
|
||||
if (s.charAt(startIndexArgument) != '(') {
|
||||
return false;
|
||||
}
|
||||
++startIndexArgument;
|
||||
endIndex = s.indexOf(')', startIndexArgument);
|
||||
if (endIndex == -1) return false;
|
||||
|
||||
String argumentString = s.substring(startIndexArgument, endIndex);
|
||||
if (argumentString.length() == 0 || !isFloat(argumentString)) return false;
|
||||
|
||||
argument = argumentString.toFloat();
|
||||
++endIndex; // Must also strip ')' from the original string.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse conversions marked with "%conv_marker%(float)"
|
||||
// Must be called last, since all sensor values must be converted, processed, etc.
|
||||
void parseStandardConversions(String& s, boolean useURLencode) {
|
||||
if (s.indexOf(F("%c_")) == -1)
|
||||
return; // Nothing to replace
|
||||
|
||||
float arg = 0.0;
|
||||
int startIndex = 0;
|
||||
int endIndex = 0;
|
||||
// These replacements should be done in a while loop per marker,
|
||||
// since they also replace the numerical parameter.
|
||||
// The marker may occur more than once per string, but with different parameters.
|
||||
#define SMART_CONV(T,FUN) while (getConvertArgument((T), s, arg, startIndex, endIndex)) { repl(s.substring(startIndex, endIndex), (FUN), s, useURLencode); }
|
||||
SMART_CONV(F("%c_w_dir%"), getBearing(arg))
|
||||
SMART_CONV(F("%c_c2f%"), toString(CelsiusToFahrenheit(arg), 1))
|
||||
SMART_CONV(F("%c_ms2Bft%"), String(m_secToBeaufort(arg)))
|
||||
SMART_CONV(F("%c_cm2imp%"), centimeterToImperialLength(arg))
|
||||
SMART_CONV(F("%c_mm2imp%"), millimeterToImperialLength(arg))
|
||||
SMART_CONV(F("%c_m2day%"), toString(minutesToDay(arg), 2))
|
||||
SMART_CONV(F("%c_m2dh%"), minutesToDayHour(arg))
|
||||
SMART_CONV(F("%c_m2dhm%"), minutesToDayHourMinute(arg))
|
||||
SMART_CONV(F("%c_s2dhms%"), secondsToDayHourMinuteSecond(arg))
|
||||
#undef SMART_CONV
|
||||
}
|
||||
@@ -0,0 +1,567 @@
|
||||
|
||||
/********************************************************************************************\
|
||||
Time stuff
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define SECS_PER_MIN (60UL)
|
||||
#define SECS_PER_HOUR (3600UL)
|
||||
#define SECS_PER_DAY (SECS_PER_HOUR * 24UL)
|
||||
#define DAYS_PER_WEEK (7UL)
|
||||
#define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK)
|
||||
#define SECS_PER_YEAR (SECS_PER_WEEK * 52UL)
|
||||
#define SECS_YR_2000 (946684800UL) // the time at the start of y2k
|
||||
#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) )
|
||||
|
||||
timeStruct tm;
|
||||
uint32_t syncInterval = 3600; // time sync will be attempted after this many seconds
|
||||
uint32_t sysTime = 0;
|
||||
uint32_t prevMillis = 0;
|
||||
uint32_t nextSyncTime = 0;
|
||||
|
||||
byte PrevMinutes = 0;
|
||||
|
||||
void breakTime(unsigned long timeInput, struct timeStruct &tm) {
|
||||
uint8_t year;
|
||||
uint8_t month, monthLength;
|
||||
uint32_t time;
|
||||
unsigned long days;
|
||||
const uint8_t monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
time = (uint32_t)timeInput;
|
||||
tm.Second = time % 60;
|
||||
time /= 60; // now it is minutes
|
||||
tm.Minute = time % 60;
|
||||
time /= 60; // now it is hours
|
||||
tm.Hour = time % 24;
|
||||
time /= 24; // now it is days
|
||||
tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1
|
||||
|
||||
year = 0;
|
||||
days = 0;
|
||||
while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) {
|
||||
year++;
|
||||
}
|
||||
tm.Year = year; // year is offset from 1970
|
||||
|
||||
days -= LEAP_YEAR(year) ? 366 : 365;
|
||||
time -= days; // now it is days in this year, starting at 0
|
||||
|
||||
days = 0;
|
||||
month = 0;
|
||||
monthLength = 0;
|
||||
for (month = 0; month < 12; month++) {
|
||||
if (month == 1) { // february
|
||||
if (LEAP_YEAR(year)) {
|
||||
monthLength = 29;
|
||||
} else {
|
||||
monthLength = 28;
|
||||
}
|
||||
} else {
|
||||
monthLength = monthDays[month];
|
||||
}
|
||||
|
||||
if (time >= monthLength) {
|
||||
time -= monthLength;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tm.Month = month + 1; // jan is month 1
|
||||
tm.Day = time + 1; // day of month
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
static bool firstUpdate = true;
|
||||
String event = firstUpdate ? F("Time#Initialized") : F("Time#Set");
|
||||
firstUpdate = false;
|
||||
rulesProcessing(event);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getUnixTime() {
|
||||
return sysTime;
|
||||
}
|
||||
|
||||
unsigned long now() {
|
||||
// calculate number of seconds passed since last call to now()
|
||||
const long msec_passed = timePassedSince(prevMillis);
|
||||
const long seconds_passed = msec_passed / 1000;
|
||||
sysTime += seconds_passed;
|
||||
prevMillis += seconds_passed * 1000;
|
||||
if (nextSyncTime <= sysTime) {
|
||||
// nextSyncTime & sysTime are in seconds
|
||||
unsigned long t = getNtpTime();
|
||||
if (t != 0) {
|
||||
setTime(t);
|
||||
}
|
||||
}
|
||||
uint32_t localSystime = toLocal(sysTime);
|
||||
breakTime(localSystime, tm);
|
||||
return (unsigned long)localSystime;
|
||||
}
|
||||
|
||||
int year(unsigned long t) {
|
||||
timeStruct tmp;
|
||||
breakTime(t, tmp);
|
||||
return 1970 + tmp.Year;
|
||||
}
|
||||
|
||||
int weekday(unsigned long t) {
|
||||
timeStruct tmp;
|
||||
breakTime(t, tmp);
|
||||
return tmp.Wday;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int year()
|
||||
{
|
||||
return 1970 + tm.Year;
|
||||
}
|
||||
|
||||
byte month()
|
||||
{
|
||||
return tm.Month;
|
||||
}
|
||||
|
||||
byte day()
|
||||
{
|
||||
return tm.Day;
|
||||
}
|
||||
|
||||
byte hour()
|
||||
{
|
||||
return tm.Hour;
|
||||
}
|
||||
|
||||
byte minute()
|
||||
{
|
||||
return tm.Minute;
|
||||
}
|
||||
|
||||
byte second()
|
||||
{
|
||||
return tm.Second;
|
||||
}
|
||||
|
||||
// day of week, sunday is day 1
|
||||
int weekday()
|
||||
{
|
||||
return tm.Wday;
|
||||
}
|
||||
|
||||
String weekday_str()
|
||||
{
|
||||
const int wday(weekday() - 1); // here: Count from Sunday = 0
|
||||
const String weekDays = F("SunMonTueWedThuFriSat");
|
||||
return weekDays.substring(wday * 3, wday * 3 + 3);
|
||||
}
|
||||
|
||||
void initTime()
|
||||
{
|
||||
nextSyncTime = 0;
|
||||
now();
|
||||
}
|
||||
|
||||
void checkTime()
|
||||
{
|
||||
now();
|
||||
if (tm.Minute != PrevMinutes)
|
||||
{
|
||||
PluginCall(PLUGIN_CLOCK_IN, 0, dummyString);
|
||||
PrevMinutes = tm.Minute;
|
||||
if (Settings.UseRules)
|
||||
{
|
||||
String event;
|
||||
event.reserve(21);
|
||||
event = F("Clock#Time=");
|
||||
event += weekday_str();
|
||||
event += ",";
|
||||
if (hour() < 10)
|
||||
event += "0";
|
||||
event += hour();
|
||||
event += ":";
|
||||
if (minute() < 10)
|
||||
event += "0";
|
||||
event += minute();
|
||||
rulesProcessing(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned long getNtpTime()
|
||||
{
|
||||
if (!Settings.UseNTP || !WiFiConnected(10)) {
|
||||
return 0;
|
||||
}
|
||||
IPAddress timeServerIP;
|
||||
String log = F("NTP : NTP send to ");
|
||||
if (Settings.NTPHost[0] != 0) {
|
||||
WiFi.hostByName(Settings.NTPHost, 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)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
WiFiUDP udp;
|
||||
udp.begin(123);
|
||||
|
||||
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
|
||||
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
|
||||
|
||||
log += F(" (");
|
||||
log += timeServerIP.toString();
|
||||
log += F(")");
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
while (udp.parsePacket() > 0) ; // discard any previously received packets
|
||||
|
||||
memset(packetBuffer, 0, NTP_PACKET_SIZE);
|
||||
packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
packetBuffer[1] = 0; // Stratum, or type of clock
|
||||
packetBuffer[2] = 6; // Polling Interval
|
||||
packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
packetBuffer[12] = 49;
|
||||
packetBuffer[13] = 0x4E;
|
||||
packetBuffer[14] = 49;
|
||||
packetBuffer[15] = 52;
|
||||
udp.beginPacket(timeServerIP, 123); //NTP requests are to port 123
|
||||
udp.write(packetBuffer, NTP_PACKET_SIZE);
|
||||
udp.endPacket();
|
||||
|
||||
uint32_t beginWait = millis();
|
||||
while (!timeOutReached(beginWait + 1000)) {
|
||||
int size = udp.parsePacket();
|
||||
if (size >= NTP_PACKET_SIZE) {
|
||||
udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
|
||||
unsigned long secsSince1900;
|
||||
// convert four bytes starting at location 40 to a long integer
|
||||
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
|
||||
secsSince1900 |= (unsigned long)packetBuffer[43];
|
||||
log = F("NTP : NTP replied: ");
|
||||
log += timePassedSince(beginWait);
|
||||
log += F(" mSec");
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
return secsSince1900 - 2208988800UL;
|
||||
}
|
||||
delay(10);
|
||||
}
|
||||
log = F("NTP : No reply");
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Unsigned long Timer timeOut check
|
||||
\*********************************************************************************************/
|
||||
|
||||
// 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 signed_diff = 0;
|
||||
// To cast a value to a signed long, the difference may not exceed half the ULONG_MAX
|
||||
const unsigned long half_max_unsigned_long = 2147483647u; // = 2^31 -1
|
||||
if (next >= prev) {
|
||||
const unsigned long diff = next - prev;
|
||||
if (diff <= half_max_unsigned_long) {
|
||||
// Normal situation, just return the difference.
|
||||
// Difference is a positive value.
|
||||
signed_diff = static_cast<long>(diff);
|
||||
} else {
|
||||
// prev has overflow, return a negative difference value
|
||||
signed_diff = static_cast<long>((ULONG_MAX - next) + prev + 1u);
|
||||
signed_diff = -1 * signed_diff;
|
||||
}
|
||||
} else {
|
||||
// next < prev
|
||||
const unsigned long diff = prev - next;
|
||||
if (diff <= half_max_unsigned_long) {
|
||||
// Normal situation, return a negative difference value
|
||||
signed_diff = static_cast<long>(diff);
|
||||
signed_diff = -1 * signed_diff;
|
||||
} else {
|
||||
// next has overflow, return a positive difference value
|
||||
signed_diff = static_cast<long>((ULONG_MAX - prev) + next + 1u);
|
||||
}
|
||||
}
|
||||
return signed_diff;
|
||||
}
|
||||
|
||||
// Compute the number of milliSeconds passed since timestamp given.
|
||||
// N.B. value can be negative if the timestamp has not yet been reached.
|
||||
long timePassedSince(unsigned long timestamp) {
|
||||
return timeDiff(timestamp, millis());
|
||||
}
|
||||
|
||||
// Check if a certain timeout has been reached.
|
||||
boolean timeOutReached(unsigned long timer)
|
||||
{
|
||||
const long passed = timePassedSince(timer);
|
||||
return passed >= 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
Convert a 32 bit integer into a string like "Sun,12:30"
|
||||
\*********************************************************************************************/
|
||||
String timeLong2String(unsigned long lngTime)
|
||||
{
|
||||
unsigned long x = 0;
|
||||
String time = "";
|
||||
|
||||
x = (lngTime >> 16) & 0xf;
|
||||
if (x == 0x0f)
|
||||
x = 0;
|
||||
String weekDays = F("AllSunMonTueWedThuFriSatWrkWkd");
|
||||
time = weekDays.substring(x * 3, x * 3 + 3);
|
||||
time += ",";
|
||||
|
||||
x = (lngTime >> 12) & 0xf;
|
||||
if (x == 0xf)
|
||||
time += "*";
|
||||
else if (x == 0xe)
|
||||
time += "-";
|
||||
else
|
||||
time += x;
|
||||
|
||||
x = (lngTime >> 8) & 0xf;
|
||||
if (x == 0xf)
|
||||
time += "*";
|
||||
else if (x == 0xe)
|
||||
time += "-";
|
||||
else
|
||||
time += x;
|
||||
|
||||
time += ":";
|
||||
|
||||
x = (lngTime >> 4) & 0xf;
|
||||
if (x == 0xf)
|
||||
time += "*";
|
||||
else if (x == 0xe)
|
||||
time += "-";
|
||||
else
|
||||
time += x;
|
||||
|
||||
x = (lngTime) & 0xf;
|
||||
if (x == 0xf)
|
||||
time += "*";
|
||||
else if (x == 0xe)
|
||||
time += "-";
|
||||
else
|
||||
time += x;
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
// returns the current Date separated by the given delimiter
|
||||
// date format example with '-' delimiter: 2016-12-31 (YYYY-MM-DD)
|
||||
String getDateString(const timeStruct& ts, char delimiter) {
|
||||
char DateString[20]; //19 digits plus the null char
|
||||
const int year = 1970 + ts.Year;
|
||||
sprintf_P(DateString, PSTR("%4d%c%02d%c%02d"), year, delimiter, ts.Month, delimiter, ts.Day);
|
||||
return DateString;
|
||||
}
|
||||
|
||||
String getDateString(char delimiter)
|
||||
{
|
||||
return getDateString(tm, delimiter);
|
||||
}
|
||||
|
||||
// returns the current Date without delimiter
|
||||
// date format example: 20161231 (YYYYMMDD)
|
||||
String getDateString()
|
||||
{
|
||||
return getDateString('\0');
|
||||
}
|
||||
|
||||
// returns the current Time separated by the given delimiter
|
||||
// time format example with ':' delimiter: 23:59:59 (HH:MM:SS)
|
||||
String getTimeString(const timeStruct& ts, char delimiter, bool am_pm, bool show_seconds)
|
||||
{
|
||||
char TimeString[20]; //19 digits plus the null char
|
||||
if (am_pm) {
|
||||
uint8_t hour(ts.Hour % 12);
|
||||
if (hour == 0) { hour = 12; }
|
||||
const char a_or_p = ts.Hour < 12 ? 'A' : 'P';
|
||||
if (show_seconds) {
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d%c%02d %cM"),
|
||||
hour, delimiter, ts.Minute, delimiter, ts.Second, a_or_p);
|
||||
} else {
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d %cM"),
|
||||
hour, delimiter, ts.Minute, a_or_p);
|
||||
}
|
||||
} else {
|
||||
if (show_seconds) {
|
||||
sprintf_P(TimeString, PSTR("%02d%c%02d%c%02d"),
|
||||
ts.Hour, delimiter, ts.Minute, delimiter, ts.Second);
|
||||
} else {
|
||||
sprintf_P(TimeString, PSTR("%d%c%02d"),
|
||||
ts.Hour, delimiter, ts.Minute);
|
||||
}
|
||||
}
|
||||
return TimeString;
|
||||
}
|
||||
|
||||
String getTimeString(char delimiter, bool show_seconds /*=true*/)
|
||||
{
|
||||
return getTimeString(tm, delimiter, false, show_seconds);
|
||||
}
|
||||
|
||||
String getTimeString_ampm(char delimiter, bool show_seconds /*=true*/)
|
||||
{
|
||||
return getTimeString(tm, delimiter, true, show_seconds);
|
||||
}
|
||||
|
||||
// returns the current Time without delimiter
|
||||
// time format example: 235959 (HHMMSS)
|
||||
String getTimeString()
|
||||
{
|
||||
return getTimeString('\0');
|
||||
}
|
||||
|
||||
String getTimeString_ampm()
|
||||
{
|
||||
return getTimeString_ampm('\0');
|
||||
}
|
||||
|
||||
// returns the current Date and Time separated by the given delimiter
|
||||
// if called like this: getDateTimeString('\0', '\0', '\0');
|
||||
// it will give back this: 20161231235959 (YYYYMMDDHHMMSS)
|
||||
String getDateTimeString(const timeStruct& ts, char dateDelimiter, char timeDelimiter, char dateTimeDelimiter, bool am_pm)
|
||||
{
|
||||
String ret = getDateString(ts, dateDelimiter);
|
||||
if (dateTimeDelimiter != '\0')
|
||||
ret += dateTimeDelimiter;
|
||||
ret += getTimeString(ts, timeDelimiter, am_pm, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
String getDateTimeString(char dateDelimiter, char timeDelimiter, char dateTimeDelimiter) {
|
||||
return getDateTimeString(tm, dateDelimiter, timeDelimiter, dateTimeDelimiter, false);
|
||||
}
|
||||
|
||||
String getDateTimeString_ampm(char dateDelimiter, char timeDelimiter, char dateTimeDelimiter) {
|
||||
return getDateTimeString(tm, dateDelimiter, timeDelimiter, dateTimeDelimiter, true);
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
Convert a string like "Sun,12:30" into a 32 bit integer
|
||||
\*********************************************************************************************/
|
||||
unsigned long string2TimeLong(const String &str)
|
||||
{
|
||||
// format 0000WWWWAAAABBBBCCCCDDDD
|
||||
// WWWW=weekday, AAAA=hours tens digit, BBBB=hours, CCCC=minutes tens digit DDDD=minutes
|
||||
|
||||
char command[20];
|
||||
char TmpStr1[10];
|
||||
int w, x, y;
|
||||
unsigned long a;
|
||||
{
|
||||
// Within a scope so the tmpString is only used for copy.
|
||||
String tmpString(str);
|
||||
tmpString.toLowerCase();
|
||||
tmpString.toCharArray(command, 20);
|
||||
}
|
||||
unsigned long lngTime = 0;
|
||||
|
||||
if (GetArgv(command, TmpStr1, 1))
|
||||
{
|
||||
String day = TmpStr1;
|
||||
String weekDays = F("allsunmontuewedthufrisatwrkwkd");
|
||||
y = weekDays.indexOf(TmpStr1) / 3;
|
||||
if (y == 0)
|
||||
y = 0xf; // wildcard is 0xf
|
||||
lngTime |= (unsigned long)y << 16;
|
||||
}
|
||||
|
||||
if (GetArgv(command, TmpStr1, 2))
|
||||
{
|
||||
y = 0;
|
||||
for (x = strlen(TmpStr1) - 1; x >= 0; x--)
|
||||
{
|
||||
w = TmpStr1[x];
|
||||
if ( (w >= '0' && w <= '9') || w == '*')
|
||||
{
|
||||
a = 0xffffffff ^ (0xfUL << y); // create mask to clean nibble position y
|
||||
lngTime &= a; // maak nibble leeg
|
||||
if (w == '*')
|
||||
lngTime |= (0xFUL << y); // fill nibble with wildcard value
|
||||
else
|
||||
lngTime |= (w - '0') << y; // fill nibble with token
|
||||
y += 4;
|
||||
}
|
||||
else
|
||||
if (w == ':');
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lngTime;
|
||||
}
|
||||
|
||||
/********************************************************************************************\
|
||||
Match clock event
|
||||
\*********************************************************************************************/
|
||||
boolean matchClockEvent(unsigned long clockEvent, unsigned long clockSet)
|
||||
{
|
||||
unsigned long Mask;
|
||||
for (byte y = 0; y < 8; y++)
|
||||
{
|
||||
if (((clockSet >> (y * 4)) & 0xf) == 0xf) // if nibble y has the wildcard value 0xf
|
||||
{
|
||||
Mask = 0xffffffff ^ (0xFUL << (y * 4)); // Mask to wipe nibble position y.
|
||||
clockEvent &= Mask; // clear nibble
|
||||
clockEvent |= (0xFUL << (y * 4)); // fill with wildcard value 0xf
|
||||
}
|
||||
}
|
||||
|
||||
if (((clockSet >> (16)) & 0xf) == 0x8) // if weekday nibble has the wildcard value 0x8 (workdays)
|
||||
if (weekday() >= 2 and weekday() <= 6) // and we have a working day today...
|
||||
{
|
||||
Mask = 0xffffffff ^ (0xFUL << (16)); // Mask to wipe nibble position.
|
||||
clockEvent &= Mask; // clear nibble
|
||||
clockEvent |= (0x8UL << (16)); // fill with wildcard value 0x8
|
||||
}
|
||||
|
||||
if (((clockSet >> (16)) & 0xf) == 0x9) // if weekday nibble has the wildcard value 0x9 (weekends)
|
||||
if (weekday() == 1 or weekday() == 7) // and we have a weekend day today...
|
||||
{
|
||||
Mask = 0xffffffff ^ (0xFUL << (16)); // Mask to wipe nibble position.
|
||||
clockEvent &= Mask; // clear nibble
|
||||
clockEvent |= (0x9UL << (16)); // fill with wildcard value 0x9
|
||||
}
|
||||
|
||||
if (clockEvent == clockSet)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
|
||||
/********************************************************************************************\
|
||||
Time zone
|
||||
\*********************************************************************************************/
|
||||
|
||||
// Borrowed code from Timezone: https://github.com/JChristensen/Timezon
|
||||
|
||||
TimeChangeRule m_dst; // rule for start of dst or summer time for any year
|
||||
TimeChangeRule m_std; // rule for start of standard time for any year
|
||||
uint32_t m_dstUTC = 0; // dst start for given/current year, given in UTC
|
||||
uint32_t m_stdUTC = 0; // std time start for given/current year, given in UTC
|
||||
uint32_t m_dstLoc = 0; // dst start for given/current year, given in local time
|
||||
uint32_t m_stdLoc = 0; // std time start for given/current year, given in local time
|
||||
|
||||
/*
|
||||
// Examples time zones
|
||||
// Australia Eastern Time Zone (Sydney, Melbourne)
|
||||
TimeChangeRule aEDT = {First, Sun, Oct, 2, 660}; // UTC + 11 hours
|
||||
TimeChangeRule aEST = {First, Sun, Apr, 3, 600}; // UTC + 10 hours
|
||||
setTimeZone(aEDT, aEST);
|
||||
|
||||
// Central European Time (Frankfurt, Paris)
|
||||
TimeChangeRule CEST = {Last, Sun, Mar, 2, 120}; // Central European Summer Time
|
||||
TimeChangeRule CET = {Last, Sun, Oct, 3, 60}; // Central European Standard Time
|
||||
setTimeZone(CEST, CET);
|
||||
|
||||
// United Kingdom (London, Belfast)
|
||||
TimeChangeRule BST = {Last, Sun, Mar, 1, 60}; // British Summer Time
|
||||
TimeChangeRule GMT = {Last, Sun, Oct, 2, 0}; // Standard Time
|
||||
setTimeZone(BST, GMT);
|
||||
|
||||
// UTC
|
||||
TimeChangeRule utcRule = {Last, Sun, Mar, 1, 0}; // UTC
|
||||
setTimeZone(utcRule, utcRule);
|
||||
|
||||
// US Eastern Time Zone (New York, Detroit)
|
||||
TimeChangeRule usEDT = {Second, Sun, Mar, 2, -240}; // Eastern Daylight Time = UTC - 4 hours
|
||||
TimeChangeRule usEST = {First, Sun, Nov, 2, -300}; // Eastern Standard Time = UTC - 5 hours
|
||||
setTimeZone(usEDT, usEST);
|
||||
|
||||
// US Central Time Zone (Chicago, Houston)
|
||||
TimeChangeRule usCDT = {Second, dowSunday, Mar, 2, -300};
|
||||
TimeChangeRule usCST = {First, dowSunday, Nov, 2, -360};
|
||||
setTimeZone(usCDT, usCST);
|
||||
|
||||
// US Mountain Time Zone (Denver, Salt Lake City)
|
||||
TimeChangeRule usMDT = {Second, dowSunday, Mar, 2, -360};
|
||||
TimeChangeRule usMST = {First, dowSunday, Nov, 2, -420};
|
||||
setTimeZone(usMDT, usMST);
|
||||
|
||||
// Arizona is US Mountain Time Zone but does not use DST
|
||||
setTimeZone(usMST, usMST);
|
||||
|
||||
// US Pacific Time Zone (Las Vegas, Los Angeles)
|
||||
TimeChangeRule usPDT = {Second, dowSunday, Mar, 2, -420};
|
||||
TimeChangeRule usPST = {First, dowSunday, Nov, 2, -480};
|
||||
setTimeZone(usPDT, usPST);
|
||||
*/
|
||||
|
||||
void getDefaultDst_flash_values(uint16_t& start, uint16_t& end) {
|
||||
// DST start: Last Sunday March 2am => 3am
|
||||
// DST end: Last Sunday October 3am => 2am
|
||||
TimeChangeRule CEST(Last, Sun, Mar, 2, Settings.TimeZone); // Summer Time
|
||||
TimeChangeRule CET(Last, Sun, Oct, 3, Settings.TimeZone); // Standard Time
|
||||
start = CEST.toFlashStoredValue();
|
||||
end = CET.toFlashStoredValue();
|
||||
}
|
||||
|
||||
void applyTimeZone(uint32_t curTime) {
|
||||
int dst_offset = Settings.DST ? 60 : 0;
|
||||
uint16_t tmpStart(Settings.DST_Start);
|
||||
uint16_t tmpEnd(Settings.DST_End);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
TimeChangeRule start(tmpStart, Settings.TimeZone + dst_offset); // Summer Time
|
||||
TimeChangeRule end(tmpEnd, Settings.TimeZone); // Standard Time
|
||||
if (start.isValid() && end.isValid()) {
|
||||
setTimeZone(start, end, curTime);
|
||||
return;
|
||||
}
|
||||
getDefaultDst_flash_values(tmpStart, tmpEnd);
|
||||
}
|
||||
}
|
||||
|
||||
void setTimeZone(const TimeChangeRule& dstStart, const TimeChangeRule& stdStart, uint32_t curTime) {
|
||||
m_dst = dstStart;
|
||||
m_std = stdStart;
|
||||
if (calcTimeChanges(year(curTime))) {
|
||||
logTimeZoneInfo();
|
||||
}
|
||||
}
|
||||
|
||||
void logTimeZoneInfo() {
|
||||
String log = F("Current Time Zone: ");
|
||||
if (m_std.offset != m_dst.offset) {
|
||||
// Summer time
|
||||
log += F(" DST time start: ");
|
||||
if (m_dstLoc != 0) {
|
||||
timeStruct tmp;
|
||||
breakTime(m_dstLoc, tmp);
|
||||
log += getDateTimeString(tmp, '-', ':', ' ', false);
|
||||
}
|
||||
log += F(" offset: ");
|
||||
log += m_dst.offset;
|
||||
log += F(" min");
|
||||
}
|
||||
// Standard/Winter time.
|
||||
log += F("STD time start: ");
|
||||
if (m_stdLoc != 0) {
|
||||
timeStruct tmp;
|
||||
breakTime(m_stdLoc, tmp);
|
||||
log += getDateTimeString(tmp, '-', ':', ' ', false);
|
||||
}
|
||||
log += F(" offset: ");
|
||||
log += m_std.offset;
|
||||
log += F(" min");
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
|
||||
uint32_t makeTime(const timeStruct &tm) {
|
||||
// assemble time elements into uint32_t
|
||||
// note year argument is offset from 1970 (see macros in time.h to convert to other formats)
|
||||
// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9
|
||||
const uint8_t monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
int i;
|
||||
uint32_t seconds;
|
||||
|
||||
// seconds from 1970 till 1 jan 00:00:00 of the given year
|
||||
seconds= tm.Year*(SECS_PER_DAY * 365);
|
||||
for (i = 0; i < tm.Year; i++) {
|
||||
if (LEAP_YEAR(i)) {
|
||||
seconds += SECS_PER_DAY; // add extra days for leap years
|
||||
}
|
||||
}
|
||||
|
||||
// add days for this year, months start from 1
|
||||
for (i = 1; i < tm.Month; i++) {
|
||||
if ( (i == 2) && LEAP_YEAR(tm.Year)) {
|
||||
seconds += SECS_PER_DAY * 29;
|
||||
} else {
|
||||
seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0
|
||||
}
|
||||
}
|
||||
seconds+= (tm.Day-1) * SECS_PER_DAY;
|
||||
seconds+= tm.Hour * SECS_PER_HOUR;
|
||||
seconds+= tm.Minute * SECS_PER_MIN;
|
||||
seconds+= tm.Second;
|
||||
return (uint32_t)seconds;
|
||||
}
|
||||
|
||||
|
||||
///*----------------------------------------------------------------------*
|
||||
// * Convert the given time change rule to a uint32_t value *
|
||||
// * for the given year. *
|
||||
// *----------------------------------------------------------------------*/
|
||||
uint32_t calcTimeChangeForRule(const TimeChangeRule& r, int yr)
|
||||
{
|
||||
uint8_t m = r.month; // temp copies of r.month and r.week
|
||||
uint8_t w = r.week;
|
||||
if (w == 0) // is this a "Last week" rule?
|
||||
{
|
||||
if (++m > 12) // yes, for "Last", go to the next month
|
||||
{
|
||||
m = 1;
|
||||
++yr;
|
||||
}
|
||||
w = 1; // and treat as first week of next month, subtract 7 days later
|
||||
}
|
||||
|
||||
// calculate first day of the month, or for "Last" rules, first day of the next month
|
||||
timeStruct tm;
|
||||
tm.Hour = r.hour;
|
||||
tm.Minute = 0;
|
||||
tm.Second = 0;
|
||||
tm.Day = 1;
|
||||
tm.Month = m;
|
||||
tm.Year = yr - 1970;
|
||||
uint32_t t = makeTime(tm);
|
||||
|
||||
// add offset from the first of the month to r.dow, and offset for the given week
|
||||
t += ( (r.dow - weekday(t) + 7) % 7 + (w - 1) * 7 ) * SECS_PER_DAY;
|
||||
// back up a week if this is a "Last" rule
|
||||
if (r.week == 0) t -= 7 * SECS_PER_DAY;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------*
|
||||
* Calculate the DST and standard time change points for the given *
|
||||
* given year as local and UTC uint32_t values. *
|
||||
*----------------------------------------------------------------------*/
|
||||
bool calcTimeChanges(int yr)
|
||||
{
|
||||
uint32_t dstLoc = calcTimeChangeForRule(m_dst, yr);
|
||||
uint32_t stdLoc = calcTimeChangeForRule(m_std, yr);
|
||||
bool changed = (m_dstLoc != dstLoc) || (m_stdLoc != stdLoc);
|
||||
m_dstLoc = dstLoc;
|
||||
m_stdLoc = stdLoc;
|
||||
m_dstUTC = m_dstLoc - m_std.offset * SECS_PER_MIN;
|
||||
m_stdUTC = m_stdLoc - m_dst.offset * SECS_PER_MIN;
|
||||
return changed;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*
|
||||
* Convert the given UTC time to local time, standard or *
|
||||
* daylight time, as appropriate. *
|
||||
*----------------------------------------------------------------------*/
|
||||
uint32_t toLocal(uint32_t utc)
|
||||
{
|
||||
// recalculate the time change points if needed
|
||||
if (year(utc) != year(m_dstUTC)) calcTimeChanges(year(utc));
|
||||
|
||||
if (utcIsDST(utc))
|
||||
return utc + m_dst.offset * SECS_PER_MIN;
|
||||
else
|
||||
return utc + m_std.offset * SECS_PER_MIN;
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------*
|
||||
* Determine whether the given UTC uint32_t is within the DST interval *
|
||||
* or the Standard time interval. *
|
||||
*----------------------------------------------------------------------*/
|
||||
bool utcIsDST(uint32_t utc)
|
||||
{
|
||||
// recalculate the time change points if needed
|
||||
if (year(utc) != year(m_dstUTC)) calcTimeChanges(year(utc));
|
||||
|
||||
if (m_stdUTC == m_dstUTC) // daylight time not observed in this tz
|
||||
return false;
|
||||
else if (m_stdUTC > m_dstUTC) // northern hemisphere
|
||||
return (utc >= m_dstUTC && utc < m_stdUTC);
|
||||
else // southern hemisphere
|
||||
return !(utc >= m_stdUTC && utc < m_dstUTC);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*
|
||||
* Determine whether the given Local uint32_t is within the DST interval *
|
||||
* or the Standard time interval. *
|
||||
*----------------------------------------------------------------------*/
|
||||
bool locIsDST(uint32_t local)
|
||||
{
|
||||
// recalculate the time change points if needed
|
||||
if (year(local) != year(m_dstLoc)) calcTimeChanges(year(local));
|
||||
|
||||
if (m_stdUTC == m_dstUTC) // daylight time not observed in this tz
|
||||
return false;
|
||||
else if (m_stdLoc > m_dstLoc) // northern hemisphere
|
||||
return (local >= m_dstLoc && local < m_stdLoc);
|
||||
else // southern hemisphere
|
||||
return !(local >= m_stdLoc && local < m_dstLoc);
|
||||
}
|
||||
+1895
-1249
File diff suppressed because it is too large
Load Diff
-330
@@ -1,330 +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
|
||||
WiFi.softAP(WifiGetAPssid().c_str(), SecuritySettings.WifiAPKey);
|
||||
// We start in STA mode
|
||||
WifiAPMode(false);
|
||||
|
||||
String log("WIFI : AP Mode ssid will be ");
|
||||
log=log+WifiGetAPssid();
|
||||
|
||||
log=log+F(" with address ");
|
||||
log=log+apIP.toString();
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool WifiIsAP()
|
||||
{
|
||||
#if defined(ESP8266)
|
||||
byte wifimode = wifi_get_opmode();
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
byte wifimode = WiFi.getMode();
|
||||
#endif
|
||||
return(wifimode == 2 || wifimode == 3); //apmode is enabled
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Set Wifi AP Mode
|
||||
//********************************************************************************
|
||||
void WifiAPMode(boolean state)
|
||||
{
|
||||
if (WifiIsAP())
|
||||
{
|
||||
//want to disable?
|
||||
if (!state)
|
||||
{
|
||||
WiFi.mode(WIFI_STA);
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : AP Mode disabled"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//want to enable?
|
||||
if (state)
|
||||
{
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
addLog(LOG_LEVEL_INFO, F("WIFI : AP Mode enabled"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Configure network and connect to Wifi SSID and SSID2
|
||||
//********************************************************************************
|
||||
boolean WifiConnect(byte connectAttempts)
|
||||
{
|
||||
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
|
||||
|
||||
//use static ip?
|
||||
if (Settings.IP[0] != 0 && Settings.IP[0] != 255)
|
||||
{
|
||||
const IPAddress ip = Settings.IP;
|
||||
log = F("IP : Static IP :");
|
||||
log += ip;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
const IPAddress gw = Settings.Gateway;
|
||||
const IPAddress subnet = Settings.Subnet;
|
||||
const IPAddress dns = Settings.DNS;
|
||||
WiFi.config(ip, gw, subnet, dns);
|
||||
}
|
||||
|
||||
//try to connect to one of the access points
|
||||
if (WifiConnectSSID(SecuritySettings.WifiSSID, SecuritySettings.WifiKey, connectAttempts) ||
|
||||
WifiConnectSSID(SecuritySettings.WifiSSID2, SecuritySettings.WifiKey2, connectAttempts))
|
||||
{
|
||||
// fix octet?
|
||||
if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255)
|
||||
{
|
||||
IPAddress ip = WiFi.localIP();
|
||||
IPAddress gw = WiFi.gatewayIP();
|
||||
IPAddress subnet = WiFi.subnetMask();
|
||||
ip[3] = Settings.IP_Octet;
|
||||
log = F("IP : Fixed IP octet:");
|
||||
log += ip;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
WiFi.config(ip, gw, subnet);
|
||||
}
|
||||
|
||||
#ifdef FEATURE_MDNS
|
||||
|
||||
String log = F("WIFI : ");
|
||||
if (MDNS.begin(WifiGetHostname().c_str(), WiFi.localIP())) {
|
||||
|
||||
log += F("mDNS started, with name: ");
|
||||
log += WifiGetHostname();
|
||||
log += F(".local");
|
||||
}
|
||||
else{
|
||||
log += F("mDNS failed");
|
||||
}
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
#endif
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
addLog(LOG_LEVEL_ERROR, F("WIFI : Could not connect to AP!"));
|
||||
|
||||
//everything failed, activate AP mode (will deactivate automatically after a while if its connected again)
|
||||
WifiAPMode(true);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Connect to Wifi specific SSID
|
||||
//********************************************************************************
|
||||
boolean WifiConnectSSID(char WifiSSID[], char WifiKey[], byte connectAttempts)
|
||||
{
|
||||
String log;
|
||||
|
||||
//already connected, need to disconnect first
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
return(true);
|
||||
|
||||
//no ssid specified
|
||||
if ((WifiSSID[0] == 0) || (strcasecmp(WifiSSID, "ssid") == 0))
|
||||
return(false);
|
||||
|
||||
for (byte tryConnect = 1; tryConnect <= connectAttempts; tryConnect++)
|
||||
{
|
||||
log = F("WIFI : Connecting ");
|
||||
log += WifiSSID;
|
||||
log += F(" attempt #");
|
||||
log += tryConnect;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
|
||||
if (tryConnect == 1)
|
||||
WiFi.begin(WifiSSID, WifiKey);
|
||||
else
|
||||
WiFi.begin();
|
||||
|
||||
//wait until it connects
|
||||
for (byte x = 0; x < 200; x++)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
statusLED(false);
|
||||
delay(50);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
{
|
||||
if (Settings.UseNTP) {
|
||||
initTime();
|
||||
}
|
||||
log = F("WIFI : Connected! IP: ");
|
||||
log += formatIP(WiFi.localIP());
|
||||
log += F(" (");
|
||||
log += WifiGetHostname();
|
||||
log += F(")");
|
||||
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
statusLED(true);
|
||||
return(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// log = F("WIFI : Disconnecting!");
|
||||
// addLog(LOG_LEVEL_INFO, log);
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Disconnect from Wifi AP
|
||||
//********************************************************************************
|
||||
void WifiDisconnect()
|
||||
{
|
||||
WiFi.disconnect();
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// 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 automatically reconnect
|
||||
if (NC_Count > 2)
|
||||
{
|
||||
WifiConnect(2);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//********************************************************************************
|
||||
// Return subnet range of WiFi.
|
||||
//********************************************************************************
|
||||
bool getSubnetRange(IPAddress& low, IPAddress& high)
|
||||
{
|
||||
if (WifiIsAP()) {
|
||||
// WiFi is active as accesspoint, do not check.
|
||||
return false;
|
||||
}
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
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;
|
||||
}
|
||||
+27
-90
@@ -34,7 +34,7 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
if (event->idx != 0)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (!WiFiConnected(100)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
@@ -76,64 +76,6 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
switch (event->sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
break;
|
||||
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
|
||||
url += F("&svalue=");
|
||||
url += (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
break;
|
||||
case SENSOR_TYPE_DUAL: // any sensor that uses two simple values
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
url += (";");
|
||||
url += formatUserVar(event, 1);
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 1);
|
||||
url += F(";");
|
||||
url += humStat(UserVar[event->BaseVarIndex + 1]);
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_BARO: // temp + bar used for BMP085 and BMP280
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 1);
|
||||
url += F(";0;0;");
|
||||
break;
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 1);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 2);
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 1);
|
||||
url += F(";");
|
||||
url += humStat(UserVar[event->BaseVarIndex + 1]);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 2);
|
||||
url += F(";0");
|
||||
break;
|
||||
case SENSOR_TYPE_QUAD:
|
||||
url += F("&svalue=");
|
||||
url += formatUserVar(event, 0);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 1);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 2);
|
||||
url += F(";");
|
||||
url += formatUserVar(event, 3);
|
||||
break;
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
url = F("/json.htm?type=command¶m=switchlight&idx=");
|
||||
url += event->idx;
|
||||
@@ -147,28 +89,39 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
url = F("/json.htm?type=command¶m=switchlight&idx=");
|
||||
url += event->idx;
|
||||
url += F("&switchcmd=");
|
||||
if (UserVar[event->BaseVarIndex] == 0)
|
||||
if (UserVar[event->BaseVarIndex] == 0) {
|
||||
url += ("Off");
|
||||
else
|
||||
{
|
||||
} else {
|
||||
url += F("Set%20Level&level=");
|
||||
url += UserVar[event->BaseVarIndex];
|
||||
}
|
||||
break;
|
||||
case (SENSOR_TYPE_WIND):
|
||||
url += F("&svalue="); // WindDir in degrees; WindDir as text; Wind speed average ; Wind speed gust; 0
|
||||
url += formatUserVar(event, 0);
|
||||
url += ";";
|
||||
url += getBearing(UserVar[event->BaseVarIndex]);
|
||||
url += ";";
|
||||
// Domoticz expects the wind speed in (m/s * 10)
|
||||
url += toString((UserVar[event->BaseVarIndex + 1] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[1]);
|
||||
url += ";";
|
||||
url += toString((UserVar[event->BaseVarIndex + 2] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[2]);
|
||||
url += ";0";
|
||||
|
||||
case SENSOR_TYPE_SINGLE:
|
||||
case SENSOR_TYPE_LONG:
|
||||
case SENSOR_TYPE_DUAL:
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
case SENSOR_TYPE_QUAD:
|
||||
case SENSOR_TYPE_TEMP_HUM:
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO:
|
||||
case SENSOR_TYPE_WIND:
|
||||
default:
|
||||
url = F("/json.htm?type=command¶m=udevice&idx=");
|
||||
url += event->idx;
|
||||
url += F("&nvalue=0");
|
||||
url += F("&svalue=");
|
||||
url += formatDomoticzSensorType(event);
|
||||
break;
|
||||
}
|
||||
|
||||
// Add WiFi reception quality
|
||||
url += F("&rssi=");
|
||||
url += mapRSSItoDomoticz();
|
||||
#if FEATURE_ADC_VCC
|
||||
url += F("&battery=");
|
||||
url += mapVccToDomoticz();
|
||||
#endif
|
||||
|
||||
// This will send the request to the server
|
||||
String request = F("GET ");
|
||||
@@ -182,7 +135,7 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
client.print(request);
|
||||
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client.available() && !timeOutReached(timer))
|
||||
while (!client.available() && !timeOutReached(timer))
|
||||
yield();
|
||||
|
||||
// Read all the lines of the reply from server and log them
|
||||
@@ -212,19 +165,3 @@ boolean CPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
int humStat(int hum){
|
||||
int lHumStat;
|
||||
if(hum<30){
|
||||
lHumStat = 2;
|
||||
}else if(hum<40){
|
||||
lHumStat = 0;
|
||||
}else if(hum<59){
|
||||
lHumStat = 1;
|
||||
}else{
|
||||
lHumStat = 3;
|
||||
|
||||
}
|
||||
return lHumStat;
|
||||
}
|
||||
|
||||
+95
-161
@@ -44,81 +44,86 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
// char json[512];
|
||||
// json[0] = 0;
|
||||
// event->String2.toCharArray(json, 512);
|
||||
// Find first enabled controller index with this protocol
|
||||
byte ControllerID = findFirstEnabledControllerWithId(CPLUGIN_ID_002);
|
||||
if (ControllerID < CONTROLLER_MAX) {
|
||||
StaticJsonBuffer<512> jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.parseObject(event->String2.c_str());
|
||||
if (root.success())
|
||||
{
|
||||
unsigned int idx = root[F("idx")];
|
||||
float nvalue = root[F("nvalue")];
|
||||
long nvaluealt = root[F("nvalue")];
|
||||
//const char* name = root["name"]; // Not used
|
||||
//const char* svalue = root["svalue"]; // Not used
|
||||
const char* svalue1 = root[F("svalue1")];
|
||||
//const char* svalue2 = root["svalue2"]; // Not used
|
||||
//const char* svalue3 = root["svalue3"]; // Not used
|
||||
const char* switchtype = root[F("switchType")]; // Expect "On/Off" or "dimmer"
|
||||
if (nvalue == 0)
|
||||
nvalue = nvaluealt;
|
||||
if ((int)switchtype == 0)
|
||||
switchtype = "?";
|
||||
|
||||
StaticJsonBuffer<512> jsonBuffer;
|
||||
JsonObject& root = jsonBuffer.parseObject(event->String2.c_str());
|
||||
|
||||
if (root.success())
|
||||
{
|
||||
unsigned int idx = root[F("idx")];
|
||||
float nvalue = root[F("nvalue")];
|
||||
long nvaluealt = root[F("nvalue")];
|
||||
//const char* name = root["name"]; // Not used
|
||||
//const char* svalue = root["svalue"]; // Not used
|
||||
const char* svalue1 = root[F("svalue1")];
|
||||
//const char* svalue2 = root["svalue2"]; // Not used
|
||||
//const char* svalue3 = root["svalue3"]; // Not used
|
||||
const char* switchtype = root[F("switchType")]; // Expect "On/Off" or "dimmer"
|
||||
if (nvalue == 0)
|
||||
nvalue = nvaluealt;
|
||||
if ((int)switchtype == 0)
|
||||
switchtype = "?";
|
||||
|
||||
for (byte x = 0; x < TASKS_MAX; x++) {
|
||||
// We need the index of the controller we are: 0-CONTROLLER_MAX
|
||||
byte ControllerID = 0;
|
||||
for (byte i=0; i < CONTROLLER_MAX; i++)
|
||||
{
|
||||
if (Settings.Protocol[i] == CPLUGIN_ID_002) { ControllerID = i; }
|
||||
}
|
||||
if (Settings.TaskDeviceID[ControllerID][x] == idx) // get idx for our controller index
|
||||
{
|
||||
if (Settings.TaskDeviceNumber[x] == 1) // temp solution, if input switch, update state
|
||||
{
|
||||
String action = F("inputSwitchState,");
|
||||
action += x;
|
||||
action += ",";
|
||||
action += nvalue;
|
||||
struct EventStruct TempEvent;
|
||||
parseCommandString(&TempEvent, action);
|
||||
PluginCall(PLUGIN_WRITE, &TempEvent, action);
|
||||
}
|
||||
if (Settings.TaskDeviceNumber[x] == 29) // temp solution, if plugin 029, set gpio
|
||||
for (byte x = 0; x < TASKS_MAX; x++) {
|
||||
// We need the index of the controller we are: 0...CONTROLLER_MAX
|
||||
if (Settings.TaskDeviceEnabled[x] && Settings.TaskDeviceID[ControllerID][x] == idx) // get idx for our controller index
|
||||
{
|
||||
String action = "";
|
||||
int baseVar = x * VARS_PER_TASK;
|
||||
struct EventStruct TempEvent;
|
||||
if (strcasecmp_P(switchtype, PSTR("dimmer")) == 0)
|
||||
{
|
||||
int pwmValue = UserVar[baseVar];
|
||||
action = F("pwm,");
|
||||
action += Settings.TaskDevicePin1[x];
|
||||
action += ",";
|
||||
switch ((int)nvalue)
|
||||
switch (Settings.TaskDeviceNumber[x]) {
|
||||
case 1: // temp solution, if input switch, update state
|
||||
{
|
||||
case 0:
|
||||
pwmValue = 0;
|
||||
break;
|
||||
case 1:
|
||||
pwmValue = UserVar[baseVar];
|
||||
break;
|
||||
case 2:
|
||||
pwmValue = 10 * atol(svalue1);
|
||||
UserVar[baseVar] = pwmValue;
|
||||
break;
|
||||
action = F("inputSwitchState,");
|
||||
action += x;
|
||||
action += ",";
|
||||
action += nvalue;
|
||||
break;
|
||||
}
|
||||
action += pwmValue;
|
||||
case 29: // temp solution, if plugin 029, set gpio
|
||||
{
|
||||
action = "";
|
||||
int baseVar = x * VARS_PER_TASK;
|
||||
struct EventStruct TempEvent;
|
||||
if (strcasecmp_P(switchtype, PSTR("dimmer")) == 0)
|
||||
{
|
||||
int pwmValue = UserVar[baseVar];
|
||||
action = F("pwm,");
|
||||
action += Settings.TaskDevicePin1[x];
|
||||
action += ",";
|
||||
switch ((int)nvalue)
|
||||
{
|
||||
case 0:
|
||||
pwmValue = 0;
|
||||
break;
|
||||
case 1:
|
||||
pwmValue = UserVar[baseVar];
|
||||
break;
|
||||
case 2:
|
||||
pwmValue = 10 * atol(svalue1);
|
||||
UserVar[baseVar] = pwmValue;
|
||||
break;
|
||||
}
|
||||
action += pwmValue;
|
||||
} else {
|
||||
UserVar[baseVar] = nvalue;
|
||||
action = F("gpio,");
|
||||
action += Settings.TaskDevicePin1[x];
|
||||
action += ",";
|
||||
action += nvalue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
UserVar[baseVar] = nvalue;
|
||||
action = F("gpio,");
|
||||
action += Settings.TaskDevicePin1[x];
|
||||
action += ",";
|
||||
action += nvalue;
|
||||
if (action.length() > 0) {
|
||||
struct EventStruct TempEvent;
|
||||
parseCommandString(&TempEvent, action);
|
||||
PluginCall(PLUGIN_WRITE, &TempEvent, action);
|
||||
// trigger rulesprocessing
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(x);
|
||||
}
|
||||
parseCommandString(&TempEvent, action);
|
||||
PluginCall(PLUGIN_WRITE, &TempEvent, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,88 +135,23 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
if (event->idx != 0)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
if (!ControllerSettings.checkHostReachable(true)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
|
||||
StaticJsonBuffer<200> jsonBuffer;
|
||||
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
|
||||
root[F("idx")] = event->idx;
|
||||
|
||||
String values;
|
||||
// char str[80];
|
||||
root[F("RSSI")] = mapRSSItoDomoticz();
|
||||
#if FEATURE_ADC_VCC
|
||||
root[F("Battery")] = mapVccToDomoticz();
|
||||
#endif
|
||||
|
||||
switch (event->sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
|
||||
root[F("nvalue")] = 0;
|
||||
values = formatUserVar(event, 0);
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
break;
|
||||
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
|
||||
root[F("nvalue")] = 0;
|
||||
values = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
break;
|
||||
case SENSOR_TYPE_DUAL: // any sensor that uses two simple values
|
||||
root[F("nvalue")] = 0;
|
||||
values = formatUserVar(event, 0);
|
||||
values += ";";
|
||||
values += formatUserVar(event, 1);
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_TRIPLE: // any sensor that uses three simple values
|
||||
root[F("nvalue")] = 0;
|
||||
values = toString(UserVar[event->BaseVarIndex ], ExtraTaskSettings.TaskDeviceValueDecimals[0]);
|
||||
values += ";";
|
||||
values += toString(UserVar[event->BaseVarIndex + 1], ExtraTaskSettings.TaskDeviceValueDecimals[1]);
|
||||
values += ";";
|
||||
values += toString(UserVar[event->BaseVarIndex + 2], ExtraTaskSettings.TaskDeviceValueDecimals[2]);
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11
|
||||
root[F("nvalue")] = 0;
|
||||
values = formatUserVar(event, 0);
|
||||
values += ";";
|
||||
values += formatUserVar(event, 1);
|
||||
values += ";0";
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085
|
||||
root[F("nvalue")] = 0;
|
||||
values = formatUserVar(event, 0);
|
||||
values += formatUserVar(event, 1);
|
||||
values += ";0;0;";
|
||||
// values.toCharArray(str, 80);
|
||||
root[F("svalue")] = values.c_str();
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280
|
||||
root[F("nvalue")] = 0;
|
||||
values = formatUserVar(event, 0);
|
||||
values += ";";
|
||||
values += formatUserVar(event, 1);
|
||||
values += ";0;";
|
||||
values += formatUserVar(event, 2);
|
||||
values += ";0";
|
||||
root[F("svalue")] = values.c_str();
|
||||
// values.toCharArray(str, 80);
|
||||
// root[F("svalue")] = str;
|
||||
break;
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
root[F("command")] = String(F("switchlight"));
|
||||
if (UserVar[event->BaseVarIndex] == 0)
|
||||
@@ -226,19 +166,19 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
else
|
||||
root[F("Set%20Level")] = UserVar[event->BaseVarIndex];
|
||||
break;
|
||||
case SENSOR_TYPE_WIND: // WindDir in degrees; WindDir as text; Wind speed average ; Wind speed gust
|
||||
values = formatUserVar(event, 0);
|
||||
values += ";";
|
||||
values += getBearing(int(UserVar[event->BaseVarIndex] / 22.5));
|
||||
values += ";";
|
||||
// Domoticz expects the wind speed in (m/s * 10)
|
||||
values += toString((UserVar[event->BaseVarIndex + 1] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[1]);
|
||||
values += ";";
|
||||
values += toString((UserVar[event->BaseVarIndex + 2] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[2]);
|
||||
values += ";0;0";
|
||||
root[F("svalue")] = values.c_str();
|
||||
// values.toCharArray(str, 80);
|
||||
// root["svalue"] = str;
|
||||
|
||||
case SENSOR_TYPE_SINGLE:
|
||||
case SENSOR_TYPE_LONG:
|
||||
case SENSOR_TYPE_DUAL:
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
case SENSOR_TYPE_QUAD:
|
||||
case SENSOR_TYPE_TEMP_HUM:
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO:
|
||||
case SENSOR_TYPE_WIND:
|
||||
default:
|
||||
root[F("nvalue")] = 0;
|
||||
root[F("svalue")] = formatDomoticzSensorType(event);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -249,15 +189,9 @@ boolean CPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
String pubname = ControllerSettings.Publish;
|
||||
pubname.replace(F("%sysname%"), Settings.Name);
|
||||
pubname.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName);
|
||||
pubname.replace(F("%id%"), String(event->idx));
|
||||
|
||||
if (!MQTTclient.publish(pubname.c_str(), json.c_str(), Settings.MQTTRetainFlag))
|
||||
parseControllerVariables(pubname, event, false);
|
||||
if (!MQTTpublish(event->ControllerIndex, pubname.c_str(), json.c_str(), Settings.MQTTRetainFlag))
|
||||
{
|
||||
log = F("MQTT : publish failed");
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
MQTTConnect();
|
||||
connectionFailures++;
|
||||
}
|
||||
else if (connectionFailures)
|
||||
|
||||
+5
-5
@@ -57,8 +57,8 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
|
||||
url += formatUserVar(event, 0);
|
||||
url += "\n";
|
||||
|
||||
strcpy_P(log, PSTR("TELNT: Sending enter"));
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
// strcpy_P(log, PSTR("TELNT: Sending enter"));
|
||||
// addLog(LOG_LEVEL_ERROR, log);
|
||||
client.print(" \n");
|
||||
|
||||
unsigned long timer = millis() + 200;
|
||||
@@ -77,20 +77,20 @@ boolean CPlugin_003(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
success = true;
|
||||
strcpy_P(log, PSTR("TELNT: Password request ok"));
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
|
||||
strcpy_P(log, PSTR("TELNT: Sending pw"));
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
client.println(SecuritySettings.ControllerPassword[event->ControllerIndex]);
|
||||
delay(100);
|
||||
while (client.available())
|
||||
client.read();
|
||||
|
||||
strcpy_P(log, PSTR("TELNT: Sending cmd"));
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
client.print(url);
|
||||
delay(10);
|
||||
while (client.available())
|
||||
|
||||
+17
-1
@@ -16,7 +16,7 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
Protocol[++protocolCount].Number = CPLUGIN_ID_004;
|
||||
Protocol[protocolCount].usesMQTT = false;
|
||||
Protocol[protocolCount].usesAccount = false;
|
||||
Protocol[protocolCount].usesAccount = true;
|
||||
Protocol[protocolCount].usesPassword = true;
|
||||
Protocol[protocolCount].defaultPort = 80;
|
||||
Protocol[protocolCount].usesID = true;
|
||||
@@ -29,6 +29,22 @@ boolean CPlugin_004(byte function, struct EventStruct *event, String& string)
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_GET_PROTOCOL_DISPLAY_NAME:
|
||||
{
|
||||
success = true;
|
||||
switch (event->idx) {
|
||||
case CONTROLLER_USER:
|
||||
string = F("ThingHTTP Name");
|
||||
break;
|
||||
case CONTROLLER_PASS:
|
||||
string = F("API Key");
|
||||
break;
|
||||
default:
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
|
||||
+41
-43
@@ -39,51 +39,50 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_PROTOCOL_RECV:
|
||||
{
|
||||
// Split topic into array
|
||||
String tmpTopic = event->String1.substring(1);
|
||||
String topicSplit[10];
|
||||
int SlashIndex = tmpTopic.indexOf('/');
|
||||
byte count = 0;
|
||||
while (SlashIndex > 0 && count < 10 - 1)
|
||||
{
|
||||
topicSplit[count] = tmpTopic.substring(0, SlashIndex);
|
||||
tmpTopic = tmpTopic.substring(SlashIndex + 1);
|
||||
SlashIndex = tmpTopic.indexOf('/');
|
||||
count++;
|
||||
byte ControllerID = findFirstEnabledControllerWithId(CPLUGIN_ID_005);
|
||||
if (ControllerID == CONTROLLER_MAX) {
|
||||
// Controller is not enabled.
|
||||
break;
|
||||
} else {
|
||||
String cmd;
|
||||
struct EventStruct TempEvent;
|
||||
bool validTopic = false;
|
||||
const int lastindex = event->String1.lastIndexOf('/');
|
||||
const String lastPartTopic = event->String1.substring(lastindex + 1);
|
||||
if (lastPartTopic == F("cmd")) {
|
||||
cmd = event->String2;
|
||||
parseCommandString(&TempEvent, cmd);
|
||||
TempEvent.Source = VALUE_SOURCE_MQTT;
|
||||
validTopic = true;
|
||||
} else {
|
||||
if (lastindex > 0) {
|
||||
// Topic has at least one separator
|
||||
if (isFloat(event->String2) && isInt(lastPartTopic)) {
|
||||
int prevLastindex = event->String1.lastIndexOf('/', lastindex - 1);
|
||||
cmd = event->String1.substring(prevLastindex + 1, lastindex);
|
||||
TempEvent.Par1 = lastPartTopic.toInt();
|
||||
TempEvent.Par2 = event->String2.toFloat();
|
||||
TempEvent.Par3 = 0;
|
||||
validTopic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (validTopic) {
|
||||
// in case of event, store to buffer and return...
|
||||
String command = parseString(cmd, 1);
|
||||
if (command == F("event")) {
|
||||
eventBuffer = cmd.substring(6);
|
||||
} else if (!PluginCall(PLUGIN_WRITE, &TempEvent, cmd)) {
|
||||
remoteConfig(&TempEvent, cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
topicSplit[count] = tmpTopic;
|
||||
|
||||
String cmd = "";
|
||||
struct EventStruct TempEvent;
|
||||
|
||||
if (topicSplit[count] == F("cmd"))
|
||||
{
|
||||
cmd = event->String2;
|
||||
parseCommandString(&TempEvent, cmd);
|
||||
TempEvent.Source = VALUE_SOURCE_MQTT;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = topicSplit[count - 1];
|
||||
TempEvent.Par1 = topicSplit[count].toInt();
|
||||
TempEvent.Par2 = event->String2.toFloat();
|
||||
TempEvent.Par3 = 0;
|
||||
}
|
||||
// in case of event, store to buffer and return...
|
||||
String command = parseString(cmd, 1);
|
||||
if (command == F("event"))
|
||||
eventBuffer = cmd.substring(6);
|
||||
else if
|
||||
(PluginCall(PLUGIN_WRITE, &TempEvent, cmd));
|
||||
else
|
||||
remoteConfig(&TempEvent, cmd);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (!WiFiConnected(100)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
@@ -96,9 +95,7 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
String pubname = ControllerSettings.Publish;
|
||||
pubname.replace(F("%sysname%"), Settings.Name);
|
||||
pubname.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName);
|
||||
pubname.replace(F("%id%"), String(event->idx));
|
||||
parseControllerVariables(pubname, event, false);
|
||||
|
||||
String value = "";
|
||||
// byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]);
|
||||
@@ -111,7 +108,8 @@ boolean CPlugin_005(byte function, struct EventStruct *event, String& string)
|
||||
value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
else
|
||||
value = formatUserVar(event, x);
|
||||
MQTTclient.publish(tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
|
||||
|
||||
MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
|
||||
String log = F("MQTT : ");
|
||||
log += tmppubname;
|
||||
log += " ";
|
||||
|
||||
+3
-5
@@ -76,7 +76,7 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (!WiFiConnected(100)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
@@ -89,9 +89,7 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
|
||||
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString);
|
||||
|
||||
String pubname = ControllerSettings.Publish;
|
||||
pubname.replace(F("%sysname%"), Settings.Name);
|
||||
pubname.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName);
|
||||
pubname.replace(F("%id%"), String(event->idx));
|
||||
parseControllerVariables(pubname, event, false);
|
||||
|
||||
String value = "";
|
||||
// byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]);
|
||||
@@ -104,7 +102,7 @@ boolean CPlugin_006(byte function, struct EventStruct *event, String& string)
|
||||
value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
else
|
||||
value = formatUserVar(event, x);
|
||||
MQTTclient.publish(tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
|
||||
MQTTpublish(event->ControllerIndex, tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+14
-41
@@ -31,10 +31,16 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (!WiFiConnected(100)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
const byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
if (valueCount == 0 || valueCount > 3) {
|
||||
addLog(LOG_LEVEL_ERROR, F("emoncms : Unknown sensortype or too many sensor values"));
|
||||
break;
|
||||
}
|
||||
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
|
||||
@@ -59,47 +65,14 @@ boolean CPlugin_007(byte function, struct EventStruct *event, String& string)
|
||||
postDataStr += Settings.Unit;
|
||||
postDataStr += F("&json=");
|
||||
|
||||
switch (event->sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
|
||||
postDataStr += F("{field");
|
||||
postDataStr += event->idx;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, 0);
|
||||
postDataStr += "}";
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM: // dual value
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
case SENSOR_TYPE_DUAL:
|
||||
postDataStr += F("{field");
|
||||
postDataStr += event->idx;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, 0);
|
||||
postDataStr += F(",field");
|
||||
postDataStr += event->idx + 1;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, 1);
|
||||
postDataStr += "}";
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO:
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
postDataStr += F("{field");
|
||||
postDataStr += event->idx;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, 0);
|
||||
postDataStr += F(",field");
|
||||
postDataStr += event->idx + 1;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, 1);
|
||||
postDataStr += F(",field");
|
||||
postDataStr += event->idx + 2;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, 2);
|
||||
postDataStr += "}";
|
||||
break;
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
break;
|
||||
for (byte i = 0; i < valueCount; ++i) {
|
||||
postDataStr += (i == 0) ? F("{") : F(",");
|
||||
postDataStr += F("field");
|
||||
postDataStr += event->idx + i;
|
||||
postDataStr += ":";
|
||||
postDataStr += formatUserVar(event, i);
|
||||
}
|
||||
postDataStr += "}";
|
||||
postDataStr += F("&apikey=");
|
||||
postDataStr += SecuritySettings.ControllerPassword[event->ControllerIndex]; // "0UDNN17RW6XAS2E5" // api key
|
||||
|
||||
|
||||
+3
-5
@@ -68,7 +68,7 @@ boolean CPlugin_008(byte function, struct EventStruct *event, String& string)
|
||||
//********************************************************************************
|
||||
boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (!WiFiConnected(100)) {
|
||||
return false;
|
||||
}
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
@@ -105,10 +105,8 @@ boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned
|
||||
|
||||
String url = "/";
|
||||
url += ControllerSettings.Publish;
|
||||
//TODO: move this to a generic replacement function?
|
||||
url.replace(F("%sysname%"), URLEncode(Settings.Name));
|
||||
url.replace(F("%tskname%"), URLEncode(ExtraTaskSettings.TaskDeviceName));
|
||||
url.replace(F("%id%"), String(event->idx));
|
||||
parseControllerVariables(url, event, true);
|
||||
|
||||
url.replace(F("%valname%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex]));
|
||||
if (longValue)
|
||||
url.replace(F("%value%"), String(longValue));
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (!WiFiConnected(100)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
+3
-5
@@ -80,18 +80,16 @@ void C010_Send(struct EventStruct *event, byte varIndex, float value, unsigned l
|
||||
|
||||
String msg = "";
|
||||
msg += ControllerSettings.Publish;
|
||||
msg.replace(F("%sysname%"), Settings.Name);
|
||||
msg.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName);
|
||||
msg.replace(F("%id%"), String(event->idx));
|
||||
parseControllerVariables(msg, event, false);
|
||||
msg.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[varIndex]);
|
||||
if (longValue)
|
||||
msg.replace(F("%value%"), String(longValue));
|
||||
else
|
||||
msg.replace(F("%value%"), toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]));
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
+4
-65
@@ -120,7 +120,7 @@ boolean CPlugin_011(byte function, struct EventStruct *event, String& string)
|
||||
//********************************************************************************
|
||||
boolean HTTPSend011(struct EventStruct *event)
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (!WiFiConnected(100)) {
|
||||
return false;
|
||||
}
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
@@ -270,75 +270,14 @@ void ReplaceTokenByValue(String& s, struct EventStruct *event)
|
||||
// %1%%vname1%,Standort=%tskname% Wert=%val1%%/1%%2%%LF%%vname2%,Standort=%tskname% Wert=%val2%%/2%%3%%LF%%vname3%,Standort=%tskname% Wert=%val3%%/3%%4%%LF%%vname4%,Standort=%tskname% Wert=%val4%%/4%
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP before parsing: "));
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, s);
|
||||
|
||||
switch (event->sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE:
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
case SENSOR_TYPE_DIMMER:
|
||||
case SENSOR_TYPE_WIND:
|
||||
case SENSOR_TYPE_LONG:
|
||||
{
|
||||
DeleteNotNeededValues(s,1);
|
||||
break;
|
||||
}
|
||||
case SENSOR_TYPE_DUAL:
|
||||
case SENSOR_TYPE_TEMP_HUM:
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
{
|
||||
DeleteNotNeededValues(s,2);
|
||||
break;
|
||||
}
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO:
|
||||
{
|
||||
DeleteNotNeededValues(s,3);
|
||||
break;
|
||||
}
|
||||
case SENSOR_TYPE_QUAD:
|
||||
{
|
||||
DeleteNotNeededValues(s,4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
const byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
DeleteNotNeededValues(s,valueCount);
|
||||
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP after parsing: "));
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, s);
|
||||
|
||||
//NOTE: cant we just call parseTemplate() for all the standard stuff??
|
||||
parseControllerVariables(s, event, true);
|
||||
|
||||
s.replace(F("%systime%"), getTimeString(':'));
|
||||
|
||||
#if FEATURE_ADC_VCC
|
||||
s.replace(F("%vcc%"), String(vcc));
|
||||
#endif
|
||||
|
||||
// IPAddress ip = WiFi.localIP();
|
||||
// char strIP[20];
|
||||
// sprintf_P(strIP, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]);
|
||||
s.replace(F("%ip%"),WiFi.localIP().toString());
|
||||
|
||||
s.replace(F("%sysload%"), String(100 - (100 * loopCounterLast / loopCounterMax)));
|
||||
s.replace(F("%uptime%"), String(wdcounter / 2));
|
||||
|
||||
s.replace(F("%CR%"), F("\r"));
|
||||
s.replace(F("%LF%"), F("\n"));
|
||||
s.replace(F("%sysname%"), URLEncode(Settings.Name));
|
||||
s.replace(F("%tskname%"), URLEncode(ExtraTaskSettings.TaskDeviceName));
|
||||
s.replace(F("%id%"), String(event->idx));
|
||||
s.replace(F("%vname1%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[0]));
|
||||
s.replace(F("%vname2%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[1]));
|
||||
s.replace(F("%vname3%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[2]));
|
||||
s.replace(F("%vname4%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[3]));
|
||||
|
||||
if (event->sensorType == SENSOR_TYPE_LONG)
|
||||
s.replace(F("%val1%"), String((unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)));
|
||||
else {
|
||||
s.replace(F("%val1%"), formatUserVar(event, 0));
|
||||
s.replace(F("%val2%"), formatUserVar(event, 1));
|
||||
s.replace(F("%val3%"), formatUserVar(event, 2));
|
||||
s.replace(F("%val4%"), formatUserVar(event, 3));
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, F("HTTP after replacements: "));
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, s);
|
||||
}
|
||||
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 012: Blynk #############################################
|
||||
//#######################################################################################################
|
||||
|
||||
#ifdef PLUGIN_BUILD_TESTING
|
||||
|
||||
#define CPLUGIN_012
|
||||
#define CPLUGIN_ID_012 12
|
||||
#define CPLUGIN_NAME_012 "Blynk HTTP [TESTING]"
|
||||
|
||||
boolean CPlugin_012(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case CPLUGIN_PROTOCOL_ADD:
|
||||
{
|
||||
Protocol[++protocolCount].Number = CPLUGIN_ID_012;
|
||||
Protocol[protocolCount].usesMQTT = false;
|
||||
Protocol[protocolCount].usesAccount = false;
|
||||
Protocol[protocolCount].usesPassword = true;
|
||||
Protocol[protocolCount].defaultPort = 80;
|
||||
Protocol[protocolCount].usesID = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(CPLUGIN_NAME_012);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
String postDataStr = F("");
|
||||
const byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
success = CPlugin_012_send(event, valueCount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
boolean CPlugin_012_send(struct EventStruct *event, int nrValues) {
|
||||
String postDataStr = F("");
|
||||
boolean success = true;
|
||||
for (int i = 0; i < nrValues && success; ++i) {
|
||||
postDataStr = F("update/V") ;
|
||||
postDataStr += event->idx + i;
|
||||
postDataStr += F("?value=");
|
||||
postDataStr += formatUserVar(event, i);
|
||||
success = Blynk_get(postDataStr, event->ControllerIndex);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
boolean Blynk_get(const String& command, byte controllerIndex, float *data )
|
||||
{
|
||||
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(controllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
// Use WiFiClient class to create TCP connections
|
||||
WiFiClient client;
|
||||
if ((SecuritySettings.ControllerPassword[controllerIndex][0] == 0) || !ControllerSettings.connectToHost(client))
|
||||
{
|
||||
connectionFailures++;
|
||||
addLog(LOG_LEVEL_ERROR, F("Blynk : connection failed"));
|
||||
return false;
|
||||
}
|
||||
if (connectionFailures)
|
||||
connectionFailures--;
|
||||
|
||||
// We now create a URI for the request
|
||||
char request[300] = {0};
|
||||
sprintf_P(request,
|
||||
PSTR("GET /%s/%s HTTP/1.1\r\n Host: %s \r\n Connection: close\r\n\r\n"),
|
||||
SecuritySettings.ControllerPassword[controllerIndex],
|
||||
command.c_str(),
|
||||
ControllerSettings.getHost().c_str());
|
||||
addLog(LOG_LEVEL_DEBUG, request);
|
||||
client.print(request);
|
||||
|
||||
unsigned long timer = millis() + 200;
|
||||
while (!client.available() && !timeOutReached(timer))
|
||||
yield();
|
||||
|
||||
boolean success = false;
|
||||
char log[80] = {0};
|
||||
|
||||
// Read all the lines of the reply from server and log them
|
||||
while (client.available()) {
|
||||
String line;
|
||||
safeReadStringUntil(client, line, '\n');
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, line);
|
||||
// success ?
|
||||
if (line.substring(0, 15) == "HTTP/1.1 200 OK") {
|
||||
strcpy_P(log, PSTR("HTTP : Success"));
|
||||
success = true;
|
||||
}
|
||||
else if (line.substring(0, 24) == "HTTP/1.1 400 Bad Request") {
|
||||
strcpy_P(log, PSTR("HTTP : Unauthorized"));
|
||||
}
|
||||
else if (line.substring(0, 25) == "HTTP/1.1 401 Unauthorized") {
|
||||
strcpy_P(log, PSTR("HTTP : Unauthorized"));
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
// data only
|
||||
if (data && line.startsWith("["))
|
||||
{
|
||||
String strValue = line;
|
||||
byte pos = strValue.indexOf('"',2);
|
||||
strValue = strValue.substring(2, pos);
|
||||
strValue.trim();
|
||||
float value = strValue.toFloat();
|
||||
*data = value;
|
||||
success = true;
|
||||
|
||||
char value_char[5] = {0};
|
||||
strValue.toCharArray(value_char, 5);
|
||||
sprintf_P(log, PSTR("Blynk get - %s => %s"),command.c_str(), value_char );
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
}
|
||||
yield();
|
||||
}
|
||||
strcpy_P(log, PSTR("HTTP : closing connection"));
|
||||
addLog(LOG_LEVEL_DEBUG, log);
|
||||
|
||||
client.flush();
|
||||
client.stop();
|
||||
|
||||
// important - backgroudtasks - free mem
|
||||
timer = millis() + Settings.MessageDelay;
|
||||
while (!timeOutReached(timer))
|
||||
backgroundtasks();
|
||||
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
//#######################################################################################################
|
||||
//########################### Controller Plugin 013: ESPEasy P2P network ################################
|
||||
//#######################################################################################################
|
||||
|
||||
#define CPLUGIN_013
|
||||
#define CPLUGIN_ID_013 13
|
||||
#define CPLUGIN_NAME_013 "ESPEasy P2P Networking"
|
||||
|
||||
WiFiUDP C013_portUDP;
|
||||
|
||||
struct infoStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 3;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
byte deviceNumber;
|
||||
char taskName[26];
|
||||
char ValueNames[VARS_PER_TASK][26];
|
||||
};
|
||||
|
||||
struct dataStruct
|
||||
{
|
||||
byte header = 255;
|
||||
byte ID = 5;
|
||||
byte sourcelUnit;
|
||||
byte destUnit;
|
||||
byte sourceTaskIndex;
|
||||
byte destTaskIndex;
|
||||
float Values[VARS_PER_TASK];
|
||||
};
|
||||
|
||||
|
||||
boolean CPlugin_013(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
boolean success = false;
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case CPLUGIN_PROTOCOL_ADD:
|
||||
{
|
||||
Protocol[++protocolCount].Number = CPLUGIN_ID_013;
|
||||
Protocol[protocolCount].usesMQTT = false;
|
||||
Protocol[protocolCount].usesTemplate = false;
|
||||
Protocol[protocolCount].usesAccount = false;
|
||||
Protocol[protocolCount].usesPassword = false;
|
||||
Protocol[protocolCount].defaultPort = 65501;
|
||||
Protocol[protocolCount].usesID = false;
|
||||
Protocol[protocolCount].Custom = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_GET_DEVICENAME:
|
||||
{
|
||||
string = F(CPLUGIN_NAME_013);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_TEMPLATE:
|
||||
{
|
||||
event->String1 = "";
|
||||
event->String2 = "";
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_INIT:
|
||||
{
|
||||
//C013_portUDP.begin(Settings.UDPPort);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_TASK_CHANGE_NOTIFICATION:
|
||||
{
|
||||
C013_SendUDPTaskInfo(0, event->TaskIndex, event->TaskIndex);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
C013_Send(event, 0, UserVar[event->BaseVarIndex], 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case CPLUGIN_UDP_IN:
|
||||
{
|
||||
C013_Receive(event);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
// Generic UDP message
|
||||
//********************************************************************************
|
||||
void C013_Send(struct EventStruct *event, byte varIndex, float value, unsigned long longValue)
|
||||
{
|
||||
ControllerSettingsStruct ControllerSettings;
|
||||
LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings));
|
||||
statusLED(true);
|
||||
C013_SendUDPTaskData(0, event->TaskIndex, event->TaskIndex);
|
||||
}
|
||||
|
||||
void C013_SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
struct infoStruct infoReply;
|
||||
infoReply.sourcelUnit = Settings.Unit;
|
||||
infoReply.sourceTaskIndex = sourceTaskIndex;
|
||||
infoReply.destTaskIndex = destTaskIndex;
|
||||
LoadTaskSettings(infoReply.sourceTaskIndex);
|
||||
infoReply.deviceNumber = Settings.TaskDeviceNumber[infoReply.sourceTaskIndex];
|
||||
strcpy(infoReply.taskName, ExtraTaskSettings.TaskDeviceName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x]);
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
if (x != Settings.Unit){
|
||||
infoReply.destUnit = x;
|
||||
C013_sendUDP(x, (byte*)&infoReply, sizeof(infoStruct));
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void C013_SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskIndex)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
struct dataStruct dataReply;
|
||||
dataReply.sourcelUnit = Settings.Unit;
|
||||
dataReply.sourceTaskIndex = sourceTaskIndex;
|
||||
dataReply.destTaskIndex = destTaskIndex;
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
dataReply.Values[x] = UserVar[dataReply.sourceTaskIndex * VARS_PER_TASK + x];
|
||||
|
||||
byte firstUnit = 1;
|
||||
byte lastUnit = UNIT_MAX - 1;
|
||||
if (destUnit != 0)
|
||||
{
|
||||
firstUnit = destUnit;
|
||||
lastUnit = destUnit;
|
||||
}
|
||||
for (byte x = firstUnit; x <= lastUnit; x++)
|
||||
{
|
||||
if (x != Settings.Unit){
|
||||
dataReply.destUnit = x;
|
||||
C013_sendUDP(x, (byte*) &dataReply, sizeof(dataStruct));
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
Send UDP message (unit 255=broadcast)
|
||||
\*********************************************************************************************/
|
||||
void C013_sendUDP(byte unit, byte* data, byte size)
|
||||
{
|
||||
if (!WiFiConnected(100)) {
|
||||
return;
|
||||
}
|
||||
if (unit != 255)
|
||||
if (Nodes[unit].ip[0] == 0)
|
||||
return;
|
||||
String log = "C013 : Send UDP message to ";
|
||||
log += unit;
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
|
||||
statusLED(true);
|
||||
|
||||
IPAddress remoteNodeIP;
|
||||
if (unit == 255)
|
||||
remoteNodeIP = {255, 255, 255, 255};
|
||||
else
|
||||
remoteNodeIP = Nodes[unit].ip;
|
||||
C013_portUDP.beginPacket(remoteNodeIP, Settings.UDPPort);
|
||||
C013_portUDP.write(data, size);
|
||||
C013_portUDP.endPacket();
|
||||
}
|
||||
|
||||
void C013_Receive(struct EventStruct *event) {
|
||||
|
||||
if (event->Data[1] > 1 && event->Data[1] < 6)
|
||||
{
|
||||
String log = (F("C013 : msg "));
|
||||
for (byte x = 1; x < 6; x++)
|
||||
{
|
||||
log += " ";
|
||||
log += (int)event->Data[x];
|
||||
}
|
||||
addLog(LOG_LEVEL_DEBUG_MORE, log);
|
||||
}
|
||||
|
||||
switch (event->Data[1]) {
|
||||
case 2: // sensor info pull request
|
||||
{
|
||||
//SendUDPTaskInfo(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: // sensor info
|
||||
{
|
||||
struct infoStruct infoReply;
|
||||
memcpy((byte*)&infoReply, (byte*)event->Data, sizeof(infoStruct));
|
||||
|
||||
// to prevent flash wear out (bugs in communication?) we can only write to an empty task
|
||||
// so it will write only once and has to be cleared manually through webgui
|
||||
if (Settings.TaskDeviceNumber[infoReply.destTaskIndex] == 0)
|
||||
{
|
||||
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
|
||||
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed
|
||||
for (byte x = 0; x < CONTROLLER_MAX; x++)
|
||||
Settings.TaskDeviceSendData[x][infoReply.destTaskIndex] = false;
|
||||
strcpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName);
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
strcpy( ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x]);
|
||||
SaveTaskSettings(infoReply.destTaskIndex);
|
||||
SaveSettings();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: // sensor data pull request
|
||||
{
|
||||
//SendUDPTaskData(packetBuffer[2], packetBuffer[5], packetBuffer[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: // sensor data
|
||||
{
|
||||
struct dataStruct dataReply;
|
||||
memcpy((byte*)&dataReply, (byte*)event->Data, sizeof(dataStruct));
|
||||
|
||||
// only if this task has a remote feed, update values
|
||||
if (Settings.TaskDeviceDataFeed[dataReply.destTaskIndex] != 0)
|
||||
{
|
||||
for (byte x = 0; x < VARS_PER_TASK; x++)
|
||||
{
|
||||
UserVar[dataReply.destTaskIndex * VARS_PER_TASK + x] = dataReply.Values[x];
|
||||
}
|
||||
if (Settings.UseRules)
|
||||
createRuleEvents(dataReply.destTaskIndex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
// HUM_STAT can be one of:
|
||||
// 0=Normal
|
||||
// 1=Comfortable
|
||||
// 2=Dry
|
||||
// 3=Wet
|
||||
String humStatDomoticz(struct EventStruct *event, byte rel_index){
|
||||
const int hum = UserVar[event->BaseVarIndex + rel_index];
|
||||
if (hum < 30) { return formatUserVarDomoticz(2); }
|
||||
if (hum < 40) { return formatUserVarDomoticz(0); }
|
||||
if (hum < 59) { return formatUserVarDomoticz(1); }
|
||||
return formatUserVarDomoticz(3);
|
||||
}
|
||||
|
||||
int mapRSSItoDomoticz() {
|
||||
long rssi = WiFi.RSSI();
|
||||
if (-50 < rssi) { return 10; }
|
||||
if (rssi <= -98) { return 0; }
|
||||
rssi = rssi + 97; // Range 0..47 => 1..9
|
||||
return (rssi / 5) + 1;
|
||||
}
|
||||
|
||||
int mapVccToDomoticz() {
|
||||
#if FEATURE_ADC_VCC
|
||||
// Voltage range from 2.6V .. 3.6V => 0..100%
|
||||
if (vcc < 2.6) return 0;
|
||||
return (vcc - 2.6) * 100;
|
||||
#else
|
||||
return 255;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Format including trailing semi colon
|
||||
String formatUserVarDomoticz(struct EventStruct *event, byte rel_index) {
|
||||
String text = formatUserVar(event, rel_index);
|
||||
text += F(";");
|
||||
return text;
|
||||
}
|
||||
|
||||
String formatUserVarDomoticz(int value) {
|
||||
String text;
|
||||
text += value;
|
||||
text.trim();
|
||||
text += F(";");
|
||||
return text;
|
||||
}
|
||||
|
||||
String formatDomoticzSensorType(struct EventStruct *event) {
|
||||
String values;
|
||||
switch (event->sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
|
||||
values = formatUserVarDomoticz(event, 0);
|
||||
break;
|
||||
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
|
||||
values = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16);
|
||||
break;
|
||||
case SENSOR_TYPE_DUAL: // any sensor that uses two simple values
|
||||
values = formatUserVarDomoticz(event, 0);
|
||||
values += formatUserVarDomoticz(event, 1);
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM:
|
||||
// temp + hum + hum_stat, used for DHT11
|
||||
// http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Temperature.2Fhumidity
|
||||
values = formatUserVarDomoticz(event, 0); // TEMP = Temperature
|
||||
values += formatUserVarDomoticz(event, 1); // HUM = Humidity
|
||||
values += humStatDomoticz(event, 1); // HUM_STAT = Humidity status
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO:
|
||||
// temp + hum + hum_stat + bar + bar_fore, used for BME280
|
||||
// http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Temperature.2Fhumidity.2Fbarometer
|
||||
values = formatUserVarDomoticz(event, 0); // TEMP = Temperature
|
||||
values += formatUserVarDomoticz(event, 1); // HUM = Humidity
|
||||
values += humStatDomoticz(event, 1); // HUM_STAT = Humidity status
|
||||
values += formatUserVarDomoticz(event, 2); // BAR = Barometric pressure
|
||||
values += formatUserVarDomoticz(0); // BAR_FOR = Barometer forecast
|
||||
break;
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
// temp + hum + hum_stat + bar + bar_fore, used for BMP085
|
||||
// http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Temperature.2Fbarometer
|
||||
values = formatUserVarDomoticz(event, 0); // TEMP = Temperature
|
||||
values += formatUserVarDomoticz(event, 1); // BAR = Barometric pressure
|
||||
values += formatUserVarDomoticz(0); // BAR_FOR = Barometer forecast
|
||||
values += formatUserVarDomoticz(0); // ALTITUDE= Not used at the moment, can be 0
|
||||
break;
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
values = formatUserVarDomoticz(event, 0);
|
||||
values += formatUserVarDomoticz(event, 1);
|
||||
values += formatUserVarDomoticz(event, 2);
|
||||
break;
|
||||
case SENSOR_TYPE_QUAD:
|
||||
values = formatUserVarDomoticz(event, 0);
|
||||
values += formatUserVarDomoticz(event, 1);
|
||||
values += formatUserVarDomoticz(event, 2);
|
||||
values += formatUserVarDomoticz(event, 3);
|
||||
break;
|
||||
case SENSOR_TYPE_WIND:
|
||||
// WindDir in degrees; WindDir as text; Wind speed average ; Wind speed gust; 0
|
||||
// http://www.domoticz.com/wiki/Domoticz_API/JSON_URL%27s#Wind
|
||||
values = formatUserVarDomoticz(event, 0); // WB = Wind bearing (0-359)
|
||||
values += getBearing(UserVar[event->BaseVarIndex]); // WD = Wind direction (S, SW, NNW, etc.)
|
||||
values += ";"; // Needed after getBearing
|
||||
// Domoticz expects the wind speed in (m/s * 10)
|
||||
values += toString((UserVar[event->BaseVarIndex + 1] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[1]);
|
||||
values += ";"; // WS = 10 * Wind speed [m/s]
|
||||
values += toString((UserVar[event->BaseVarIndex + 2] * 10),ExtraTaskSettings.TaskDeviceValueDecimals[2]);
|
||||
values += ";"; // WG = 10 * Gust [m/s]
|
||||
values += formatUserVarDomoticz(0); // Temperature
|
||||
values += formatUserVarDomoticz(0); // Temperature Windchill
|
||||
break;
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
case SENSOR_TYPE_DIMMER:
|
||||
// Too specific for HTTP/MQTT
|
||||
break;
|
||||
default:
|
||||
{
|
||||
String log = F("Domoticz Controller: Not yet implemented sensor type: ");
|
||||
log += event->sensorType;
|
||||
log += F(" idx: ");
|
||||
log += event->idx;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Now strip trailing semi colon.
|
||||
int index_last_char = values.length() -1;
|
||||
if (index_last_char > 0 && values.charAt(index_last_char) == ';') {
|
||||
values.setCharAt(index_last_char, ' ');
|
||||
}
|
||||
values.trim();
|
||||
{
|
||||
String log = F(" Domoticz: Sensortype: ");
|
||||
log += event->sensorType;
|
||||
log += F(" idx: ");
|
||||
log += event->idx;
|
||||
log += F(" values: ");
|
||||
log += values;
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*********************************************************************************************\
|
||||
Get value count from sensor type
|
||||
\*********************************************************************************************/
|
||||
|
||||
byte getValueCountFromSensorType(byte sensorType)
|
||||
{
|
||||
switch (sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc
|
||||
case SENSOR_TYPE_SWITCH:
|
||||
case SENSOR_TYPE_DIMMER:
|
||||
return 1;
|
||||
case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags)
|
||||
return 1;
|
||||
case SENSOR_TYPE_TEMP_HUM:
|
||||
case SENSOR_TYPE_TEMP_BARO:
|
||||
case SENSOR_TYPE_DUAL:
|
||||
return 2;
|
||||
case SENSOR_TYPE_TEMP_HUM_BARO:
|
||||
case SENSOR_TYPE_TRIPLE:
|
||||
case SENSOR_TYPE_WIND:
|
||||
return 3;
|
||||
case SENSOR_TYPE_QUAD:
|
||||
return 4;
|
||||
}
|
||||
addLog(LOG_LEVEL_ERROR, F("getValueCountFromSensorType: Unknown sensortype"));
|
||||
return 0;
|
||||
}
|
||||
+54
-25
@@ -6,7 +6,7 @@
|
||||
#define NPLUGIN_ID_001 1
|
||||
#define NPLUGIN_NAME_001 "Email (SMTP)"
|
||||
|
||||
#define NPLUGIN_001_TIMEOUT 3000
|
||||
#define NPLUGIN_001_TIMEOUT 5000
|
||||
|
||||
boolean NPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
{
|
||||
@@ -56,7 +56,7 @@ boolean NPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
body = NotificationSettings.Body;
|
||||
subject = parseTemplate(subject, subject.length());
|
||||
body = parseTemplate(body, body.length());
|
||||
NPlugin_001_send(NotificationSettings.Domain, NotificationSettings.Receiver, NotificationSettings.Sender, subject, body, NotificationSettings.Server, NotificationSettings.Port);
|
||||
NPlugin_001_send(NotificationSettings, subject, body);
|
||||
success = true;
|
||||
}
|
||||
|
||||
@@ -64,29 +64,46 @@ boolean NPlugin_001(byte function, struct EventStruct *event, String& string)
|
||||
return success;
|
||||
}
|
||||
|
||||
boolean NPlugin_001_send(String aDomain , String aTo, String aFrom, String aSub, String aMesg, String aHost, int aPort)
|
||||
{
|
||||
boolean NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, const String& aSub, const String& aMesg) {
|
||||
// String& aDomain , String aTo, String aFrom, String aSub, String aMesg, String aHost, int aPort)
|
||||
boolean myStatus = false;
|
||||
|
||||
// Use WiFiClient class to create TCP connections
|
||||
WiFiClient client;
|
||||
addLog(LOG_LEVEL_DEBUG, String(F("EMAIL: Connecting to "))+aHost);
|
||||
if (!client.connect(aHost.c_str(), aPort)) {
|
||||
addLog(LOG_LEVEL_ERROR, String(F("EMAIL: Error connecting to "))+aHost);
|
||||
String aHost = notificationsettings.Server;
|
||||
addLog(LOG_LEVEL_DEBUG, String(F("EMAIL: Connecting to "))+aHost + notificationsettings.Port);
|
||||
if (!client.connect(aHost.c_str(), notificationsettings.Port)) {
|
||||
addLog(LOG_LEVEL_ERROR, String(F("EMAIL: Error connecting to "))+aHost + notificationsettings.Port);
|
||||
myStatus = false;
|
||||
}
|
||||
else {
|
||||
String mailheader = F(
|
||||
"From: $nodename <$emailfrom>\r\n"
|
||||
"To: $ato\r\n"
|
||||
"Subject: $subject\r\n"
|
||||
"Reply-To: $nodename <$emailfrom>\r\n"
|
||||
"MIME-VERSION: 1.0\r\n"
|
||||
"Content-type: text/html; charset=UTF-8\r\n"
|
||||
"X-Mailer: EspEasy v$espeasyversion\r\n\r\n"
|
||||
);
|
||||
|
||||
mailheader.replace(String(F("$nodename")), Settings.Name);
|
||||
mailheader.replace(String(F("$emailfrom")), notificationsettings.Sender);
|
||||
mailheader.replace(String(F("$ato")), notificationsettings.Receiver);
|
||||
mailheader.replace(String(F("$subject")), aSub);
|
||||
mailheader.replace(String(F("$espeasyversion")), String(BUILD));
|
||||
|
||||
// Wait for Client to Start Sending
|
||||
// The MTA Exchange
|
||||
while (true) {
|
||||
|
||||
if (NPlugin_001_MTA(client, "", F("220 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, String(F("EHLO ")) + aDomain, F("250 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, String(F("MAIL FROM:")) + aFrom + "", F("250 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, String(F("RCPT TO:")) + aTo + "", F("250 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, F("DATA"), F("354 ")) == false) break;
|
||||
if (NPlugin_001_MTA(client, String(F("Subject:")) + aSub + F("\r\n\r\n") + aMesg + F("\r\n.\r\n"), F("250 ")) == false) break;
|
||||
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, F("DATA"), F("354 "))) break;
|
||||
if (!NPlugin_001_MTA(client, mailheader + aMesg + String(F("\r\n.\r\n")), F("250 "))) break;
|
||||
|
||||
myStatus = true;
|
||||
break;
|
||||
@@ -100,21 +117,32 @@ boolean NPlugin_001_send(String aDomain , String aTo, String aFrom, String aSub,
|
||||
addLog(LOG_LEVEL_INFO, F("EMAIL: Connection Closed Successfully"));
|
||||
}
|
||||
else {
|
||||
addLog(LOG_LEVEL_ERROR, F("EMAIL: Connection Closed With Error"));
|
||||
String log = F("EMAIL: Connection Closed With Error. Used header: ");
|
||||
log += mailheader;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return myStatus;
|
||||
|
||||
}
|
||||
|
||||
boolean NPlugin_001_Auth(WiFiClient& client, String user, String pass) {
|
||||
if (user.length() == 0 || pass.length() == 0) {
|
||||
// No user/password given.
|
||||
return true;
|
||||
}
|
||||
if (!NPlugin_001_MTA(client, String(F("AUTH LOGIN")), F("334 "))) return false;
|
||||
base64 encoder;
|
||||
String auth;
|
||||
auth = encoder.encode(user);
|
||||
if (!NPlugin_001_MTA(client, auth, F("334 "))) return false;
|
||||
auth = encoder.encode(pass);
|
||||
if (!NPlugin_001_MTA(client, auth, F("235 "))) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean NPlugin_001_MTA(WiFiClient& client, String aStr, const String &aWaitForPattern)
|
||||
{
|
||||
|
||||
boolean myStatus = false;
|
||||
|
||||
addLog(LOG_LEVEL_DEBUG, aStr);
|
||||
|
||||
if (aStr.length() ) client.println(aStr);
|
||||
@@ -125,8 +153,10 @@ boolean NPlugin_001_MTA(WiFiClient& client, String aStr, const String &aWaitForP
|
||||
unsigned long timer = millis() + NPLUGIN_001_TIMEOUT;
|
||||
while (true) {
|
||||
if (timeOutReached(timer)) {
|
||||
myStatus = false;
|
||||
break;
|
||||
String log = F("Plugin_001_MTA: timeout. ");
|
||||
log += aStr;
|
||||
addLog(LOG_LEVEL_ERROR, log);
|
||||
return false;
|
||||
}
|
||||
|
||||
yield();
|
||||
@@ -138,10 +168,9 @@ boolean NPlugin_001_MTA(WiFiClient& client, String aStr, const String &aWaitForP
|
||||
addLog(LOG_LEVEL_DEBUG, line);
|
||||
|
||||
if (line.indexOf(aWaitForPattern) >= 0) {
|
||||
myStatus = true;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return myStatus;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,10 @@ boolean NPlugin_002(byte function, struct EventStruct *event, String& string)
|
||||
NotificationSettingsStruct NotificationSettings;
|
||||
LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettings));
|
||||
//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;
|
||||
}
|
||||
|
||||
|
||||
+89
-15
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P001
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 001: Input Switch #########################################
|
||||
//#######################################################################################################
|
||||
@@ -10,10 +11,10 @@
|
||||
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 1
|
||||
#define PLUGIN_001_TYPE_DIMMER 3 // Due to some changes in previous versions, do not use 2.
|
||||
#define PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH 0
|
||||
#define PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW 1
|
||||
#define PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH 2
|
||||
@@ -27,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)
|
||||
{
|
||||
@@ -61,23 +64,21 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
if (choice != PLUGIN_001_TYPE_SWITCH && choice != PLUGIN_001_TYPE_DIMMER)
|
||||
choice = PLUGIN_001_TYPE_SWITCH;
|
||||
String options[2];
|
||||
options[0] = F("Switch");
|
||||
options[1] = F("Dimmer");
|
||||
int optionValues[2] = { PLUGIN_001_TYPE_SWITCH, PLUGIN_001_TYPE_DIMMER };
|
||||
addFormSelector(string, F("Switch Type"), F("plugin_001_type"), 2, options, optionValues, choice);
|
||||
const byte switchtype = P001_getSwitchType(event);
|
||||
addFormSelector(string, F("Switch Type"), F("plugin_001_type"), 2, options, optionValues, switchtype);
|
||||
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == PLUGIN_001_TYPE_DIMMER)
|
||||
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;
|
||||
}
|
||||
|
||||
choice = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
|
||||
byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
|
||||
String buttonOptions[3];
|
||||
buttonOptions[0] = F("Normal Switch");
|
||||
buttonOptions[1] = F("Push Button Active Low");
|
||||
@@ -110,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
|
||||
@@ -130,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);
|
||||
@@ -162,7 +200,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
byte output_value = sendState ? 1 : 0;
|
||||
event->sensorType = SENSOR_TYPE_SWITCH;
|
||||
if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == PLUGIN_001_TYPE_DIMMER) {
|
||||
if (P001_getSwitchType(event) == PLUGIN_001_TYPE_DIMMER) {
|
||||
if (sendState) {
|
||||
output_value = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
|
||||
// Only set type to being dimmer when setting a value else it is "switched off".
|
||||
@@ -203,9 +241,14 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
success = true;
|
||||
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));
|
||||
@@ -275,16 +318,19 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
}
|
||||
|
||||
if (command == F("longpulse"))
|
||||
if ((command == F("longpulse")) || (command == F("longpulse_ms")))
|
||||
{
|
||||
boolean time_in_msec = command == F("longpulse_ms");
|
||||
success = true;
|
||||
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);
|
||||
setSystemTimer(event->Par3 * 1000, PLUGIN_ID_001, event->Par1, !event->Par2, 0);
|
||||
log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Pulse set for ")) + String(event->Par3) + String(F(" S"));
|
||||
setSystemTimer(time_in_msec ? event->Par3 : event->Par3 * 1000,
|
||||
PLUGIN_ID_001, event->Par1, !event->Par2, 0);
|
||||
log = String(F("SW : GPIO ")) + String(event->Par1) +
|
||||
String(F(" Pulse set for ")) + String(event->Par3) + String(time_in_msec ? F(" msec") : F(" sec"));
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0));
|
||||
}
|
||||
@@ -326,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;
|
||||
@@ -383,6 +438,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string)
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
#if defined(ESP32)
|
||||
void analogWriteESP32(int pin, int value)
|
||||
{
|
||||
@@ -408,3 +464,21 @@ void analogWriteESP32(int pin, int value)
|
||||
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];
|
||||
switch (choice) {
|
||||
case 2: // Old implementation for Dimmer
|
||||
case PLUGIN_001_TYPE_DIMMER:
|
||||
choice = PLUGIN_001_TYPE_DIMMER;
|
||||
break;
|
||||
case 1: // Old implementation for switch
|
||||
case PLUGIN_001_TYPE_SWITCH:
|
||||
default:
|
||||
choice = PLUGIN_001_TYPE_SWITCH;
|
||||
break;
|
||||
}
|
||||
return choice;
|
||||
}
|
||||
#endif // USES_P001
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P002
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 002: Analog ###############################################
|
||||
//#######################################################################################################
|
||||
@@ -150,3 +151,4 @@ boolean Plugin_002(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif // USES_P002
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P003
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 003: Pulse ###############################################
|
||||
//#######################################################################################################
|
||||
@@ -267,3 +268,4 @@ bool Plugin_003_pulseinit(byte Par1, byte Index, byte Mode)
|
||||
|
||||
return(true);
|
||||
}
|
||||
#endif // USES_P003
|
||||
|
||||
+97
-55
@@ -1,15 +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)
|
||||
{
|
||||
@@ -49,46 +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(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 ++;
|
||||
// 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");
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -100,13 +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")));
|
||||
Plugin_004_DS_startConvertion(addr);
|
||||
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;
|
||||
}
|
||||
@@ -117,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;
|
||||
@@ -127,10 +146,7 @@ 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;
|
||||
@@ -166,6 +182,15 @@ 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
|
||||
\*********************************************************************************************/
|
||||
@@ -355,7 +380,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
|
||||
{
|
||||
@@ -371,7 +398,9 @@ uint8_t Plugin_004_DS_reset()
|
||||
delayMicroseconds(40);
|
||||
r = !digitalRead(Plugin_004_DallasPin);
|
||||
delayMicroseconds(420);
|
||||
// interrupts();
|
||||
#if defined(ESP32)
|
||||
ESP32interrupts();
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -553,14 +582,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;
|
||||
}
|
||||
@@ -572,22 +605,30 @@ 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);
|
||||
}
|
||||
}
|
||||
@@ -613,3 +654,4 @@ boolean Plugin_004_DS_crc8(uint8_t * addr)
|
||||
}
|
||||
return crc == *addr; // addr 8
|
||||
}
|
||||
#endif // USES_P004
|
||||
|
||||
+101
-83
@@ -1,10 +1,11 @@
|
||||
#ifdef USES_P005
|
||||
//#######################################################################################################
|
||||
//######################## Plugin 005: Temperature and Humidity sensor DHT 11/22 ########################
|
||||
//#######################################################################################################
|
||||
|
||||
#define PLUGIN_005
|
||||
#define PLUGIN_ID_005 5
|
||||
#define PLUGIN_NAME_005 "Environment - DHT11/12/22"
|
||||
#define PLUGIN_NAME_005 "Environment - DHT11/12/22 SONOFF2301/7021"
|
||||
#define PLUGIN_VALUENAME1_005 "Temperature"
|
||||
#define PLUGIN_VALUENAME2_005 "Humidity"
|
||||
|
||||
@@ -47,10 +48,10 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD:
|
||||
{
|
||||
const String options[] = { F("DHT 11"), F("DHT 22"), F("DHT 12") };
|
||||
int indices[] = { 11, 22, 12 };
|
||||
const String options[] = { F("DHT 11"), F("DHT 22"), F("DHT 12"), F("Sonoff am2301"), F("Sonoff si7021") };
|
||||
int indices[] = { 11, 22, 12, 23, 70 };
|
||||
|
||||
addFormSelector(string, F("DHT Type"), F("plugin_005_dhttype"), 3, options, indices, Settings.TaskDevicePluginConfig[event->TaskIndex][0] );
|
||||
addFormSelector(string, F("DHT Type"), F("plugin_005_dhttype"), 5, options, indices, Settings.TaskDevicePluginConfig[event->TaskIndex][0] );
|
||||
|
||||
success = true;
|
||||
break;
|
||||
@@ -67,96 +68,91 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
|
||||
case PLUGIN_READ:
|
||||
{
|
||||
byte dht_dat[5];
|
||||
byte dht_in;
|
||||
byte i;
|
||||
// byte Retry = 0;
|
||||
boolean error = false;
|
||||
|
||||
byte Par3 = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
|
||||
Plugin_005_DHT_Pin = Settings.TaskDevicePin1[event->TaskIndex];
|
||||
|
||||
pinMode(Plugin_005_DHT_Pin, OUTPUT);
|
||||
// DHT start condition, pull-down i/o pin for 18ms
|
||||
digitalWrite(Plugin_005_DHT_Pin, LOW); // Pull low
|
||||
delay(18);
|
||||
digitalWrite(Plugin_005_DHT_Pin, HIGH); // Pull high
|
||||
delayMicroseconds(20); // was 40
|
||||
if(Par3 == 11 || Par3 == 22 || Par3 == 12) delay(18);
|
||||
else if (Par3 == 23 ) delayMicroseconds(900);
|
||||
else if (Par3 == 70 ) delayMicroseconds(500);
|
||||
pinMode(Plugin_005_DHT_Pin, INPUT); // change pin to input
|
||||
delayMicroseconds(10);
|
||||
delayMicroseconds(50);
|
||||
|
||||
dht_in = digitalRead(Plugin_005_DHT_Pin);
|
||||
if (!dht_in)
|
||||
error = waitState(0);
|
||||
if(error)
|
||||
{ logError(event, F("DHT : no Reading !"));
|
||||
break;
|
||||
}
|
||||
error = waitState(1);
|
||||
if(error)
|
||||
{ logError(event, F("DHT : no Reading !"));
|
||||
break;
|
||||
}
|
||||
noInterrupts();
|
||||
error = waitState(0);
|
||||
if(error)
|
||||
{ logError(event, F("DHT : no Reading !"));
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
delayMicroseconds(80);
|
||||
dht_in = digitalRead(Plugin_005_DHT_Pin);
|
||||
if (dht_in)
|
||||
{
|
||||
delayMicroseconds(80); // now ready for data reception
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
byte data = Plugin_005_read_dht_dat();
|
||||
if (data != -1)
|
||||
dht_dat[i] = data;
|
||||
else
|
||||
{
|
||||
addLog(LOG_LEVEL_ERROR, F("DHT : protocol timeout!"));
|
||||
error = true;
|
||||
}
|
||||
byte data = Plugin_005_read_dht_dat();
|
||||
if(data == -1)
|
||||
{ logError(event, "DHT : protocol timeout!");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!error)
|
||||
{
|
||||
dht_dat[i] = data;
|
||||
}
|
||||
interrupts();
|
||||
|
||||
// Checksum calculation is a Rollover Checksum by design!
|
||||
byte dht_check_sum = dht_dat[0] + dht_dat[1] + dht_dat[2] + dht_dat[3]; // check check_sum
|
||||
|
||||
if (dht_dat[4] == dht_check_sum)
|
||||
{
|
||||
float temperature = NAN;
|
||||
float humidity = NAN;
|
||||
|
||||
if (Par3 == 11)
|
||||
{
|
||||
temperature = float(dht_dat[2]); // Temperature
|
||||
humidity = float(dht_dat[0]); // Humidity
|
||||
}
|
||||
else if (Par3 == 12)
|
||||
{
|
||||
temperature = float(dht_dat[2]*10 + (dht_dat[3] & 0x7f)) / 10.0; // Temperature
|
||||
if (dht_dat[3] & 0x80) { temperature = -temperature; } // Negative temperature
|
||||
humidity = float(dht_dat[0]*10+dht_dat[1]) / 10.0; // Humidity
|
||||
}
|
||||
|
||||
if (Par3 == 22)
|
||||
{
|
||||
if (dht_dat[2] & 0x80) // negative temperature
|
||||
temperature = -0.1 * word(dht_dat[2] & 0x7F, dht_dat[3]);
|
||||
else
|
||||
temperature = 0.1 * word(dht_dat[2], dht_dat[3]);
|
||||
humidity = word(dht_dat[0], dht_dat[1]) * 0.1; // Humidity
|
||||
}
|
||||
if (temperature != NAN || humidity != NAN) // According to negated original if, maybe use && instead?
|
||||
{
|
||||
UserVar[event->BaseVarIndex] = temperature;
|
||||
UserVar[event->BaseVarIndex + 1] = humidity;
|
||||
String log = F("DHT : Temperature: ");
|
||||
log += UserVar[event->BaseVarIndex];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
log = F("DHT : Humidity: ");
|
||||
log += UserVar[event->BaseVarIndex + 1];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
}
|
||||
} // checksum
|
||||
} // error
|
||||
} // dht
|
||||
} // !dht
|
||||
if(!success)
|
||||
byte dht_check_sum = (dht_dat[0] + dht_dat[1] + dht_dat[2] + dht_dat[3]) & 0xFF; // check check_sum
|
||||
if (dht_dat[4] != dht_check_sum)
|
||||
{
|
||||
addLog(LOG_LEVEL_INFO, F("DHT : No reading!"));
|
||||
UserVar[event->BaseVarIndex] = NAN;
|
||||
UserVar[event->BaseVarIndex + 1] = NAN;
|
||||
logError(event, "DHT : checksum error!");
|
||||
break;
|
||||
}
|
||||
|
||||
float temperature = NAN;
|
||||
float humidity = NAN;
|
||||
if (Par3 == 11)
|
||||
{
|
||||
temperature = float(dht_dat[2]); // Temperature
|
||||
humidity = float(dht_dat[0]); // Humidity
|
||||
}
|
||||
else if (Par3 == 12)
|
||||
{
|
||||
temperature = float(dht_dat[2]*10 + (dht_dat[3] & 0x7f)) / 10.0; // Temperature
|
||||
if (dht_dat[3] & 0x80) { temperature = -temperature; } // Negative temperature
|
||||
humidity = float(dht_dat[0]*10+dht_dat[1]) / 10.0; // Humidity
|
||||
}
|
||||
else if (Par3 == 22 || Par3 == 23 || Par3 == 70)
|
||||
{
|
||||
if (dht_dat[2] & 0x80) // negative temperature
|
||||
temperature = -0.1 * word(dht_dat[2] & 0x7F, dht_dat[3]);
|
||||
else
|
||||
temperature = 0.1 * word(dht_dat[2], dht_dat[3]);
|
||||
humidity = 0.1 * word(dht_dat[0], dht_dat[1]); // Humidity
|
||||
}
|
||||
|
||||
if (temperature == NAN || humidity == NAN)
|
||||
{ logError(event, "DHT : invalid NAN reading !");
|
||||
break;
|
||||
}
|
||||
|
||||
UserVar[event->BaseVarIndex] = temperature;
|
||||
UserVar[event->BaseVarIndex + 1] = humidity;
|
||||
String log = F("DHT : Temperature: ");
|
||||
log += UserVar[event->BaseVarIndex];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
log = F("DHT : Humidity: ");
|
||||
log += UserVar[event->BaseVarIndex + 1];
|
||||
addLog(LOG_LEVEL_INFO, log);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -164,6 +160,31 @@ boolean Plugin_005(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* DHT sub to log an error
|
||||
\*********************************************************************************************/
|
||||
void logError(struct EventStruct *event, String text)
|
||||
{
|
||||
addLog(LOG_LEVEL_INFO, text);
|
||||
UserVar[event->BaseVarIndex] = NAN;
|
||||
UserVar[event->BaseVarIndex + 1] = NAN;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* DHT sub to wait until a pin is in a certiin state
|
||||
\*********************************************************************************************/
|
||||
boolean waitState(int state)
|
||||
{
|
||||
byte counter = 0;
|
||||
while (( digitalRead(Plugin_005_DHT_Pin) != state) && (counter < 100))
|
||||
{
|
||||
delayMicroseconds(1);
|
||||
counter++;
|
||||
}
|
||||
if( counter < 100) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* DHT sub to get an 8 bit value from the receiving bitstream
|
||||
\*********************************************************************************************/
|
||||
@@ -172,7 +193,6 @@ int Plugin_005_read_dht_dat(void)
|
||||
byte i = 0;
|
||||
byte result = 0;
|
||||
byte counter = 0;
|
||||
//noInterrupts();
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
while ((!digitalRead(Plugin_005_DHT_Pin)) && (counter < 100))
|
||||
@@ -182,10 +202,9 @@ int Plugin_005_read_dht_dat(void)
|
||||
}
|
||||
if (counter >= 100)
|
||||
{
|
||||
//interrupts();
|
||||
return -1;
|
||||
}
|
||||
delayMicroseconds(30);
|
||||
delayMicroseconds(35); // was 30
|
||||
if (digitalRead(Plugin_005_DHT_Pin))
|
||||
result |= (1 << (7 - i));
|
||||
counter = 0;
|
||||
@@ -196,10 +215,9 @@ int Plugin_005_read_dht_dat(void)
|
||||
}
|
||||
if (counter >= 100)
|
||||
{
|
||||
//interrupts();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
//interrupts();
|
||||
return result;
|
||||
}
|
||||
#endif // USES_P005
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P006
|
||||
//#######################################################################################################
|
||||
//######################## Plugin 006 BMP0685 I2C Barometric Pressure Sensor ###########################
|
||||
//#######################################################################################################
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P009
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 009: MCP23017 input #######################################
|
||||
//#######################################################################################################
|
||||
@@ -306,3 +307,4 @@ void Plugin_009_Config(byte Par1, byte Par2)
|
||||
Wire.endTransmission();
|
||||
}
|
||||
}
|
||||
#endif // USES_P009
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P010
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin-010: LuxRead ############################################
|
||||
//#######################################################################################################
|
||||
@@ -124,3 +125,4 @@ boolean Plugin_010(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
#endif // USES_P010
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#ifdef USES_P011
|
||||
//#######################################################################################################
|
||||
//#################################### Plugin 011: Pro Mini Extender ####################################
|
||||
//#######################################################################################################
|
||||
@@ -211,3 +212,4 @@ void Plugin_011_Write(byte Par1, byte Par2)
|
||||
Wire.write((Par2 >> 8));
|
||||
Wire.endTransmission();
|
||||
}
|
||||
#endif // USES_P011
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user