Compare commits
610 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71886c162b | ||
|
|
df1f516f6b | ||
|
|
2e55189d59 | ||
|
|
6ade40ce85 | ||
|
|
94c5f0d7a8 | ||
|
|
b1028086a3 | ||
|
|
385b3570b2 | ||
|
|
77edd12030 | ||
|
|
217fca31e4 | ||
|
|
5e1d20fc72 | ||
|
|
db60309ce8 | ||
|
|
6a5b757a24 | ||
|
|
a19098a004 | ||
|
|
ec10c29aca | ||
|
|
f90ab46794 | ||
|
|
b8ca97e019 | ||
|
|
e12757dbb9 | ||
|
|
3e9b44d193 | ||
|
|
3006d25406 | ||
|
|
f2ae9a0711 | ||
|
|
19945e4ccb | ||
|
|
61ab16acd6 | ||
|
|
3a84292f82 | ||
|
|
1d314294c7 | ||
|
|
b5b1dbfe85 | ||
|
|
5be88dd188 | ||
|
|
88b67b9541 | ||
|
|
a31da3186f | ||
|
|
9a7a38e913 | ||
|
|
a0960f5468 | ||
|
|
9b87a512cf | ||
|
|
8da985b6d0 | ||
|
|
5cb2a39746 | ||
|
|
6268cadc95 | ||
|
|
470b4b3972 | ||
|
|
a88ae2ca56 | ||
|
|
9875fbef0a | ||
|
|
cf29ddc8d0 | ||
|
|
ad70fcba7f | ||
|
|
a9a7720a11 | ||
|
|
8ff4f50f79 | ||
|
|
aea07f42d1 | ||
|
|
8d75c06852 | ||
|
|
ffbedbc1e6 | ||
|
|
a47d48c973 | ||
|
|
c54092c932 | ||
|
|
9134c3b4af | ||
|
|
7e21955211 | ||
|
|
40ac760285 | ||
|
|
de63bdac39 | ||
|
|
408d63825a | ||
|
|
3e1eb02f54 | ||
|
|
d2f55e1064 | ||
|
|
c97bead631 | ||
|
|
8264ca4e9e | ||
|
|
05bdaa4bc7 | ||
|
|
cc2de04f6b | ||
|
|
f99f13a090 | ||
|
|
f35ab125ec | ||
|
|
b8342f1c9c | ||
|
|
0ce77bbc59 | ||
|
|
e39eccb99e | ||
|
|
77ce67d685 | ||
|
|
ef125ff109 | ||
|
|
30e3bbd0e8 | ||
|
|
7bf1c35dcf | ||
|
|
c6ea2dff8a | ||
|
|
f2329476ec | ||
|
|
c4512b75d9 | ||
|
|
92e43abbc4 | ||
|
|
07d6bfa989 | ||
|
|
ccf5e66f31 | ||
|
|
6f5e71164a | ||
|
|
12131764d1 | ||
|
|
594c0b8550 | ||
|
|
ed729c32d2 | ||
|
|
ea26ee8d40 | ||
|
|
53f09c0630 | ||
|
|
2856e02eac | ||
|
|
a4f0c9195e | ||
|
|
0e73a0293b | ||
|
|
f4f5d6e562 | ||
|
|
e5c3629e2e | ||
|
|
5028471598 | ||
|
|
c28027496d | ||
|
|
c0f5509652 | ||
|
|
9bc48ececa | ||
|
|
1f53e4d4a2 | ||
|
|
dbef0e6583 | ||
|
|
c246e5af35 | ||
|
|
d36796429e | ||
|
|
37a31a9b94 | ||
|
|
c2ab3f96a7 | ||
|
|
ef36b5377d | ||
|
|
f12237d298 | ||
|
|
5b312d4c8b | ||
|
|
d21e82b020 | ||
|
|
c6e5606b4c | ||
|
|
7b4dc43147 | ||
|
|
62510ac6a3 | ||
|
|
bffe2d7bd0 | ||
|
|
cbaf1e576d | ||
|
|
0d355dbf35 | ||
|
|
d851bff762 | ||
|
|
453f4b549b | ||
|
|
8d669b12b6 | ||
|
|
ed3234d949 | ||
|
|
603a00376f | ||
|
|
4f34cfb654 | ||
|
|
fd1e536cdb | ||
|
|
0c6a880a74 | ||
|
|
89fa053310 | ||
|
|
267887908e | ||
|
|
b86f58befe | ||
|
|
b804101c24 | ||
|
|
f28502514f | ||
|
|
79da716a44 | ||
|
|
f76a440b74 | ||
|
|
18dad0c72c | ||
|
|
14a5ab6740 | ||
|
|
d0d56c4416 | ||
|
|
9dd9a01211 | ||
|
|
480e7f5b54 | ||
|
|
cffee7bfa7 | ||
|
|
5b9eda9c63 | ||
|
|
0a363d5fc0 | ||
|
|
9eb646085e | ||
|
|
e3269f6edc | ||
|
|
57d3120b45 | ||
|
|
81da8261a0 | ||
|
|
7e5949b4a9 | ||
|
|
a776b8ac31 | ||
|
|
14e19226ea | ||
|
|
5473b3e42e | ||
|
|
143179cac9 | ||
|
|
ad2c7ee363 | ||
|
|
755448f9f5 | ||
|
|
f304a6891f | ||
|
|
1221661ae3 | ||
|
|
a78f17abec | ||
|
|
70bf957a8a | ||
|
|
e8e04db7b4 | ||
|
|
d5def30c59 | ||
|
|
81176bc4e6 | ||
|
|
730ba12c8d | ||
|
|
80ad456d48 | ||
|
|
2d75526395 | ||
|
|
cd618a43d4 | ||
|
|
1979236f3a | ||
|
|
3589adcb78 | ||
|
|
4a834ecfc8 | ||
|
|
3dcc3492e8 | ||
|
|
2e77dcc660 | ||
|
|
89f60a0422 | ||
|
|
0455c09e4c | ||
|
|
7360b882ac | ||
|
|
5ffd29e31a | ||
|
|
5d7e892464 | ||
|
|
e8fd5de5b2 | ||
|
|
a8e7aa99e8 | ||
|
|
9a0db83f83 | ||
|
|
4e85566b88 | ||
|
|
8be72f6f23 | ||
|
|
513bc2c0ab | ||
|
|
036ba77a68 | ||
|
|
392277100c | ||
|
|
a7092ac503 | ||
|
|
027a16a39b | ||
|
|
c66af86d88 | ||
|
|
e621fdec0c | ||
|
|
447594b5ea | ||
|
|
a0b208cca0 | ||
|
|
1a4061fdb5 | ||
|
|
fb59f1f0a0 | ||
|
|
b1961033b3 | ||
|
|
863498f762 | ||
|
|
bdc44a4070 | ||
|
|
6451522f89 | ||
|
|
5ca1e9268c | ||
|
|
451a6841c9 | ||
|
|
3e3f46a683 | ||
|
|
2b0eaafea6 | ||
|
|
c1a8fde9a0 | ||
|
|
9dbd1b2a1b | ||
|
|
0cc1007543 | ||
|
|
8ca86181e4 | ||
|
|
8759d8f868 | ||
|
|
65a32b4166 | ||
|
|
933a0cddf8 | ||
|
|
d4c0542c84 | ||
|
|
05f5aaaeca | ||
|
|
036bd07e72 | ||
|
|
9c3e7b9ec0 | ||
|
|
1fd0383f69 | ||
|
|
9e62db5237 | ||
|
|
3062786bb3 | ||
|
|
b42847c135 | ||
|
|
5befcd24b5 | ||
|
|
61f3002568 | ||
|
|
0b7e0e166c | ||
|
|
3b52770a1b | ||
|
|
d0b9f53d8c | ||
|
|
92a9d7d26a | ||
|
|
ffd958a1b3 | ||
|
|
a7e9c7e24b | ||
|
|
9839cc6386 | ||
|
|
8d66d38fd2 | ||
|
|
a004d1647d | ||
|
|
21fe2c5f8f | ||
|
|
867e43637c | ||
|
|
c9025917b2 | ||
|
|
258def854c | ||
|
|
e8481818c8 | ||
|
|
f646e9bc59 | ||
|
|
680923bdd5 | ||
|
|
17e43a7ff2 | ||
|
|
71a5cfed4b | ||
|
|
c055477d3b | ||
|
|
ad4acca17a | ||
|
|
37b84300b4 | ||
|
|
d9a8dac266 | ||
|
|
76f704b060 | ||
|
|
cde360f7ec | ||
|
|
d69a2f1514 | ||
|
|
06a5c1a798 | ||
|
|
ca1f25ecf6 | ||
|
|
adcd7fb170 | ||
|
|
f105436b41 | ||
|
|
47738c751c | ||
|
|
0b3f2da6ef | ||
|
|
fa7092cc17 | ||
|
|
773d6e002c | ||
|
|
b78d1baaaf | ||
|
|
50ff59239c | ||
|
|
8f36878dde | ||
|
|
a29e98fd41 | ||
|
|
e4d5551f16 | ||
|
|
e610a1ffe4 | ||
|
|
ac927d188b | ||
|
|
bbf2f6c7de | ||
|
|
398816dbeb | ||
|
|
f3b399b31f | ||
|
|
2b0a38d25d | ||
|
|
b41dacb6c0 | ||
|
|
c5f5532303 | ||
|
|
09485c995e | ||
|
|
dc936b63d6 | ||
|
|
b5213794a8 | ||
|
|
2f8365a790 | ||
|
|
47be430bc1 | ||
|
|
918da24c8d | ||
|
|
0e82f2a02f | ||
|
|
447f15cfa4 | ||
|
|
8f80c206e7 | ||
|
|
e1a61985a2 | ||
|
|
16ad0c22f0 | ||
|
|
3d0d027216 | ||
|
|
b58a17a99e | ||
|
|
adaf2e15cd | ||
|
|
1723683370 | ||
|
|
9cd0a7982a | ||
|
|
d2726aae90 | ||
|
|
607a66b983 | ||
|
|
38b2adcaad | ||
|
|
d7879d8853 | ||
|
|
2d5b09a16f | ||
|
|
a06a722c23 | ||
|
|
d9d45f86cb | ||
|
|
e49b9cff67 | ||
|
|
8c69a4cb7a | ||
|
|
1042ac141a | ||
|
|
81aab35231 | ||
|
|
1c5742c7d4 | ||
|
|
4d646e67f3 | ||
|
|
59fbc51283 | ||
|
|
125e21900a | ||
|
|
569efd3e45 | ||
|
|
6c557ec015 | ||
|
|
63b917eb07 | ||
|
|
71af63dfc7 | ||
|
|
0cae048ada | ||
|
|
71021da261 | ||
|
|
1d897e491a | ||
|
|
57c0b408e5 | ||
|
|
43e0186efe | ||
|
|
8831d74cbc | ||
|
|
9a9d2cb964 | ||
|
|
2fc2a0cbdb | ||
|
|
40c041c9e7 | ||
|
|
b00c1dd055 | ||
|
|
761245049f | ||
|
|
30e142edd3 | ||
|
|
b7d84c002d | ||
|
|
551afe0cd7 | ||
|
|
5d8bfc2930 | ||
|
|
5d947cc8e1 | ||
|
|
7bf92db4c9 | ||
|
|
593c1d6b05 | ||
|
|
30e326b8b8 | ||
|
|
cf60eb52d8 | ||
|
|
8850dac291 | ||
|
|
bed52d0a4a | ||
|
|
10e564eeea | ||
|
|
ae47c4c79a | ||
|
|
e99e9fed11 | ||
|
|
79e9dbb9c6 | ||
|
|
081a6888fa | ||
|
|
ae6ba79f1e | ||
|
|
d9d2ad4382 | ||
|
|
31d277ffa2 | ||
|
|
7fe5f8907e | ||
|
|
2e9b59e2e0 | ||
|
|
5188894301 | ||
|
|
4c16efbbf7 | ||
|
|
8055243909 | ||
|
|
2eb4383e03 | ||
|
|
bafd043aae | ||
|
|
3379e7cc48 | ||
|
|
d971fc440f | ||
|
|
31658f4eab | ||
|
|
339be2b7a4 | ||
|
|
3e716e429f | ||
|
|
a8a61665f4 | ||
|
|
a7a1002509 | ||
|
|
65154e48cb | ||
|
|
32c10e5ae8 | ||
|
|
61ee1c6ff3 | ||
|
|
6642d96688 | ||
|
|
df8b085f0e | ||
|
|
7a415ccdfc | ||
|
|
2a432dc6ee | ||
|
|
322d1f09de | ||
|
|
44f4bd6e62 | ||
|
|
2bb74233cc | ||
|
|
19f6fd2295 | ||
|
|
558811e4f9 | ||
|
|
ed560a338e | ||
|
|
74741682bf | ||
|
|
d32d4e21e9 | ||
|
|
78f301d503 | ||
|
|
318ffc821c | ||
|
|
ef4ec16860 | ||
|
|
6bc927c535 | ||
|
|
2fe2b3c975 | ||
|
|
e4ad0d3b59 | ||
|
|
750261d205 | ||
|
|
df1b25f381 | ||
|
|
4af7ccd84c | ||
|
|
4282053f68 | ||
|
|
5c7d993dbe | ||
|
|
cdef7a53a4 | ||
|
|
b1f26d4ebe | ||
|
|
9bf534288c | ||
|
|
3d359229cf | ||
|
|
8013f8d5b3 | ||
|
|
cf12ab4b74 | ||
|
|
0f3eecaa8a | ||
|
|
22c1f4bb4e | ||
|
|
43c5fea782 | ||
|
|
41eab27f20 | ||
|
|
ba354f68d1 | ||
|
|
a6c7cc7b41 | ||
|
|
4dfc1631af | ||
|
|
58861fa524 | ||
|
|
1c6b1c530f | ||
|
|
21b498fece | ||
|
|
446e2c123f | ||
|
|
b3a7ee633d | ||
|
|
8b6366688a | ||
|
|
1671c78260 | ||
|
|
96ca459df8 | ||
|
|
51fb981d24 | ||
|
|
2ef46195d3 | ||
|
|
6e35b5ba8b | ||
|
|
b8ea0bd1ff | ||
|
|
8ca6ca2c88 | ||
|
|
508804d0d5 | ||
|
|
eb251050a5 | ||
|
|
67758b4980 | ||
|
|
f187d7258b | ||
|
|
5efd1f3a91 | ||
|
|
e3def22b07 | ||
|
|
ce5839ce27 | ||
|
|
50082043ef | ||
|
|
012045878d | ||
|
|
3083ccddcc | ||
|
|
f39b9041a0 | ||
|
|
37827cdd6c | ||
|
|
58f41a1f9b | ||
|
|
7712faca0a | ||
|
|
805fe1d47e | ||
|
|
0d4d1eff94 | ||
|
|
38cc460358 | ||
|
|
8600360173 | ||
|
|
f3371c443e | ||
|
|
a86f750473 | ||
|
|
92b532ce9a | ||
|
|
924f97cbe8 | ||
|
|
8817dc6d73 | ||
|
|
7324d59e08 | ||
|
|
dcd8e9250f | ||
|
|
f07578e0cb | ||
|
|
cabcf8b7b2 | ||
|
|
a90a07f46d | ||
|
|
9839bab8dc | ||
|
|
b9dd3de63b | ||
|
|
194aa90aee | ||
|
|
9bc72df1b5 | ||
|
|
b2439ca0af | ||
|
|
70d04d807b | ||
|
|
2372675c79 | ||
|
|
cb66900575 | ||
|
|
de4be44728 | ||
|
|
21dc037848 | ||
|
|
9fe5e69503 | ||
|
|
c0ac381f6f | ||
|
|
5f235c121d | ||
|
|
6b8e9a63f3 | ||
|
|
3dcda08735 | ||
|
|
f92ee8e762 | ||
|
|
94200dd3a4 | ||
|
|
512c4dd6f1 | ||
|
|
6d43854557 | ||
|
|
112ba7ac5c | ||
|
|
4c58929dd4 | ||
|
|
2188509d2c | ||
|
|
263ef14822 | ||
|
|
ed24f72cf9 | ||
|
|
c1197d06fe | ||
|
|
bd4d1cdd41 | ||
|
|
2c70d66d4a | ||
|
|
97ecace40e | ||
|
|
6ef988549d | ||
|
|
9088d79390 | ||
|
|
0c9bcb2445 | ||
|
|
c98c54bd6b | ||
|
|
225e66a522 | ||
|
|
f1810a9784 | ||
|
|
9526051766 | ||
|
|
bd435b175b | ||
|
|
42ab734256 | ||
|
|
77d89e7df3 | ||
|
|
c1dec16c50 | ||
|
|
86ae11f4c4 | ||
|
|
7ca1970fff | ||
|
|
b1cbbeb935 | ||
|
|
2dce4462a0 | ||
|
|
55e2bc27c6 | ||
|
|
2c3cad6e61 | ||
|
|
6122a8371a | ||
|
|
4ffeb05120 | ||
|
|
310f55abb6 | ||
|
|
d6c0642a02 | ||
|
|
541556874f | ||
|
|
477d7080b8 | ||
|
|
173c752d62 | ||
|
|
3b70488828 | ||
|
|
334783f89a | ||
|
|
89a54e31f1 | ||
|
|
354d18f78e | ||
|
|
0e8806eb2b | ||
|
|
731550acb3 | ||
|
|
be4019b4d3 | ||
|
|
70ffcd9adf | ||
|
|
bbe511dd15 | ||
|
|
82d5ac91d7 | ||
|
|
54de0eab6a | ||
|
|
4d5bb274d1 | ||
|
|
131fae57e5 | ||
|
|
37da53c20e | ||
|
|
6ad57a15cf | ||
|
|
4729bce16c | ||
|
|
0b5ac7a139 | ||
|
|
677e23ad14 | ||
|
|
6d838e3043 | ||
|
|
f322abceb8 | ||
|
|
e754d21598 | ||
|
|
0fdd861ef1 | ||
|
|
2e5f6a3507 | ||
|
|
4e57cab0fa | ||
|
|
9930c8f94d | ||
|
|
f8e262b87e | ||
|
|
896bdaf124 | ||
|
|
2e4f2639a3 | ||
|
|
ce89a92d0d | ||
|
|
1d9d1f6bbd | ||
|
|
767b57fc01 | ||
|
|
9e00177d76 | ||
|
|
095429a7df | ||
|
|
983efd61fb | ||
|
|
e028316308 | ||
|
|
e1354accb8 | ||
|
|
ea726f928d | ||
|
|
6b419dbfc0 | ||
|
|
006a9eaf44 | ||
|
|
76117854c6 | ||
|
|
6eae6db46b | ||
|
|
3aacb7150d | ||
|
|
81298a1034 | ||
|
|
b3d728df91 | ||
|
|
9a091ff11a | ||
|
|
6989b1730e | ||
|
|
1595542d59 | ||
|
|
fba9992a10 | ||
|
|
867dce2294 | ||
|
|
692554a899 | ||
|
|
f3cc616e07 | ||
|
|
d1c289b709 | ||
|
|
e7a0874a57 | ||
|
|
1beb9c4bb8 | ||
|
|
6eef3a9037 | ||
|
|
ddaaae46a6 | ||
|
|
4e4773a370 | ||
|
|
f4a2ffc5d2 | ||
|
|
ba1117e10e | ||
|
|
0cd46f932a | ||
|
|
937f404583 | ||
|
|
d13d60d752 | ||
|
|
31e4e7c709 | ||
|
|
0d3a8ce31b | ||
|
|
be185b46a7 | ||
|
|
90fa5b3b93 | ||
|
|
733996772b | ||
|
|
d4c921ea2e | ||
|
|
2852061699 | ||
|
|
d8859b9f0a | ||
|
|
ae1bc96006 | ||
|
|
f30ffb4413 | ||
|
|
273c6467c8 | ||
|
|
846a1d007c | ||
|
|
1dccc8dc78 | ||
|
|
e0d67bd057 | ||
|
|
4b4b93ac04 | ||
|
|
4390aee1e0 | ||
|
|
4cddb16788 | ||
|
|
e1179fd8c8 | ||
|
|
cb77285277 | ||
|
|
6c9d161950 | ||
|
|
40aaac5868 | ||
|
|
e16b69594e | ||
|
|
4837bf007a | ||
|
|
705fd4dafd | ||
|
|
a3e28d3c66 | ||
|
|
4a6755c28a | ||
|
|
188fe5dc52 | ||
|
|
44a8ae457d | ||
|
|
92eafcfe1a | ||
|
|
b12b031fdd | ||
|
|
492ec489a1 | ||
|
|
c57124e876 | ||
|
|
95b33c9c34 | ||
|
|
c6d8b63e54 | ||
|
|
f0f02c4ea6 | ||
|
|
eb2cb6810a | ||
|
|
b3c090e9ed | ||
|
|
13366fc9f8 | ||
|
|
929af7830a | ||
|
|
13062cf0e4 | ||
|
|
b897a8a35f | ||
|
|
117dc5288d | ||
|
|
4b5a3bd3d5 | ||
|
|
b224a67ea7 | ||
|
|
793f919d59 | ||
|
|
315987b2f6 | ||
|
|
9b7db548a2 | ||
|
|
126b70f781 | ||
|
|
0bbff627e2 | ||
|
|
961d23e2a1 | ||
|
|
b03ff9a48a | ||
|
|
3ffb40fafa | ||
|
|
1a3b4ac2ac | ||
|
|
794e17442f | ||
|
|
238d7119e0 | ||
|
|
8a929a8348 | ||
|
|
cf77153647 | ||
|
|
a2da0b0641 | ||
|
|
73faa13811 | ||
|
|
1a71872c7b | ||
|
|
62fe7135bd | ||
|
|
078940d29f | ||
|
|
2fafe42c18 | ||
|
|
c8a7537157 | ||
|
|
d4bf1cb23d | ||
|
|
46e4350013 | ||
|
|
202eb0d854 | ||
|
|
898702346e | ||
|
|
b72e6f16ca | ||
|
|
b9c27ed324 | ||
|
|
0166dfe16e | ||
|
|
7274541722 | ||
|
|
709ff7a701 | ||
|
|
66c224c954 | ||
|
|
3f9b37aa7f | ||
|
|
0377958d8f | ||
|
|
cc1cfd70b8 | ||
|
|
bc125ad76c | ||
|
|
62a2246448 | ||
|
|
587cf751d8 | ||
|
|
600181ed07 | ||
|
|
f0e525d2e2 | ||
|
|
f86cdd8cde | ||
|
|
4a4c537a0d | ||
|
|
1caaf04dfa | ||
|
|
b422a80249 | ||
|
|
ba19e20833 | ||
|
|
c34ddb2bc3 | ||
|
|
aa315f8472 | ||
|
|
2af6af2bf0 | ||
|
|
5694ff7c97 | ||
|
|
76f1c689c1 |
20
.github/stale.yml
vendored
Normal file
20
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 120
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- keep
|
||||
- enhancement
|
||||
- confirmed
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
Hey! This issue has been open for quite some time without any new comments now.
|
||||
It will be closed automatically in a week if no further activity occurs.
|
||||
|
||||
Thank you for using WLED!
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -3,3 +3,9 @@
|
||||
.piolibdeps
|
||||
.vscode
|
||||
!.vscode/extensions.json
|
||||
/wled00/Release
|
||||
/wled00/extLibs
|
||||
/platformio_override.ini
|
||||
.DS_Store
|
||||
.gitignore
|
||||
.clang-format
|
||||
|
||||
14
.travis.yml
14
.travis.yml
@@ -18,18 +18,26 @@
|
||||
# it (remove "# " before each line) or use own configuration according to the
|
||||
# Travis CI documentation (see above).
|
||||
#
|
||||
# * Test the Travis config here:
|
||||
# < https://config.travis-ci.com/explore >
|
||||
#
|
||||
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
sudo: false
|
||||
# - "2.7"
|
||||
- "3.5"
|
||||
os: linux
|
||||
cache:
|
||||
bundler: true
|
||||
ccache: true
|
||||
directories:
|
||||
- "~/.platformio"
|
||||
- "~/.buildcache"
|
||||
env:
|
||||
- PLATFORMIO_CI_SRC=wled00
|
||||
install:
|
||||
- pip install -U platformio
|
||||
- platformio update
|
||||
script:
|
||||
- platformio ci --project-conf=./platformio.ini -v
|
||||
# - platformio ci --project-conf=./platformio.ini
|
||||
- platformio run
|
||||
BIN
.vs/wled00/v15/.suo
Normal file
BIN
.vs/wled00/v15/.suo
Normal file
Binary file not shown.
12
.vscode/extensions.json
vendored
12
.vscode/extensions.json
vendored
@@ -1,7 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
||||
|
||||
111
CHANGELOG.md
Normal file
111
CHANGELOG.md
Normal file
@@ -0,0 +1,111 @@
|
||||
## WLED changelog
|
||||
|
||||
### WLED version 0.10.0
|
||||
|
||||
#### Build 2005030
|
||||
|
||||
- DMX Single RGW and Single DRGB modes now support an additional white channel
|
||||
- Improved palettes derived from set colors and changed their names
|
||||
|
||||
### Development versions between 0.9.1 and 0.10.0 release
|
||||
|
||||
#### Build 2005020
|
||||
|
||||
- Added ACST and ACST/ACDT timezones
|
||||
|
||||
#### Build 2005010
|
||||
|
||||
- Added module info page to web UI
|
||||
- Added realtime override functionality to web UI
|
||||
- Added individial segment power and brightness to web UI
|
||||
- Added feature to one-click select single segment only by tapping segment name
|
||||
- Removed palette jumping to default if color is changed
|
||||
|
||||
#### Build 2004300
|
||||
|
||||
- Added realtime override option and `lor` JSON property
|
||||
- Added `lm` (live mode) and `lip` (live IP) properties to info in JSON API
|
||||
- Added reset commands to APIs
|
||||
- Added `json/si`, returning state and info, but no FX or Palette lists
|
||||
- Added rollover detection to millis(). Can track uptimes longer than 49 days
|
||||
- Attempted to fix Wifi issues with Unifi brand APs
|
||||
|
||||
#### Build 2004230
|
||||
|
||||
- Added brightness and power for individual segments
|
||||
- Added `on` and `bri` properties to Segment object in JSON API
|
||||
- Added `C3` an `SB` commands to HTTP get API
|
||||
- Merged pull request #865 for 5CH_Shojo_PCB environment
|
||||
|
||||
#### Build 2004220
|
||||
|
||||
- Added Candle Multi effect
|
||||
- Added Palette capability to Pacifica effect
|
||||
|
||||
#### Build 2004190
|
||||
|
||||
- Added TM1814 type LED defines
|
||||
|
||||
#### Build 2004120
|
||||
|
||||
- Added Art-Net support
|
||||
- Added OTA platform to platformio.ini
|
||||
|
||||
#### Build 2004100
|
||||
|
||||
- Fixed DMX output compilation
|
||||
- Added DMX start LED setting
|
||||
|
||||
#### Build 2004061
|
||||
|
||||
- Fixed RBG and BGR getPixelColor (#825)
|
||||
- Improved formatting
|
||||
|
||||
#### Build 2004060
|
||||
|
||||
- Consolidated global variables in wled.h
|
||||
|
||||
#### Build 2003300
|
||||
|
||||
- Major change of project structure from .ino to .cpp and func_declare.h
|
||||
|
||||
#### Build 2003262
|
||||
|
||||
- Fixed compilation for Analog LEDs
|
||||
- Fixed sync settings network port fields too small
|
||||
|
||||
#### Build 2003261
|
||||
|
||||
- Fixed live preview not displaying whole light if over 255 LEDs
|
||||
|
||||
#### Build 2003251
|
||||
|
||||
- Added Pacifica effect (tentative, doesn't yet support other colors)
|
||||
- Added Atlantica palette
|
||||
- Fixed ESP32 build of Espalexa
|
||||
|
||||
#### Build 2003222
|
||||
|
||||
- Fixed Alexa Whites on non-RGBW lights (bump Espalexa to 2.4.5)
|
||||
|
||||
#### Build 2003221
|
||||
|
||||
- Moved Cronixie driver from FX library to drawOverlay handler
|
||||
|
||||
#### Build 2003211
|
||||
|
||||
- Added custom mapping compile define to FX_fcn.h
|
||||
- Merged pull request #784 by @TravisDean: Fixed initialization bug when toggling skip first
|
||||
- Added link to youtube videos by Room31 to readme
|
||||
|
||||
#### Build 2003141
|
||||
|
||||
- Fixed color of main segment returned in JSON API during transition not being target color (closes #765)
|
||||
- Fixed arlsLock() being called after pixels set in E1.31 (closes #772)
|
||||
- Fixed HTTP API calls not having an effect if no segment selected (now applies to main segment)
|
||||
|
||||
#### Build 2003121
|
||||
|
||||
- Created changelog.md - make tracking changes to code easier
|
||||
- Merged pull request #766 by @pille: Fix E1.31 out-of sequence detection
|
||||
|
||||
399
platformio.ini
399
platformio.ini
@@ -2,125 +2,314 @@
|
||||
; Please visit documentation: https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
src_dir = ./wled00
|
||||
src_dir = ./wled00
|
||||
data_dir = ./wled00/data
|
||||
lib_extra_dirs = ./wled00/src
|
||||
env_default = nodemcuv2
|
||||
; env_default = esp01
|
||||
; env_default = esp01_1m
|
||||
; env_default = d1_mini
|
||||
; env_default = esp32dev
|
||||
lib_dir = ./wled00/src
|
||||
build_cache_dir = ~/.buildcache
|
||||
extra_configs =
|
||||
platformio_override.ini
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# ENVIRONMENTS
|
||||
#
|
||||
# Please uncomment one of the lines below to select your board(s)
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Travis CI binaries (comment this out when building for single board)
|
||||
default_envs = d1_mini, esp01, esp01_1m_ota, esp32dev
|
||||
|
||||
# Release binaries
|
||||
; default_envs = nodemcuv2, esp01, esp01_1m_ota, esp01_1m_full, esp32dev, custom_WS2801, custom_APA102, custom_LEDPIN_16, custom_LEDPIN_4, custom32_LEDPIN_16
|
||||
|
||||
# Single binaries (uncomment your board)
|
||||
; default_envs = nodemcuv2
|
||||
; default_envs = esp01
|
||||
; default_envs = esp01_1m_ota
|
||||
; default_envs = esp01_1m_full
|
||||
; default_envs = esp07
|
||||
; default_envs = d1_mini
|
||||
; default_envs = heltec_wifi_kit_8
|
||||
; default_envs = h803wf
|
||||
; default_envs = d1_mini_debug
|
||||
; default_envs = d1_mini_ota
|
||||
; default_envs = esp32dev
|
||||
; default_envs = esp8285_4CH_MagicHome
|
||||
; default_envs = esp8285_4CH_H801
|
||||
; default_envs = esp8285_5CH_H801
|
||||
; default_envs = d1_mini_5CH_Shojo_PCB
|
||||
; default_envs = wemos_shield_esp32
|
||||
|
||||
[common]
|
||||
# ------------------------------------------------------------------------------
|
||||
# PLATFORM:
|
||||
# !! DO NOT confuse platformio's ESP8266 development platform with Arduino core for ESP8266
|
||||
#
|
||||
# arduino core 2.3.0 = platformIO 1.5.0
|
||||
# arduino core 2.4.0 = platformIO 1.6.0
|
||||
# arduino core 2.4.1 = platformIO 1.7.3
|
||||
# arduino core 2.4.2 = platformIO 1.8.0
|
||||
# arduino core 2.5.0 = platformIO 2.0.4
|
||||
# arduino core 2.5.1 = platformIO 2.1.1
|
||||
# arduino core 2.5.2 = platformIO 2.2.3
|
||||
# arduino core 2.6.1 = platformIO 2.3.0
|
||||
# arduino core 2.6.2 = platformIO 2.3.1
|
||||
# arduino core 2.6.3 = platformIO 2.3.2
|
||||
# ------------------------------------------------------------------------------
|
||||
arduino_core_2_3_0 = espressif8266@1.5.0
|
||||
arduino_core_2_4_0 = espressif8266@1.6.0
|
||||
arduino_core_2_4_1 = espressif8266@1.7.3
|
||||
arduino_core_2_4_2 = espressif8266@1.8.0
|
||||
arduino_core_2_5_0 = espressif8266@2.0.4
|
||||
arduino_core_2_5_1 = espressif8266@2.1.1
|
||||
arduino_core_2_5_2 = espressif8266@2.2.3
|
||||
arduino_core_2_6_1 = espressif8266@2.3.0
|
||||
arduino_core_2_6_2 = espressif8266@2.3.1
|
||||
arduino_core_2_6_3 = espressif8266@2.3.3
|
||||
|
||||
# Development platforms
|
||||
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
|
||||
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
|
||||
|
||||
platform = ${common.arduino_core_2_4_2}
|
||||
platform_latest = ${common.arduino_core_2_6_3}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# FLAGS: DEBUG
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_UPDATE -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_UPDATER -DDEBUG_ESP_OTA -DDEBUG_TLS_MEM
|
||||
#if needed (for memleaks etc) also add; -DDEBUG_ESP_OOM -include "umm_malloc/umm_malloc_cfg.h"
|
||||
#-DDEBUG_ESP_CORE is not working right now
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# FLAGS: ldscript
|
||||
# ldscript_512k ( 512 KB) = 487 KB sketch, 4 KB eeprom, no spiffs, 16 KB reserved
|
||||
# ldscript_1m0m (1024 KB) = 999 KB sketch, 4 KB eeprom, no spiffs, 16 KB reserved
|
||||
# ldscript_2m1m (2048 KB) = 1019 KB sketch, 4 KB eeprom, 1004 KB spiffs, 16 KB reserved
|
||||
# ldscript_4m1m (4096 KB) = 1019 KB sketch, 4 KB eeprom, 1002 KB spiffs, 16 KB reserved, 2048 KB empty/ota?
|
||||
# ldscript_4m3m (4096 KB) = 1019 KB sketch, 4 KB eeprom, 3040 KB spiffs, 16 KB reserved
|
||||
#
|
||||
# Available lwIP variants (macros):
|
||||
# -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH = v1.4 Higher Bandwidth (default)
|
||||
# -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY = v2 Lower Memory
|
||||
# -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH = v2 Higher Bandwidth
|
||||
#
|
||||
# BearSSL performance:
|
||||
# When building with -DSECURE_CLIENT=SECURE_CLIENT_BEARSSL, please add `board_build.f_cpu = 160000000` to the environment configuration
|
||||
#
|
||||
# BearSSL ciphers:
|
||||
# When building on core >= 2.5, you can add the build flag -DBEARSSL_SSL_BASIC in order to build BearSSL with a limited set of ciphers:
|
||||
# TLS_RSA_WITH_AES_128_CBC_SHA256 / AES128-SHA256
|
||||
# TLS_RSA_WITH_AES_256_CBC_SHA256 / AES256-SHA256
|
||||
# TLS_RSA_WITH_AES_128_CBC_SHA / AES128-SHA
|
||||
# TLS_RSA_WITH_AES_256_CBC_SHA / AES256-SHA
|
||||
# This reduces the OTA size with ~45KB, so it's especially useful on low memory boards (512k/1m).
|
||||
# ------------------------------------------------------------------------------
|
||||
build_flags = -g -w -DMQTT_MAX_PACKET_SIZE=1024 -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
|
||||
-DSECURE_CLIENT=SECURE_CLIENT_BEARSSL -DBEARSSL_SSL_BASIC
|
||||
#build_flags for the IRremoteESP8266 library (enabled decoders have to appear here)
|
||||
-D _IR_ENABLE_DEFAULT_=false
|
||||
-D DECODE_HASH=true
|
||||
-D DECODE_NEC=true
|
||||
-D DECODE_SONY=true
|
||||
-D DECODE_SAMSUNG=true
|
||||
-D DECODE_LG=true
|
||||
|
||||
build_flags_esp8266 = ${common.build_flags} -DESP8266
|
||||
build_flags_esp32 = ${common.build_flags} -DARDUINO_ARCH_ESP32
|
||||
|
||||
ldscript_512k = eagle.flash.512k.ld ;for older versions change this to eagle.flash.512k0.ld
|
||||
ldscript_1m0m = eagle.flash.1m.ld ;for older versions change this to eagle.flash.1m0.ld
|
||||
ldscript_2m1m = eagle.flash.2m1m.ld
|
||||
ldscript_4m1m = eagle.flash.4m1m.ld
|
||||
ldscript_4m3m = eagle.flash.4m3m.ld
|
||||
|
||||
shared_libdeps_dir = ./wled00/src
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# COMMON SETTINGS:
|
||||
# ------------------------------------------------------------------------------
|
||||
[env]
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
board_build.flash_mode = dout
|
||||
upload_speed = 921600
|
||||
build_flags =
|
||||
; -D VERSION=0.8.2
|
||||
; -D DEBUG
|
||||
# TODO replace libs in /lib with managed libs in here if possible.
|
||||
# If they are not changed it's just a matter of setting the correct version and change the import statement
|
||||
lib_deps_external =
|
||||
#Blynk@0.5.4
|
||||
#E131@1.0.0
|
||||
#webserver
|
||||
FastLED@3.2.1
|
||||
NeoPixelBus@2.4.1
|
||||
#PubSubClient@2.7
|
||||
#Time@1.5
|
||||
#Timezone@1.2.1
|
||||
#WS2812FX@1.1.2
|
||||
monitor_speed = 115200
|
||||
upload_speed = 115200
|
||||
lib_extra_dirs =
|
||||
${common.shared_libdeps_dir}
|
||||
|
||||
[common:esp8266]
|
||||
platform = espressif8266@1.8.0
|
||||
build_flags =
|
||||
-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH
|
||||
# ------------------------------------------------------------------------------
|
||||
# LIBRARIES: required dependencies
|
||||
# Please note that we don't always use the latest version of a library.
|
||||
#
|
||||
# The following libraries have been included (and some of them changd) in the source:
|
||||
# ArduinoJson@5.13.5, Blynk@0.5.4(changed), E131@1.0.0(changed), Time@1.5, Timezone@1.2.1
|
||||
# ------------------------------------------------------------------------------
|
||||
lib_compat_mode = strict
|
||||
lib_deps =
|
||||
FastLED@3.3.2
|
||||
NeoPixelBus@2.5.7
|
||||
ESPAsyncTCP@1.2.0
|
||||
ESPAsyncUDP@697c75a025
|
||||
AsyncTCP@1.0.3
|
||||
Esp Async WebServer@1.2.0
|
||||
IRremoteESP8266@2.7.3
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
#U8g2@~2.27.2
|
||||
#For Dallas sensor uncomment following 2 lines
|
||||
#OneWire@~2.3.5
|
||||
#For BME280 sensor uncomment following
|
||||
#BME280@~3.0.0
|
||||
lib_ignore =
|
||||
AsyncTCP
|
||||
|
||||
[common:esp8266_512k]
|
||||
platform = espressif8266@1.7.0
|
||||
build_flags =
|
||||
-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
||||
; -D WLED_DISABLE_MOBILE_UI
|
||||
-D WLED_DISABLE_OTA
|
||||
-D WLED_DISABLE_ALEXA
|
||||
; -D WLED_DISABLE_BLYNK
|
||||
; -D WLED_DISABLE_CRONIXIE
|
||||
-D WLED_DISABLE_HUESYNC
|
||||
-D WLED_DISABLE_INFRARED
|
||||
# ------------------------------------------------------------------------------
|
||||
# WLED BUILDS
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
[common:esp32]
|
||||
platform = espressif32@1.5.0
|
||||
build_flags =
|
||||
-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH
|
||||
-D ARDUINO_ARCH_ESP32
|
||||
-D WORKAROUND_ESP32_BITBANG
|
||||
|
||||
|
||||
# see: http://docs.platformio.org/en/latest/platforms/espressif8266.html
|
||||
[env:nodemcuv2]
|
||||
board = nodemcuv2
|
||||
platform = ${common:esp8266.platform}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
upload_speed = ${common.upload_speed}
|
||||
framework = ${common.framework}
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
${common:esp8266.build_flags}
|
||||
lib_deps =
|
||||
${common.lib_deps_external}
|
||||
IRremoteESP8266@2.5.3
|
||||
|
||||
[env:d1_mini]
|
||||
board = d1_mini
|
||||
platform = ${common:esp8266.platform}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
upload_speed = ${common.upload_speed}
|
||||
framework = ${common.framework}
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
${common:esp8266.build_flags}
|
||||
lib_deps =
|
||||
${common.lib_deps_external}
|
||||
IRremoteESP8266@2.5.3
|
||||
|
||||
[env:esp01_1m]
|
||||
board = esp01_1m
|
||||
platform = ${common:esp8266.platform}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
upload_speed = ${common.upload_speed}
|
||||
framework = ${common.framework}
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
${common:esp8266.build_flags}
|
||||
# disable IR because there is no pin for it
|
||||
-D WLED_DISABLE_INFRARED
|
||||
lib_deps =
|
||||
${common.lib_deps_external}
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
[env:esp01]
|
||||
board = esp01
|
||||
platform = ${common:esp8266_512k.platform}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
upload_speed = ${common.upload_speed}
|
||||
framework = ${common.framework}
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
${common:esp8266_512k.build_flags}
|
||||
lib_deps =
|
||||
${common.lib_deps_external}
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_512k}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK
|
||||
-D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
|
||||
|
||||
[env:esp01_1m_ota]
|
||||
board = esp01_1m
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK -D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
|
||||
|
||||
[env:esp01_1m_full]
|
||||
board = esp01_1m
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA
|
||||
|
||||
[env:esp07]
|
||||
board = esp07
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
[env:d1_mini]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
[env:heltec_wifi_kit_8]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
[env:h803wf]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=1 -D WLED_DISABLE_INFRARED
|
||||
|
||||
# see: http://docs.platformio.org/en/latest/platforms/espressif32.html
|
||||
[env:esp32dev]
|
||||
board = esp32dev
|
||||
platform = ${common:esp32.platform}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
upload_speed = ${common.upload_speed}
|
||||
framework = ${common.framework}
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
${common:esp32.build_flags}
|
||||
lib_deps =
|
||||
${common.lib_deps_external}
|
||||
|
||||
platform = espressif32@1.11.2
|
||||
build_flags = ${common.build_flags_esp32}
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:esp8285_4CH_MagicHome]
|
||||
board = esp8285
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ANALOG_LEDS
|
||||
|
||||
[env:esp8285_4CH_H801]
|
||||
board = esp8285
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801
|
||||
|
||||
[env:esp8285_5CH_H801]
|
||||
board = esp8285
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801 -D WLED_ENABLE_5CH_LEDS
|
||||
|
||||
[env:d1_mini_5CH_Shojo_PCB]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D SHOJO_PCB -D WLED_ENABLE_5CH_LEDS
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# DEVELOPMENT BOARDS
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
[env:d1_mini_debug]
|
||||
board = d1_mini
|
||||
build_type = debug
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} ${common.debug_flags}
|
||||
|
||||
[env:d1_mini_ota]
|
||||
board = d1_mini
|
||||
upload_protocol = espota
|
||||
# exchange for your WLED IP
|
||||
upload_port = "10.10.1.27"
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# custom board configurations
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
[env:custom_LEDPIN_4]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=4 -D IRPIN=5
|
||||
|
||||
[env:custom_LEDPIN_16]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=16
|
||||
|
||||
[env:custom_APA102]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} -D USE_APA102
|
||||
|
||||
[env:custom_WS2801]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} -D USE_WS2801
|
||||
|
||||
[env:custom32_LEDPIN_16]
|
||||
board = esp32dev
|
||||
platform = espressif32@1.11.2
|
||||
build_flags = ${common.build_flags_esp32} -D LEDPIN=16
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:wemos_shield_esp32]
|
||||
board = esp32dev
|
||||
platform = espressif32@1.11.2
|
||||
upload_port = /dev/cu.SLAB_USBtoUART
|
||||
monitor_port = /dev/cu.SLAB_USBtoUART
|
||||
upload_speed = 460800
|
||||
build_flags = ${common.build_flags_esp32} -D LEDPIN=16 -D RLYPIN=19 -D BTNPIN=17
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
36
platformio_override.ini.example
Normal file
36
platformio_override.ini.example
Normal file
@@ -0,0 +1,36 @@
|
||||
# Example PlatformIO Project Configuration Override
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copy to platformio_override.ini to activate overrides
|
||||
# ------------------------------------------------------------------------------
|
||||
# Please visit documentation: https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:esp8266_1m_custom]
|
||||
board = esp01_1m
|
||||
platform = ${common.arduino_core_2_4_2}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
-D WLED_DISABLE_OTA
|
||||
-D WLED_DISABLE_ALEXA
|
||||
-D WLED_DISABLE_BLYNK
|
||||
-D WLED_DISABLE_CRONIXIE
|
||||
-D WLED_DISABLE_HUESYNC
|
||||
-D WLED_DISABLE_INFRARED
|
||||
; PIN defines - uncomment and change, if needed:
|
||||
; -D LEDPIN=2
|
||||
; -D BTNPIN=0
|
||||
; -D IR_PIN=4
|
||||
; -D RLYPIN=12
|
||||
; -D RLYMDE=1
|
||||
; digital LED strip types - uncomment only one ! - this will disable WS281x / SK681x support
|
||||
; -D USE_APA102
|
||||
; -D USE_WS2801
|
||||
; -D USE_LPD8806
|
||||
; to drive analog LED strips (aka 5050), uncomment the following
|
||||
; PWM pins 5,12,13,15 are used with Magic Home LED Controller (default)
|
||||
; -D WLED_USE_ANALOG_LEDS
|
||||
; for the H801 controller (PINs 15,13,12,14 (W2 = 04)) uncomment this
|
||||
; -D WLED_USE_H801
|
||||
; for the BW-LT11 controller (PINs 12,4,14,5 ) uncomment this
|
||||
; -D WLED_USE_BWLT11
|
||||
; and to enable channel 5 for RGBW-CT led strips this
|
||||
; -D WLED_USE_5CH_LEDS
|
||||
73
readme.md
73
readme.md
@@ -1,47 +1,59 @@
|
||||

|
||||
|
||||
[](https://github.com/Aircoookie/WLED/releases)
|
||||
[](https://wled.discourse.group)
|
||||
[](https://discord.gg/KuqP7NE)
|
||||
[](https://github.com/Aircoookie/WLED/wiki)
|
||||
[](https://github.com/Aircoookie/WLED-App)
|
||||
|
||||
## Welcome to my project WLED!
|
||||
|
||||
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B) LEDs!
|
||||
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812, APA102) LEDs!
|
||||
|
||||
### Features:
|
||||
- WS2812FX library integrated for 80 special effects
|
||||
- FastLED noise effects and palettes
|
||||
- Customizable Mobile and desktop UI with color and effect controls
|
||||
- Settings page - configuration over network
|
||||
- Access Point and station mode - automatic failsafe AP
|
||||
- Support for RGBW strips
|
||||
- 25 user presets to save and load colors/effects easily, supports cycling through them.
|
||||
- Macro functions to automatically execute API calls
|
||||
- Nightlight function (gradually dims down)
|
||||
- Full OTA software updatability (HTTP + ArduinoOTA), password protectable
|
||||
- Configurable analog clock + support for the Cronixie kit by Diamex
|
||||
- Configurable Auto Brightness limit for safer operation
|
||||
- WS2812FX library integrated for over 100 special effects
|
||||
- FastLED noise effects and 50 palettes
|
||||
- Modern UI with color, effect and segment controls
|
||||
- Segments to set different effects and colors to parts of the LEDs
|
||||
- Settings page - configuration over network
|
||||
- Access Point and station mode - automatic failsafe AP
|
||||
- Support for RGBW strips
|
||||
- 16 user presets to save and load colors/effects easily, supports cycling through them.
|
||||
- Macro functions to automatically execute API calls
|
||||
- Nightlight function (gradually dims down)
|
||||
- Full OTA software updatability (HTTP + ArduinoOTA), password protectable
|
||||
- Configurable analog clock + support for the Cronixie kit by Diamex
|
||||
- Configurable Auto Brightness limit for safer operation
|
||||
|
||||
### Supported light control interfaces:
|
||||
- WLED Android app
|
||||
- HTTP request API
|
||||
- Blynk IoT
|
||||
- MQTT
|
||||
- E1.31
|
||||
- Hyperion
|
||||
- UDP realtime
|
||||
- Alexa voice control (including dimming and color)
|
||||
- Sync to Philips hue lights
|
||||
- Adalight (PC ambilight via serial)
|
||||
- Sync color of multiple WLED devices (UDP notifier)
|
||||
- Infrared remotes (24-key RGB, receiver required)
|
||||
- Simple timers/schedules (time from NTP, timezones/DST supported)
|
||||
- WLED app for Android and iOS
|
||||
- JSON and HTTP request APIs
|
||||
- MQTT
|
||||
- Blynk IoT
|
||||
- E1.31
|
||||
- Hyperion
|
||||
- UDP realtime
|
||||
- Alexa voice control (including dimming and color)
|
||||
- Sync to Philips hue lights
|
||||
- Adalight (PC ambilight via serial)
|
||||
- Sync color of multiple WLED devices (UDP notifier)
|
||||
- Infrared remotes (24-key RGB, receiver required)
|
||||
- Simple timers/schedules (time from NTP, timezones/DST supported)
|
||||
|
||||
### Quick start guide and documentation:
|
||||
|
||||
See the [wiki](https://github.com/Aircoookie/WLED/wiki)!
|
||||
|
||||
DrZzs has made some excellent video guides:
|
||||
[Introduction, hardware and installation](https://www.youtube.com/watch?v=tXvtxwK3jRk)
|
||||
[Settings, tips and tricks](https://www.youtube.com/watch?v=6eCE2BpLaUQ)
|
||||
|
||||
If you'd rather read, here is a very [detailed step-by-step beginner tutorial](https://tynick.com/blog/11-03-2019/getting-started-with-wled-on-esp8266/) by tynick!
|
||||
|
||||
Russian speakers, check out the videos by Room31:
|
||||
[WLED Firmware Overview: Interface and Settings](https://youtu.be/h7lKsczEI7E)
|
||||
[ESP8266 based LED controller for WS2812b strip. WLED Firmware + OpenHAB](https://youtu.be/K4ioTt3XvGc)
|
||||
|
||||
### Other
|
||||
|
||||
Licensed under the MIT license
|
||||
@@ -50,5 +62,12 @@ Credits [here](https://github.com/Aircoookie/WLED/wiki/Contributors-&-About)!
|
||||
Uses Linearicons by Perxis!
|
||||
|
||||
Join the Discord [server](https://discord.gg/KuqP7NE) to discuss everything about WLED!
|
||||
You can also send me mails to [dev.aircoookie@gmail.com](mailto:dev.aircoookie@gmail.com).
|
||||
Check out the WLED [Discourse forum](https://wled.discourse.group)!
|
||||
You can also send me mails to [dev.aircoookie@gmail.com](mailto:dev.aircoookie@gmail.com), but please only do so if you want to talk to me privately.
|
||||
If WLED really brightens up your every day, you can [](https://paypal.me/aircoookie)
|
||||
|
||||
*Disclaimer:*
|
||||
If you are sensitive to photoeleptic seizures it is not recommended that you use this software.
|
||||
In case you still want to try, don't use strobe, lighting or noise modes or high effect speed settings.
|
||||
As per the MIT license, i assume no liability for any damage to you or any other person or equipment.
|
||||
|
||||
|
||||
BIN
usermods/Enclosure_with_OLED_temp_ESP07/assets/controller.jpg
Normal file
BIN
usermods/Enclosure_with_OLED_temp_ESP07/assets/controller.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 150 KiB |
BIN
usermods/Enclosure_with_OLED_temp_ESP07/assets/pcb.png
Normal file
BIN
usermods/Enclosure_with_OLED_temp_ESP07/assets/pcb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 235 KiB |
7
usermods/Enclosure_with_OLED_temp_ESP07/assets/readme.md
Normal file
7
usermods/Enclosure_with_OLED_temp_ESP07/assets/readme.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Enclosure and PCB
|
||||
|
||||
## IP67 rated enclosure
|
||||

|
||||
|
||||
## PCB
|
||||

|
||||
68
usermods/Enclosure_with_OLED_temp_ESP07/readme.md
Normal file
68
usermods/Enclosure_with_OLED_temp_ESP07/readme.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Almost universal controller board for outdoor applications
|
||||
This usermod is using ideas from @mrVanboy and @400killer
|
||||
|
||||
Installation of file: Copy and replace file in wled00 directory.
|
||||
|
||||
For BME280 sensor use usermod_bme280.cpp. Copy to wled00 and rename to usermod.cpp
|
||||
|
||||
## Project repository
|
||||
- [Original repository](https://github.com/srg74/Controller-for-WLED-firmware) - Main controller repository
|
||||
## Features
|
||||
- SSD1306 128x32 and 128x64 I2C OLED display
|
||||
- On screen IP address, SSID and controller status (e.g. ON or OFF, recent effect)
|
||||
- Auto display shutoff for saving display lifetime
|
||||
- Dallas temperature sensor
|
||||
- Reporting temperature to MQTT broker
|
||||
|
||||
## Hardware
|
||||

|
||||
|
||||
## Functionality checked with
|
||||
- ESP-07S
|
||||
- PlatformIO
|
||||
- SSD1306 128x32 I2C OLED display
|
||||
- DS18B20 (temperature sensor)
|
||||
- BME280 (temperature, humidity and pressure sensor)
|
||||
- KY-022 (infrared receiver)
|
||||
- Push button (N.O. momentary switch)
|
||||
|
||||
For Dallas sensor uncomment `U8g2@~2.27.3`,`DallasTemperature@~3.8.0`,`OneWire@~2.3.5 under` `[common]` section in `platformio.ini`:
|
||||
```ini
|
||||
# platformio.ini
|
||||
...
|
||||
[platformio]
|
||||
...
|
||||
default_envs = esp07
|
||||
; default_envs = d1_mini
|
||||
...
|
||||
[common]
|
||||
...
|
||||
lib_deps_external =
|
||||
...
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
U8g2@~2.27.3
|
||||
#For Dallas sensor uncomment following 2 lines
|
||||
DallasTemperature@~3.8.0
|
||||
OneWire@~2.3.5
|
||||
...
|
||||
```
|
||||
|
||||
For BME280 sensor uncomment `U8g2@~2.27.3`,`BME280@~3.0.0 under` `[common]` section in `platformio.ini`:
|
||||
```ini
|
||||
# platformio.ini
|
||||
...
|
||||
[platformio]
|
||||
...
|
||||
default_envs = esp07
|
||||
; default_envs = d1_mini
|
||||
...
|
||||
[common]
|
||||
...
|
||||
lib_deps_external =
|
||||
...
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
U8g2@~2.27.3
|
||||
#For BME280 sensor uncomment following
|
||||
BME280@~3.0.0
|
||||
...
|
||||
```
|
||||
209
usermods/Enclosure_with_OLED_temp_ESP07/usermod.cpp
Normal file
209
usermods/Enclosure_with_OLED_temp_ESP07/usermod.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||
#include <DallasTemperature.h> //Dallastemperature sensor
|
||||
//The SCL and SDA pins are defined here.
|
||||
//Lolin32 boards use SCL=5 SDA=4
|
||||
#define U8X8_PIN_SCL 5
|
||||
#define U8X8_PIN_SDA 4
|
||||
// Dallas sensor
|
||||
OneWire oneWire(13);
|
||||
DallasTemperature sensor(&oneWire);
|
||||
long temptimer = millis();
|
||||
long lastMeasure = 0;
|
||||
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
|
||||
|
||||
// If display does not work or looks corrupted check the
|
||||
// constructor reference:
|
||||
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
|
||||
// or check the gallery:
|
||||
// https://github.com/olikraus/u8g2/wiki/gallery
|
||||
// --> First choise of cheap I2C OLED 128X32 0.91"
|
||||
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
|
||||
// --> Second choise of cheap I2C OLED 128X64 0.96" or 1.3"
|
||||
//U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
|
||||
// gets called once at boot. Do all initialization that doesn't depend on
|
||||
// network here
|
||||
void userSetup() {
|
||||
sensor.begin(); //Start Dallas temperature sensor
|
||||
u8x8.begin();
|
||||
//u8x8.setFlipMode(1); //Uncoment if using WLED Wemos shield
|
||||
u8x8.setPowerSave(0);
|
||||
u8x8.setContrast(10); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
u8x8.drawString(0, 0, "Loading...");
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
// interfaces here
|
||||
void userConnected() {}
|
||||
|
||||
// needRedraw marks if redraw is required to prevent often redrawing.
|
||||
bool needRedraw = true;
|
||||
|
||||
// Next variables hold the previous known values to determine if redraw is
|
||||
// required.
|
||||
String knownSsid = "";
|
||||
IPAddress knownIp;
|
||||
uint8_t knownBrightness = 0;
|
||||
uint8_t knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
|
||||
long lastUpdate = 0;
|
||||
long lastRedraw = 0;
|
||||
bool displayTurnedOff = false;
|
||||
// How often we are redrawing screen
|
||||
#define USER_LOOP_REFRESH_RATE_MS 5000
|
||||
|
||||
void userLoop() {
|
||||
|
||||
//----> Dallas temperature sensor MQTT publishing
|
||||
temptimer = millis();
|
||||
// Timer to publishe new temperature every 60 seconds
|
||||
if (temptimer - lastMeasure > 60000)
|
||||
{
|
||||
lastMeasure = temptimer;
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (mqtt != nullptr)
|
||||
{
|
||||
sensor.requestTemperatures();
|
||||
//Gets prefered temperature scale based on selection in definitions section
|
||||
#ifdef Celsius
|
||||
float board_temperature = sensor.getTempCByIndex(0);
|
||||
#else
|
||||
float board_temperature = sensor.getTempFByIndex(0);
|
||||
#endif
|
||||
//Create character string populated with user defined device topic from the UI, and the read temperature. Then publish to MQTT server.
|
||||
char subuf[38];
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, "/temperature");
|
||||
mqtt->publish(subuf, 0, true, String(board_temperature).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we time interval for redrawing passes.
|
||||
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) {
|
||||
return;
|
||||
}
|
||||
lastUpdate = millis();
|
||||
|
||||
// Turn off display after 3 minutes with no change.
|
||||
if(!displayTurnedOff && millis() - lastRedraw > 3*60*1000) {
|
||||
u8x8.setPowerSave(1);
|
||||
displayTurnedOff = true;
|
||||
}
|
||||
|
||||
// Check if values which are shown on display changed from the last time.
|
||||
if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) {
|
||||
needRedraw = true;
|
||||
} else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) {
|
||||
needRedraw = true;
|
||||
} else if (knownBrightness != bri) {
|
||||
needRedraw = true;
|
||||
} else if (knownMode != strip.getMode()) {
|
||||
needRedraw = true;
|
||||
} else if (knownPalette != strip.getSegment(0).palette) {
|
||||
needRedraw = true;
|
||||
}
|
||||
|
||||
if (!needRedraw) {
|
||||
return;
|
||||
}
|
||||
needRedraw = false;
|
||||
|
||||
if (displayTurnedOff)
|
||||
{
|
||||
u8x8.setPowerSave(0);
|
||||
displayTurnedOff = false;
|
||||
}
|
||||
lastRedraw = millis();
|
||||
|
||||
// Update last known values.
|
||||
#if defined(ESP8266)
|
||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
||||
#else
|
||||
knownSsid = WiFi.SSID();
|
||||
#endif
|
||||
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
|
||||
knownBrightness = bri;
|
||||
knownMode = strip.getMode();
|
||||
knownPalette = strip.getSegment(0).palette;
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
|
||||
// First row with Wifi name
|
||||
u8x8.setCursor(1, 0);
|
||||
u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0));
|
||||
// Print `~` char to indicate that SSID is longer, than owr dicplay
|
||||
if (knownSsid.length() > u8x8.getCols())
|
||||
u8x8.print("~");
|
||||
|
||||
// Second row with IP or Psssword
|
||||
u8x8.setCursor(1, 1);
|
||||
// Print password in AP mode and if led is OFF.
|
||||
if (apActive && bri == 0)
|
||||
u8x8.print(apPass);
|
||||
else
|
||||
u8x8.print(knownIp);
|
||||
|
||||
// Third row with mode name
|
||||
u8x8.setCursor(2, 2);
|
||||
uint8_t qComma = 0;
|
||||
bool insideQuotes = false;
|
||||
uint8_t printedChars = 0;
|
||||
char singleJsonSymbol;
|
||||
|
||||
// Find the mode name in JSON
|
||||
for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownMode))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
// Fourth row with palette name
|
||||
u8x8.setCursor(2, 3);
|
||||
qComma = 0;
|
||||
insideQuotes = false;
|
||||
printedChars = 0;
|
||||
// Looking for palette name in JSON.
|
||||
for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownPalette))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
|
||||
u8x8.setFont(u8x8_font_open_iconic_embedded_1x1);
|
||||
u8x8.drawGlyph(0, 0, 80); // wifi icon
|
||||
u8x8.drawGlyph(0, 1, 68); // home icon
|
||||
u8x8.setFont(u8x8_font_open_iconic_weather_2x2);
|
||||
u8x8.drawGlyph(0, 2, 66 + (bri > 0 ? 3 : 0)); // sun/moon icon
|
||||
}
|
||||
266
usermods/Enclosure_with_OLED_temp_ESP07/usermod_bme280.cpp
Normal file
266
usermods/Enclosure_with_OLED_temp_ESP07/usermod_bme280.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||
#include <Wire.h>
|
||||
#include <BME280I2C.h> //BME280 sensor
|
||||
|
||||
void UpdateBME280Data();
|
||||
|
||||
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
|
||||
BME280I2C bme; // Default : forced mode, standby time = 1000 ms
|
||||
// Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off,
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
|
||||
uint8_t SCL_PIN = 22;
|
||||
uint8_t SDA_PIN = 21;
|
||||
#else //ESP8266 boards
|
||||
uint8_t SCL_PIN = 5;
|
||||
uint8_t SDA_PIN = 4;
|
||||
// uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
||||
#endif
|
||||
|
||||
//The SCL and SDA pins are defined here.
|
||||
//ESP8266 Wemos D1 mini board use SCL=5 SDA=4 while ESP32 Wemos32 mini board use SCL=22 SDA=21
|
||||
#define U8X8_PIN_SCL SCL_PIN
|
||||
#define U8X8_PIN_SDA SDA_PIN
|
||||
//#define U8X8_PIN_RESET RST_PIN // Uncoment for Heltec WiFi-Kit-8
|
||||
|
||||
// If display does not work or looks corrupted check the
|
||||
// constructor reference:
|
||||
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
|
||||
// or check the gallery:
|
||||
// https://github.com/olikraus/u8g2/wiki/gallery
|
||||
// --> First choise of cheap I2C OLED 128X32 0.91"
|
||||
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
|
||||
// --> Second choise of cheap I2C OLED 128X64 0.96" or 1.3"
|
||||
//U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
|
||||
// --> Third choise of Heltec WiFi-Kit-8 OLED 128X32 0.91"
|
||||
//U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_RESET, U8X8_PIN_SCL, U8X8_PIN_SDA); // Constructor for Heltec WiFi-Kit-8
|
||||
// gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
|
||||
// BME280 sensor timer
|
||||
long tempTimer = millis();
|
||||
long lastMeasure = 0;
|
||||
|
||||
float SensorPressure(NAN);
|
||||
float SensorTemperature(NAN);
|
||||
float SensorHumidity(NAN);
|
||||
|
||||
void userSetup() {
|
||||
u8x8.begin();
|
||||
u8x8.setPowerSave(0);
|
||||
u8x8.setFlipMode(1);
|
||||
u8x8.setContrast(10); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
u8x8.drawString(0, 0, "Loading...");
|
||||
Wire.begin(SDA_PIN,SCL_PIN);
|
||||
|
||||
while(!bme.begin())
|
||||
{
|
||||
Serial.println("Could not find BME280I2C sensor!");
|
||||
delay(1000);
|
||||
}
|
||||
switch(bme.chipModel())
|
||||
{
|
||||
case BME280::ChipModel_BME280:
|
||||
Serial.println("Found BME280 sensor! Success.");
|
||||
break;
|
||||
case BME280::ChipModel_BMP280:
|
||||
Serial.println("Found BMP280 sensor! No Humidity available.");
|
||||
break;
|
||||
default:
|
||||
Serial.println("Found UNKNOWN sensor! Error!");
|
||||
}
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
// interfaces here
|
||||
void userConnected() {}
|
||||
|
||||
// needRedraw marks if redraw is required to prevent often redrawing.
|
||||
bool needRedraw = true;
|
||||
|
||||
// Next variables hold the previous known values to determine if redraw is
|
||||
// required.
|
||||
String knownSsid = "";
|
||||
IPAddress knownIp;
|
||||
uint8_t knownBrightness = 0;
|
||||
uint8_t knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
|
||||
long lastUpdate = 0;
|
||||
long lastRedraw = 0;
|
||||
bool displayTurnedOff = false;
|
||||
// How often we are redrawing screen
|
||||
#define USER_LOOP_REFRESH_RATE_MS 5000
|
||||
|
||||
void userLoop() {
|
||||
|
||||
// BME280 sensor MQTT publishing
|
||||
tempTimer = millis();
|
||||
// Timer to publish new sensor data every 60 seconds
|
||||
if (tempTimer - lastMeasure > 60000)
|
||||
{
|
||||
lastMeasure = tempTimer;
|
||||
|
||||
// Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (mqtt != nullptr)
|
||||
{
|
||||
UpdateBME280Data();
|
||||
float board_temperature = SensorTemperature;
|
||||
float board_pressure = SensorPressure;
|
||||
float board_humidity = SensorHumidity;
|
||||
|
||||
// Create string populated with user defined device topic from the UI, and the read temperature, humidity and pressure. Then publish to MQTT server.
|
||||
String t = String(mqttDeviceTopic);
|
||||
t += "/temperature";
|
||||
mqtt->publish(t.c_str(), 0, true, String(board_temperature).c_str());
|
||||
String p = String(mqttDeviceTopic);
|
||||
p += "/pressure";
|
||||
mqtt->publish(p.c_str(), 0, true, String(board_pressure).c_str());
|
||||
String h = String(mqttDeviceTopic);
|
||||
h += "/humidity";
|
||||
mqtt->publish(h.c_str(), 0, true, String(board_humidity).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we time interval for redrawing passes.
|
||||
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) {
|
||||
return;
|
||||
}
|
||||
lastUpdate = millis();
|
||||
|
||||
// Turn off display after 3 minutes with no change.
|
||||
if(!displayTurnedOff && millis() - lastRedraw > 3*60*1000) {
|
||||
u8x8.setPowerSave(1);
|
||||
displayTurnedOff = true;
|
||||
}
|
||||
|
||||
// Check if values which are shown on display changed from the last time.
|
||||
if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) {
|
||||
needRedraw = true;
|
||||
} else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) {
|
||||
needRedraw = true;
|
||||
} else if (knownBrightness != bri) {
|
||||
needRedraw = true;
|
||||
} else if (knownMode != strip.getMode()) {
|
||||
needRedraw = true;
|
||||
} else if (knownPalette != strip.getSegment(0).palette) {
|
||||
needRedraw = true;
|
||||
}
|
||||
|
||||
if (!needRedraw) {
|
||||
return;
|
||||
}
|
||||
needRedraw = false;
|
||||
|
||||
if (displayTurnedOff)
|
||||
{
|
||||
u8x8.setPowerSave(0);
|
||||
displayTurnedOff = false;
|
||||
}
|
||||
lastRedraw = millis();
|
||||
|
||||
// Update last known values.
|
||||
#if defined(ESP8266)
|
||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
||||
#else
|
||||
knownSsid = WiFi.SSID();
|
||||
#endif
|
||||
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
|
||||
knownBrightness = bri;
|
||||
knownMode = strip.getMode();
|
||||
knownPalette = strip.getSegment(0).palette;
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
|
||||
// First row with Wifi name
|
||||
u8x8.setCursor(1, 0);
|
||||
u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0));
|
||||
// Print `~` char to indicate that SSID is longer, than owr dicplay
|
||||
if (knownSsid.length() > u8x8.getCols())
|
||||
u8x8.print("~");
|
||||
|
||||
// Second row with IP or Psssword
|
||||
u8x8.setCursor(1, 1);
|
||||
// Print password in AP mode and if led is OFF.
|
||||
if (apActive && bri == 0)
|
||||
u8x8.print(apPass);
|
||||
else
|
||||
u8x8.print(knownIp);
|
||||
|
||||
// Third row with mode name
|
||||
u8x8.setCursor(2, 2);
|
||||
uint8_t qComma = 0;
|
||||
bool insideQuotes = false;
|
||||
uint8_t printedChars = 0;
|
||||
char singleJsonSymbol;
|
||||
|
||||
// Find the mode name in JSON
|
||||
for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownMode))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
// Fourth row with palette name
|
||||
u8x8.setCursor(2, 3);
|
||||
qComma = 0;
|
||||
insideQuotes = false;
|
||||
printedChars = 0;
|
||||
// Looking for palette name in JSON.
|
||||
for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownPalette))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
|
||||
u8x8.setFont(u8x8_font_open_iconic_embedded_1x1);
|
||||
u8x8.drawGlyph(0, 0, 80); // wifi icon
|
||||
u8x8.drawGlyph(0, 1, 68); // home icon
|
||||
u8x8.setFont(u8x8_font_open_iconic_weather_2x2);
|
||||
u8x8.drawGlyph(0, 2, 66 + (bri > 0 ? 3 : 0)); // sun/moon icon
|
||||
}
|
||||
|
||||
void UpdateBME280Data() {
|
||||
float temp(NAN), hum(NAN), pres(NAN);
|
||||
#ifdef Celsius
|
||||
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
|
||||
#else
|
||||
BME280::TempUnit tempUnit(BME280::TempUnit_Fahrenheit);
|
||||
#endif
|
||||
BME280::PresUnit presUnit(BME280::PresUnit_Pa);
|
||||
bme.read(pres, temp, hum, tempUnit, presUnit);
|
||||
SensorTemperature=temp;
|
||||
SensorHumidity=hum;
|
||||
SensorPressure=pres;
|
||||
}
|
||||
34
usermods/QuinLED_Dig_Uno_Temp_MQTT/readme.md
Normal file
34
usermods/QuinLED_Dig_Uno_Temp_MQTT/readme.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# QuinLED Dig Uno board
|
||||
|
||||
These files allow WLED 0.9.1 to report the temp sensor on the Quinled board to MQTT. I use it to report the board temp to Home Assistant via MQTT, so it will send notifications if something happens and the board start to heat up.
|
||||
This code uses Aircookie's WLED software. It has a premade file for user modifications. I use it to publish the temperature from the dallas temperature sensor on the Quinled board. The entries for the top of the WLED00 file, initializes the required libraries, and variables for the sensor. The .ino file waits for 60 seconds, and checks to see if the MQTT server is connected (thanks Aircoookie). It then poles the sensor, and published it using the MQTT service already running, using the main topic programmed in the WLED UI.
|
||||
|
||||
Installation of file: Copy and replace file in wled00 directory
|
||||
|
||||
## Project link
|
||||
|
||||
* [QuinLED-Dig-Uno](https://quinled.info/2018/09/15/quinled-dig-uno/) - Project link
|
||||
|
||||
### Platformio requirements
|
||||
|
||||
Uncomment `DallasTemperature@~3.8.0`,`OneWire@~2.3.5 under` `[common]` section in `platformio.ini`:
|
||||
|
||||
```ini
|
||||
# platformio.ini
|
||||
...
|
||||
[platformio]
|
||||
...
|
||||
; default_envs = esp07
|
||||
default_envs = d1_mini
|
||||
...
|
||||
[common]
|
||||
...
|
||||
lib_deps_external =
|
||||
...
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
U8g2@~2.27.3
|
||||
#For Dallas sensor uncomment following 2 lines
|
||||
DallasTemperature@~3.8.0
|
||||
OneWire@~2.3.5
|
||||
...
|
||||
```
|
||||
54
usermods/QuinLED_Dig_Uno_Temp_MQTT/usermod.cpp
Normal file
54
usermods/QuinLED_Dig_Uno_Temp_MQTT/usermod.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include <Arduino.h>
|
||||
#include "wled.h"
|
||||
//Intiating code for QuinLED Dig-Uno temp sensor
|
||||
//Uncomment Celsius if that is your prefered temperature scale
|
||||
#include <DallasTemperature.h> //Dallastemperature sensor
|
||||
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
|
||||
OneWire oneWire(18);
|
||||
#else //ESP8266 boards
|
||||
OneWire oneWire(14);
|
||||
#endif
|
||||
DallasTemperature sensor(&oneWire);
|
||||
long temptimer = millis();
|
||||
long lastMeasure = 0;
|
||||
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
|
||||
void userSetup()
|
||||
{
|
||||
// Start the DS18B20 sensor
|
||||
sensor.begin();
|
||||
}
|
||||
|
||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
||||
void userConnected()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void userLoop()
|
||||
{
|
||||
temptimer = millis();
|
||||
|
||||
// Timer to publishe new temperature every 60 seconds
|
||||
if (temptimer - lastMeasure > 60000) {
|
||||
lastMeasure = temptimer;
|
||||
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (mqtt != nullptr){
|
||||
sensor.requestTemperatures();
|
||||
|
||||
//Gets prefered temperature scale based on selection in definitions section
|
||||
#ifdef Celsius
|
||||
float board_temperature = sensor.getTempCByIndex(0);
|
||||
#else
|
||||
float board_temperature = sensors.getTempFByIndex(0);
|
||||
#endif
|
||||
|
||||
//Create character string populated with user defined device topic from the UI, and the read temperature. Then publish to MQTT server.
|
||||
char subuf[38];
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, "/temperature");
|
||||
mqtt->publish(subuf, 0, true, String(board_temperature).c_str());
|
||||
return;}
|
||||
return;}
|
||||
return;
|
||||
}
|
||||
71
usermods/Wemos_D1_mini+Wemos32_mini_shield/readme.md
Normal file
71
usermods/Wemos_D1_mini+Wemos32_mini_shield/readme.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Wemos D1 mini and Wemos32 mini shield
|
||||
- Installation of file: Copy and replace file in wled00 directory
|
||||
- For BME280 sensor use usermod_bme280.cpp. Copy to wled00 and rename to usermod.cpp
|
||||
- Added third choice of controller Heltec WiFi-Kit-8. Totally DIY but with OLED display.
|
||||
## Project repository
|
||||
- [Original repository](https://github.com/srg74/WLED-wemos-shield) - WLED Wemos shield repository
|
||||
- [Wemos shield project Wiki](https://github.com/srg74/WLED-wemos-shield/wiki)
|
||||
- [Precompiled WLED firmware](https://github.com/srg74/WLED-wemos-shield/tree/master/resources/Firmware)
|
||||
## Features
|
||||
- SSD1306 128x32 or 128x64 I2C OLED display
|
||||
- On screen IP address, SSID and controller status (e.g. ON or OFF, recent effect)
|
||||
- Auto display shutoff for saving display lifetime
|
||||
- Dallas temperature sensor
|
||||
- Reporting temperature to MQTT broker
|
||||
- Relay for energy saving
|
||||
|
||||
## Hardware
|
||||

|
||||
|
||||
## Functionality checked with
|
||||
|
||||
- Wemos D1 mini original v3.1 and clones
|
||||
- Wemos32 mini
|
||||
- PlatformIO
|
||||
- SSD1306 128x32 I2C OLED display
|
||||
- DS18B20 (temperature sensor)
|
||||
- BME280 (temperature, humidity and pressure sensor)
|
||||
- Push button (N.O. momentary switch)
|
||||
|
||||
### Platformio requirements
|
||||
|
||||
For Dallas sensor uncomment `U8g2@~2.27.3`,`DallasTemperature@~3.8.0`,`OneWire@~2.3.5 under` `[common]` section in `platformio.ini`:
|
||||
```ini
|
||||
# platformio.ini
|
||||
...
|
||||
[platformio]
|
||||
...
|
||||
; default_envs = esp07
|
||||
default_envs = d1_mini
|
||||
...
|
||||
[common]
|
||||
...
|
||||
lib_deps_external =
|
||||
...
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
U8g2@~2.27.3
|
||||
#For Dallas sensor uncomment following 2 lines
|
||||
DallasTemperature@~3.8.0
|
||||
OneWire@~2.3.5
|
||||
...
|
||||
```
|
||||
|
||||
For BME280 sensor uncomment `U8g2@~2.27.3`,`BME280@~3.0.0 under` `[common]` section in `platformio.ini`:
|
||||
```ini
|
||||
# platformio.ini
|
||||
...
|
||||
[platformio]
|
||||
...
|
||||
; default_envs = esp07
|
||||
default_envs = d1_mini
|
||||
...
|
||||
[common]
|
||||
...
|
||||
lib_deps_external =
|
||||
...
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
U8g2@~2.27.3
|
||||
#For BME280 sensor uncomment following
|
||||
BME280@~3.0.0
|
||||
...
|
||||
```
|
||||
246
usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp
Normal file
246
usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||
#include <OneWire.h> // Dallas temperature sensor
|
||||
|
||||
//Dallas sensor quick reading. Credit to - Author: Peter Scargill, August 17th, 2013
|
||||
int16_t Dallas(int x, byte start)
|
||||
{
|
||||
OneWire DallasSensor(x);
|
||||
byte i;
|
||||
byte data[2];
|
||||
int16_t result;
|
||||
do
|
||||
{
|
||||
DallasSensor.reset();
|
||||
DallasSensor.write(0xCC);
|
||||
DallasSensor.write(0xBE);
|
||||
for ( i = 0; i < 2; i++) data[i] = DallasSensor.read();
|
||||
result=(data[1]<<8)|data[0];
|
||||
result>>=4; if (data[1]&128) result|=61440;
|
||||
if (data[0]&8) ++result;
|
||||
DallasSensor.reset();
|
||||
DallasSensor.write(0xCC);
|
||||
DallasSensor.write(0x44,1);
|
||||
if (start) delay(1000);
|
||||
} while (start--);
|
||||
return result;
|
||||
}
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uint8_t SCL_PIN = 22;
|
||||
uint8_t SDA_PIN = 21;
|
||||
uint8_t DALLAS_PIN =23;
|
||||
#else
|
||||
uint8_t SCL_PIN = 5;
|
||||
uint8_t SDA_PIN = 4;
|
||||
uint8_t DALLAS_PIN =13;
|
||||
// uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
||||
#endif
|
||||
|
||||
//The SCL and SDA pins are defined here.
|
||||
//ESP8266 Wemos D1 mini board use SCL=5 SDA=4 while ESP32 Wemos32 mini board use SCL=22 SDA=21
|
||||
#define U8X8_PIN_SCL SCL_PIN
|
||||
#define U8X8_PIN_SDA SDA_PIN
|
||||
//#define U8X8_PIN_RESET RST_PIN // Uncoment for Heltec WiFi-Kit-8
|
||||
|
||||
// Dallas sensor reading timer
|
||||
long temptimer = millis();
|
||||
long lastMeasure = 0;
|
||||
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
|
||||
|
||||
// If display does not work or looks corrupted check the
|
||||
// constructor reference:
|
||||
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
|
||||
// or check the gallery:
|
||||
// https://github.com/olikraus/u8g2/wiki/gallery
|
||||
// --> First choise of cheap I2C OLED 128X32 0.91"
|
||||
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
|
||||
// --> Second choise of cheap I2C OLED 128X64 0.96" or 1.3"
|
||||
//U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
|
||||
// --> Third choise of Heltec WiFi-Kit-8 OLED 128X32 0.91"
|
||||
//U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_RESET, U8X8_PIN_SCL, U8X8_PIN_SDA); // Constructor for Heltec WiFi-Kit-8
|
||||
// gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
void userSetup() {
|
||||
//Serial.begin(115200);
|
||||
|
||||
Dallas (DALLAS_PIN,1);
|
||||
u8x8.begin();
|
||||
u8x8.setPowerSave(0);
|
||||
u8x8.setFlipMode(1);
|
||||
u8x8.setContrast(10); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
u8x8.drawString(0, 0, "Loading...");
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
// interfaces here
|
||||
void userConnected() {}
|
||||
|
||||
// needRedraw marks if redraw is required to prevent often redrawing.
|
||||
bool needRedraw = true;
|
||||
|
||||
// Next variables hold the previous known values to determine if redraw is
|
||||
// required.
|
||||
String knownSsid = "";
|
||||
IPAddress knownIp;
|
||||
uint8_t knownBrightness = 0;
|
||||
uint8_t knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
|
||||
long lastUpdate = 0;
|
||||
long lastRedraw = 0;
|
||||
bool displayTurnedOff = false;
|
||||
// How often we are redrawing screen
|
||||
#define USER_LOOP_REFRESH_RATE_MS 5000
|
||||
|
||||
void userLoop() {
|
||||
|
||||
//----> Dallas temperature sensor MQTT publishing
|
||||
temptimer = millis();
|
||||
// Timer to publishe new temperature every 60 seconds
|
||||
if (temptimer - lastMeasure > 60000)
|
||||
{
|
||||
lastMeasure = temptimer;
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (mqtt != nullptr)
|
||||
{
|
||||
// Serial.println(Dallas(DALLAS_PIN,0));
|
||||
//Gets prefered temperature scale based on selection in definitions section
|
||||
#ifdef Celsius
|
||||
int16_t board_temperature = Dallas(DALLAS_PIN,0);
|
||||
#else
|
||||
int16_t board_temperature = (Dallas(DALLAS_PIN,0)* 1.8 + 32);
|
||||
#endif
|
||||
//Create character string populated with user defined device topic from the UI, and the read temperature. Then publish to MQTT server.
|
||||
String t = String(mqttDeviceTopic);
|
||||
t += "/temperature";
|
||||
mqtt->publish(t.c_str(), 0, true, String(board_temperature).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we time interval for redrawing passes.
|
||||
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) {
|
||||
return;
|
||||
}
|
||||
lastUpdate = millis();
|
||||
|
||||
// Turn off display after 3 minutes with no change.
|
||||
if(!displayTurnedOff && millis() - lastRedraw > 3*60*1000) {
|
||||
u8x8.setPowerSave(1);
|
||||
displayTurnedOff = true;
|
||||
}
|
||||
|
||||
// Check if values which are shown on display changed from the last time.
|
||||
if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) {
|
||||
needRedraw = true;
|
||||
} else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) {
|
||||
needRedraw = true;
|
||||
} else if (knownBrightness != bri) {
|
||||
needRedraw = true;
|
||||
} else if (knownMode != strip.getMode()) {
|
||||
needRedraw = true;
|
||||
} else if (knownPalette != strip.getSegment(0).palette) {
|
||||
needRedraw = true;
|
||||
}
|
||||
|
||||
if (!needRedraw) {
|
||||
return;
|
||||
}
|
||||
needRedraw = false;
|
||||
|
||||
if (displayTurnedOff)
|
||||
{
|
||||
u8x8.setPowerSave(0);
|
||||
displayTurnedOff = false;
|
||||
}
|
||||
lastRedraw = millis();
|
||||
|
||||
// Update last known values.
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
knownSsid = WiFi.SSID();
|
||||
#else
|
||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
||||
#endif
|
||||
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
|
||||
knownBrightness = bri;
|
||||
knownMode = strip.getMode();
|
||||
knownPalette = strip.getSegment(0).palette;
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
|
||||
// First row with Wifi name
|
||||
u8x8.setCursor(1, 0);
|
||||
u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0));
|
||||
// Print `~` char to indicate that SSID is longer, than owr dicplay
|
||||
if (knownSsid.length() > u8x8.getCols())
|
||||
u8x8.print("~");
|
||||
|
||||
// Second row with IP or Psssword
|
||||
u8x8.setCursor(1, 1);
|
||||
// Print password in AP mode and if led is OFF.
|
||||
if (apActive && bri == 0)
|
||||
u8x8.print(apPass);
|
||||
else
|
||||
u8x8.print(knownIp);
|
||||
|
||||
// Third row with mode name
|
||||
u8x8.setCursor(2, 2);
|
||||
uint8_t qComma = 0;
|
||||
bool insideQuotes = false;
|
||||
uint8_t printedChars = 0;
|
||||
char singleJsonSymbol;
|
||||
|
||||
// Find the mode name in JSON
|
||||
for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownMode))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
// Fourth row with palette name
|
||||
u8x8.setCursor(2, 3);
|
||||
qComma = 0;
|
||||
insideQuotes = false;
|
||||
printedChars = 0;
|
||||
// Looking for palette name in JSON.
|
||||
for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownPalette))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
|
||||
u8x8.setFont(u8x8_font_open_iconic_embedded_1x1);
|
||||
u8x8.drawGlyph(0, 0, 80); // wifi icon
|
||||
u8x8.drawGlyph(0, 1, 68); // home icon
|
||||
u8x8.setFont(u8x8_font_open_iconic_weather_2x2);
|
||||
u8x8.drawGlyph(0, 2, 66 + (bri > 0 ? 3 : 0)); // sun/moon icon
|
||||
}
|
||||
268
usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp
Normal file
268
usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||
#include <Wire.h>
|
||||
#include <BME280I2C.h> //BME280 sensor
|
||||
|
||||
void UpdateBME280Data();
|
||||
|
||||
#define Celsius // Show temperature mesaurement in Celcius otherwise is in Fahrenheit
|
||||
BME280I2C bme; // Default : forced mode, standby time = 1000 ms
|
||||
// Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off,
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
|
||||
uint8_t SCL_PIN = 22;
|
||||
uint8_t SDA_PIN = 21;
|
||||
#else //ESP8266 boards
|
||||
uint8_t SCL_PIN = 5;
|
||||
uint8_t SDA_PIN = 4;
|
||||
// uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
||||
#endif
|
||||
|
||||
//The SCL and SDA pins are defined here.
|
||||
//ESP8266 Wemos D1 mini board use SCL=5 SDA=4 while ESP32 Wemos32 mini board use SCL=22 SDA=21
|
||||
#define U8X8_PIN_SCL SCL_PIN
|
||||
#define U8X8_PIN_SDA SDA_PIN
|
||||
//#define U8X8_PIN_RESET RST_PIN // Uncoment for Heltec WiFi-Kit-8
|
||||
|
||||
// If display does not work or looks corrupted check the
|
||||
// constructor reference:
|
||||
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
|
||||
// or check the gallery:
|
||||
// https://github.com/olikraus/u8g2/wiki/gallery
|
||||
// --> First choise of cheap I2C OLED 128X32 0.91"
|
||||
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
|
||||
// --> Second choise of cheap I2C OLED 128X64 0.96" or 1.3"
|
||||
//U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
|
||||
// --> Third choise of Heltec WiFi-Kit-8 OLED 128X32 0.91"
|
||||
//U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_RESET, U8X8_PIN_SCL, U8X8_PIN_SDA); // Constructor for Heltec WiFi-Kit-8
|
||||
// gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
|
||||
// BME280 sensor timer
|
||||
long tempTimer = millis();
|
||||
long lastMeasure = 0;
|
||||
|
||||
float SensorPressure(NAN);
|
||||
float SensorTemperature(NAN);
|
||||
float SensorHumidity(NAN);
|
||||
|
||||
void userSetup() {
|
||||
u8x8.begin();
|
||||
u8x8.setPowerSave(0);
|
||||
u8x8.setFlipMode(1);
|
||||
u8x8.setContrast(10); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
u8x8.drawString(0, 0, "Loading...");
|
||||
Wire.begin(SDA_PIN,SCL_PIN);
|
||||
|
||||
while(!bme.begin())
|
||||
{
|
||||
Serial.println("Could not find BME280I2C sensor!");
|
||||
delay(1000);
|
||||
}
|
||||
switch(bme.chipModel())
|
||||
{
|
||||
case BME280::ChipModel_BME280:
|
||||
Serial.println("Found BME280 sensor! Success.");
|
||||
break;
|
||||
case BME280::ChipModel_BMP280:
|
||||
Serial.println("Found BMP280 sensor! No Humidity available.");
|
||||
break;
|
||||
default:
|
||||
Serial.println("Found UNKNOWN sensor! Error!");
|
||||
}
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
// interfaces here
|
||||
void userConnected() {}
|
||||
|
||||
// needRedraw marks if redraw is required to prevent often redrawing.
|
||||
bool needRedraw = true;
|
||||
|
||||
// Next variables hold the previous known values to determine if redraw is
|
||||
// required.
|
||||
String knownSsid = "";
|
||||
IPAddress knownIp;
|
||||
uint8_t knownBrightness = 0;
|
||||
uint8_t knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
|
||||
long lastUpdate = 0;
|
||||
long lastRedraw = 0;
|
||||
bool displayTurnedOff = false;
|
||||
// How often we are redrawing screen
|
||||
#define USER_LOOP_REFRESH_RATE_MS 5000
|
||||
|
||||
void userLoop() {
|
||||
|
||||
// BME280 sensor MQTT publishing
|
||||
tempTimer = millis();
|
||||
// Timer to publish new sensor data every 60 seconds
|
||||
if (tempTimer - lastMeasure > 60000)
|
||||
{
|
||||
lastMeasure = tempTimer;
|
||||
|
||||
// Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (mqtt != nullptr)
|
||||
{
|
||||
UpdateBME280Data();
|
||||
float board_temperature = SensorTemperature;
|
||||
float board_pressure = SensorPressure;
|
||||
float board_humidity = SensorHumidity;
|
||||
|
||||
// Create string populated with user defined device topic from the UI, and the read temperature, humidity and pressure. Then publish to MQTT server.
|
||||
String t = String(mqttDeviceTopic);
|
||||
t += "/temperature";
|
||||
mqtt->publish(t.c_str(), 0, true, String(board_temperature).c_str());
|
||||
String p = String(mqttDeviceTopic);
|
||||
p += "/pressure";
|
||||
mqtt->publish(p.c_str(), 0, true, String(board_pressure).c_str());
|
||||
String h = String(mqttDeviceTopic);
|
||||
h += "/humidity";
|
||||
mqtt->publish(h.c_str(), 0, true, String(board_humidity).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we time interval for redrawing passes.
|
||||
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) {
|
||||
return;
|
||||
}
|
||||
lastUpdate = millis();
|
||||
|
||||
// Turn off display after 3 minutes with no change.
|
||||
if(!displayTurnedOff && millis() - lastRedraw > 3*60*1000) {
|
||||
u8x8.setPowerSave(1);
|
||||
displayTurnedOff = true;
|
||||
}
|
||||
|
||||
// Check if values which are shown on display changed from the last time.
|
||||
if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) {
|
||||
needRedraw = true;
|
||||
} else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) {
|
||||
needRedraw = true;
|
||||
} else if (knownBrightness != bri) {
|
||||
needRedraw = true;
|
||||
} else if (knownMode != strip.getMode()) {
|
||||
needRedraw = true;
|
||||
} else if (knownPalette != strip.getSegment(0).palette) {
|
||||
needRedraw = true;
|
||||
}
|
||||
|
||||
if (!needRedraw) {
|
||||
return;
|
||||
}
|
||||
needRedraw = false;
|
||||
|
||||
if (displayTurnedOff)
|
||||
{
|
||||
u8x8.setPowerSave(0);
|
||||
displayTurnedOff = false;
|
||||
}
|
||||
lastRedraw = millis();
|
||||
|
||||
// Update last known values.
|
||||
#if defined(ESP8266)
|
||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
||||
#else
|
||||
knownSsid = WiFi.SSID();
|
||||
#endif
|
||||
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
|
||||
knownBrightness = bri;
|
||||
knownMode = strip.getMode();
|
||||
knownPalette = strip.getSegment(0).palette;
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
|
||||
// First row with Wifi name
|
||||
u8x8.setCursor(1, 0);
|
||||
u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0));
|
||||
// Print `~` char to indicate that SSID is longer, than owr dicplay
|
||||
if (knownSsid.length() > u8x8.getCols())
|
||||
u8x8.print("~");
|
||||
|
||||
// Second row with IP or Psssword
|
||||
u8x8.setCursor(1, 1);
|
||||
// Print password in AP mode and if led is OFF.
|
||||
if (apActive && bri == 0)
|
||||
u8x8.print(apPass);
|
||||
else
|
||||
u8x8.print(knownIp);
|
||||
|
||||
// Third row with mode name
|
||||
u8x8.setCursor(2, 2);
|
||||
uint8_t qComma = 0;
|
||||
bool insideQuotes = false;
|
||||
uint8_t printedChars = 0;
|
||||
char singleJsonSymbol;
|
||||
|
||||
// Find the mode name in JSON
|
||||
for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownMode))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
// Fourth row with palette name
|
||||
u8x8.setCursor(2, 3);
|
||||
qComma = 0;
|
||||
insideQuotes = false;
|
||||
printedChars = 0;
|
||||
// Looking for palette name in JSON.
|
||||
for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownPalette))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
|
||||
u8x8.setFont(u8x8_font_open_iconic_embedded_1x1);
|
||||
u8x8.drawGlyph(0, 0, 80); // wifi icon
|
||||
u8x8.drawGlyph(0, 1, 68); // home icon
|
||||
u8x8.setFont(u8x8_font_open_iconic_weather_2x2);
|
||||
u8x8.drawGlyph(0, 2, 66 + (bri > 0 ? 3 : 0)); // sun/moon icon
|
||||
}
|
||||
|
||||
void UpdateBME280Data() {
|
||||
float temp(NAN), hum(NAN), pres(NAN);
|
||||
#ifdef Celsius
|
||||
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
|
||||
BME280::PresUnit presUnit(BME280::PresUnit_Pa);
|
||||
bme.read(pres, temp, hum, tempUnit, presUnit);
|
||||
#else
|
||||
BME280::TempUnit tempUnit(BME280::TempUnit_Fahrenheit);
|
||||
BME280::PresUnit presUnit(BME280::PresUnit_Pa);
|
||||
bme.read(pres, temp, hum, tempUnit, presUnit);
|
||||
#endif
|
||||
SensorTemperature=temp;
|
||||
SensorHumidity=hum;
|
||||
SensorPressure=pres;
|
||||
}
|
||||
12
usermods/battery_keypad_controller/README.md
Normal file
12
usermods/battery_keypad_controller/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Battery powered controller with keypad
|
||||
|
||||
I'm using this controller for a festival totem. Runs on 3 18650 Cells, can deliver >5A current.
|
||||
|
||||
Via keypad one can select 8 presets, change effect, effect speed, effect intensity and palette. Brightness can be
|
||||
adjusted with a potentiometer.
|
||||
|
||||
## Pictures
|
||||
|
||||

|
||||

|
||||

|
||||
BIN
usermods/battery_keypad_controller/assets/bat-key-ctrl-1.jpg
Normal file
BIN
usermods/battery_keypad_controller/assets/bat-key-ctrl-1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 319 KiB |
BIN
usermods/battery_keypad_controller/assets/bat-key-ctrl-2.jpg
Normal file
BIN
usermods/battery_keypad_controller/assets/bat-key-ctrl-2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 250 KiB |
BIN
usermods/battery_keypad_controller/assets/bat-key-ctrl-3.jpg
Normal file
BIN
usermods/battery_keypad_controller/assets/bat-key-ctrl-3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 344 KiB |
151
usermods/battery_keypad_controller/wled06_usermod.ino
Normal file
151
usermods/battery_keypad_controller/wled06_usermod.ino
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* WLED usermod for keypad and brightness-pot.
|
||||
* 3'2020 https://github.com/hobbyquaker
|
||||
*/
|
||||
|
||||
#include <Keypad.h>
|
||||
const byte keypad_rows = 4;
|
||||
const byte keypad_cols = 4;
|
||||
char keypad_keys[keypad_rows][keypad_cols] = {
|
||||
{'1', '2', '3', 'A'},
|
||||
{'4', '5', '6', 'B'},
|
||||
{'7', '8', '9', 'C'},
|
||||
{'*', '0', '#', 'D'}
|
||||
};
|
||||
|
||||
byte keypad_colPins[keypad_rows] = {D3, D2, D1, D0};
|
||||
byte keypad_rowPins[keypad_cols] = {D7, D6, D5, D4};
|
||||
|
||||
Keypad myKeypad = Keypad(makeKeymap(keypad_keys), keypad_rowPins, keypad_colPins, keypad_rows, keypad_cols);
|
||||
|
||||
void userSetup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void userConnected()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
long lastTime = 0;
|
||||
int delayMs = 20; //we want to do something every 2 seconds
|
||||
|
||||
void userLoop()
|
||||
{
|
||||
if (millis()-lastTime > delayMs)
|
||||
{
|
||||
|
||||
long analog = analogRead(0);
|
||||
int new_bri = 1;
|
||||
if (analog > 900) {
|
||||
new_bri = 255;
|
||||
} else if (analog > 30) {
|
||||
new_bri = dim8_video(map(analog, 31, 900, 16, 255));
|
||||
}
|
||||
if (bri != new_bri) {
|
||||
bri = new_bri;
|
||||
colorUpdated(1);
|
||||
|
||||
}
|
||||
|
||||
char myKey = myKeypad.getKey();
|
||||
if (myKey != NULL) {
|
||||
switch (myKey) {
|
||||
case '1':
|
||||
applyPreset(1);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
case '2':
|
||||
applyPreset(2);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
case '3':
|
||||
applyPreset(3);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
case '4':
|
||||
applyPreset(4);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
case '5':
|
||||
applyPreset(5);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
case '6':
|
||||
applyPreset(6);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
case 'A':
|
||||
applyPreset(7);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
case 'B':
|
||||
applyPreset(8);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
|
||||
case '7':
|
||||
effectCurrent += 1;
|
||||
if (effectCurrent >= MODE_COUNT) effectCurrent = 0;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
case '*':
|
||||
effectCurrent -= 1;
|
||||
if (effectCurrent < 0) effectCurrent = (MODE_COUNT-1);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
|
||||
case '8':
|
||||
if (effectSpeed < 240) {
|
||||
effectSpeed += 12;
|
||||
} else if (effectSpeed < 255) {
|
||||
effectSpeed += 1;
|
||||
}
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
case '0':
|
||||
if (effectSpeed > 15) {
|
||||
effectSpeed -= 12;
|
||||
} else if (effectSpeed > 0) {
|
||||
effectSpeed -= 1;
|
||||
}
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
|
||||
case '9':
|
||||
if (effectIntensity < 240) {
|
||||
effectIntensity += 12;
|
||||
} else if (effectIntensity < 255) {
|
||||
effectIntensity += 1;
|
||||
}
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
case '#':
|
||||
if (effectIntensity > 15) {
|
||||
effectIntensity -= 12;
|
||||
} else if (effectIntensity > 0) {
|
||||
effectIntensity -= 1;
|
||||
}
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
effectPalette += 1;
|
||||
if (effectPalette >= 50) effectPalette = 0;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
case 'D':
|
||||
effectPalette -= 1;
|
||||
if (effectPalette <= 0) effectPalette = 50;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
lastTime = millis();
|
||||
}
|
||||
|
||||
}
|
||||
28
usermods/blynk_relay_control/README.md
Normal file
28
usermods/blynk_relay_control/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Blynk controllable relay
|
||||
This usermod allows controlling a relay state from the user variables. It also allows the user variables to be set over Blynk.
|
||||
|
||||
Optionally, the servo can have a reset timer to go back to it's default state after an interval. This interval is set through userVar1.
|
||||
|
||||
## Instalation
|
||||
|
||||
Replace the WLED06_usermod.ino file in Aircoookies WLED folder with the one here.
|
||||
|
||||
## Customizations
|
||||
|
||||
Update the following parameters in WLED06_usermod.ino to configure the mod's behavior:
|
||||
|
||||
```cpp
|
||||
//Which pin is the relay connected to
|
||||
#define RELAY_PIN 5
|
||||
//Which pin state should the relay default to
|
||||
#define RELAY_PIN_DEFAULT LOW
|
||||
//If >0 The controller returns to RELAY_PIN_DEFAULT after this time in milliseconds
|
||||
#define RELAY_PIN_TIMER_DEFAULT 3000
|
||||
|
||||
//Blynk virtual pin for controlling relay
|
||||
#define BLYNK_USER_VAR0_PIN V9
|
||||
//Blynk virtual pin for controlling relay timer
|
||||
#define BLYNK_USER_VAR1_PIN V10
|
||||
//Number of milliseconds between updating blynk
|
||||
#define BLYNK_RELAY_UPDATE_INTERVAL 5000
|
||||
```
|
||||
96
usermods/blynk_relay_control/wled06_usermod.ino
Normal file
96
usermods/blynk_relay_control/wled06_usermod.ino
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* This file allows you to add own functionality to WLED more easily
|
||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in wled_eeprom.h)
|
||||
* bytes 2400+ are currently ununsed, but might be used for future wled features
|
||||
*/
|
||||
|
||||
//Use userVar0 (API calls &U0=, uint16_t) to set relay state
|
||||
#define relayPinState userVar0
|
||||
//Use userVar1 (API calls &U1=, uint16_t) to set relay timer duration
|
||||
//Ignored if 0, otherwise number of milliseconds to allow relay to stay in
|
||||
//non default state.
|
||||
#define relayTimerInterval userVar1
|
||||
|
||||
//Which pin is the relay connected to
|
||||
#define RELAY_PIN 5
|
||||
//Which pin state should the relay default to
|
||||
#define RELAY_PIN_DEFAULT LOW
|
||||
//If >0 The controller returns to RELAY_PIN_DEFAULT after this time in milliseconds
|
||||
#define RELAY_PIN_TIMER_DEFAULT 3000
|
||||
|
||||
//Blynk virtual pin for controlling relay
|
||||
#define BLYNK_USER_VAR0_PIN V9
|
||||
//Blynk virtual pin for controlling relay timer
|
||||
#define BLYNK_USER_VAR1_PIN V10
|
||||
//Number of milliseconds between updating blynk
|
||||
#define BLYNK_RELAY_UPDATE_INTERVAL 5000
|
||||
|
||||
//Is the timer for resetting the relay active
|
||||
bool relayTimerStarted = false;
|
||||
//millis() time after which relay will be reset
|
||||
unsigned long relayTimeToDefault = 0;
|
||||
//millis() time after which relay vars in Blynk will be sent
|
||||
unsigned long relayBlynkUpdateTime = 0;
|
||||
|
||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
void userSetup()
|
||||
{
|
||||
relayPinState = RELAY_PIN_DEFAULT;
|
||||
relayTimerInterval = RELAY_PIN_TIMER_DEFAULT;
|
||||
pinMode(RELAY_PIN, OUTPUT);
|
||||
digitalWrite(RELAY_PIN, relayPinState);
|
||||
}
|
||||
|
||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
||||
void userConnected()
|
||||
{
|
||||
}
|
||||
|
||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
||||
void userLoop()
|
||||
{
|
||||
//Normalize relayPinState to an accepted value
|
||||
if (relayPinState != HIGH && relayPinState != LOW) {
|
||||
relayPinState = RELAY_PIN_DEFAULT;
|
||||
}
|
||||
//If relay changes and relayTimerInterval is set, start a timer to change back
|
||||
if (relayTimerInterval != 0 &&
|
||||
relayPinState != RELAY_PIN_DEFAULT &&
|
||||
!relayTimerStarted ) {
|
||||
relayTimerStarted = true;
|
||||
relayTimeToDefault = millis() + relayTimerInterval;
|
||||
}
|
||||
//If manually changed back to default, cancel timer
|
||||
if (relayTimerStarted && relayPinState == RELAY_PIN_DEFAULT ) {
|
||||
relayTimerStarted = false;
|
||||
}
|
||||
//If timer completes, set relay back to default
|
||||
if (relayTimerStarted && millis() > relayTimeToDefault) {
|
||||
relayPinState = RELAY_PIN_DEFAULT;
|
||||
relayTimerStarted = false;
|
||||
}
|
||||
digitalWrite(RELAY_PIN, relayPinState);
|
||||
updateRelayBlynk();
|
||||
}
|
||||
|
||||
//Update Blynk with state of userVars at BLYNK_RELAY_UPDATE_INTERVAL
|
||||
void updateRelayBlynk()
|
||||
{
|
||||
if (!WLED_CONNECTED) return;
|
||||
if (relayBlynkUpdateTime > millis()) return;
|
||||
Blynk.virtualWrite(BLYNK_USER_VAR0_PIN, userVar0);
|
||||
Blynk.virtualWrite(BLYNK_USER_VAR1_PIN, userVar1);
|
||||
relayBlynkUpdateTime = millis() + BLYNK_RELAY_UPDATE_INTERVAL;
|
||||
}
|
||||
|
||||
//Add Blynk callback for setting userVar0
|
||||
BLYNK_WRITE(BLYNK_USER_VAR0_PIN)
|
||||
{
|
||||
userVar0 = param.asInt();
|
||||
}
|
||||
//Add Blynk callback for setting userVar1
|
||||
BLYNK_WRITE(BLYNK_USER_VAR1_PIN)
|
||||
{
|
||||
userVar1 = param.asInt();
|
||||
}
|
||||
23
usermods/project_cars_shiftlight/readme.md
Normal file
23
usermods/project_cars_shiftlight/readme.md
Normal file
@@ -0,0 +1,23 @@
|
||||
### Shift Light for Project Cars
|
||||
|
||||
Turn your WLED lights into a rev light and shift indicator for Project Cars.
|
||||
|
||||
It is pretty straight forward to use.
|
||||
|
||||
1. Make sure, your WLED device and your PC/console are on the same network and can talk to each other
|
||||
|
||||
2. Go to the gameplay settings menu in PCARS and enable UDP. There are 9 numbers you can choose from. This is the refresh rate. The lower the number, the better. But you might run into problems at faster rates.
|
||||
|
||||
| Number | Updates/Second |
|
||||
| ------ | -------------- |
|
||||
| 1 | 60 |
|
||||
| 2 | 50 |
|
||||
| 3 | 40 |
|
||||
| 4 | 30 |
|
||||
| 5 | 20 |
|
||||
| 6 | 15 |
|
||||
| 7 | 10 |
|
||||
| 8 | 05 |
|
||||
| 9 | 1 |
|
||||
|
||||
3. once you enter a race, WLED should automatically shift to PCARS mode. Done.
|
||||
96
usermods/project_cars_shiftlight/wled06_usermod.ino
Normal file
96
usermods/project_cars_shiftlight/wled06_usermod.ino
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Car rev display and shift indicator for Project Cars
|
||||
*
|
||||
* This works via the UDP telemetry function. You'll need to enable it in the settings of the game.
|
||||
* I've had good results with settings around 5 (20 fps).
|
||||
*
|
||||
*/
|
||||
const uint8_t PCARS_dimcolor = 20;
|
||||
WiFiUDP UDP;
|
||||
const unsigned int PCARS_localUdpPort = 5606; // local port to listen on
|
||||
char PCARS_packet[2048];
|
||||
|
||||
char PCARS_tempChar[2]; // Temporary array for u16 conversion
|
||||
|
||||
u16 PCARS_RPM;
|
||||
u16 PCARS_maxRPM;
|
||||
|
||||
long PCARS_lastRead = millis() - 2001;
|
||||
float PCARS_rpmRatio;
|
||||
|
||||
|
||||
void userSetup()
|
||||
{
|
||||
UDP.begin(PCARS_localUdpPort);
|
||||
}
|
||||
|
||||
void userConnected()
|
||||
{
|
||||
// new wifi, who dis?
|
||||
}
|
||||
|
||||
void userLoop()
|
||||
{
|
||||
PCARS_readValues();
|
||||
if (PCARS_lastRead > millis() - 2000) {
|
||||
PCARS_buildcolorbars();
|
||||
}
|
||||
}
|
||||
|
||||
void PCARS_readValues() {
|
||||
|
||||
int PCARS_packetSize = UDP.parsePacket();
|
||||
if (PCARS_packetSize) {
|
||||
int len = UDP.read(PCARS_packet, PCARS_packetSize);
|
||||
if (len > 0) {
|
||||
PCARS_packet[len] = 0;
|
||||
}
|
||||
if (len == 1367) { // Telemetry packet. Ignoring everything else.
|
||||
PCARS_lastRead = millis();
|
||||
|
||||
arlsLock(realtimeTimeoutMs, REALTIME_MODE_GENERIC);
|
||||
// current RPM
|
||||
memcpy(&PCARS_tempChar, &PCARS_packet[124], 2);
|
||||
PCARS_RPM = (PCARS_tempChar[1] << 8) + PCARS_tempChar[0];
|
||||
|
||||
// max RPM
|
||||
memcpy(&PCARS_tempChar, &PCARS_packet[126], 2);
|
||||
PCARS_maxRPM = (PCARS_tempChar[1] << 8) + PCARS_tempChar[0];
|
||||
|
||||
if (PCARS_maxRPM) {
|
||||
PCARS_rpmRatio = constrain((float)PCARS_RPM / (float)PCARS_maxRPM, 0, 1);
|
||||
} else {
|
||||
PCARS_rpmRatio = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void PCARS_buildcolorbars() {
|
||||
boolean activated = false;
|
||||
float ledratio = 0;
|
||||
|
||||
for (uint16_t i = 0; i < ledCount; i++) {
|
||||
if (PCARS_rpmRatio < .95 || (millis() % 100 > 70 )) {
|
||||
|
||||
ledratio = (float)i / (float)ledCount;
|
||||
if (ledratio < PCARS_rpmRatio) {
|
||||
activated = true;
|
||||
} else {
|
||||
activated = false;
|
||||
}
|
||||
if (ledratio > 0.66) {
|
||||
setRealtimePixel(i, 0, 0, PCARS_dimcolor + ((255 - PCARS_dimcolor)*activated), 0);
|
||||
} else if (ledratio > 0.33) {
|
||||
setRealtimePixel(i, PCARS_dimcolor + ((255 - PCARS_dimcolor)*activated), 0, 0, 0);
|
||||
} else {
|
||||
setRealtimePixel(i, 0, PCARS_dimcolor + ((255 - PCARS_dimcolor)*activated), 0, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setRealtimePixel(i, 0, 0, 0, 0);
|
||||
|
||||
}
|
||||
}
|
||||
colorUpdated(5);
|
||||
strip.show();
|
||||
}
|
||||
18
usermods/readme.md
Normal file
18
usermods/readme.md
Normal file
@@ -0,0 +1,18 @@
|
||||
### Usermods
|
||||
|
||||
This folder serves as a repository for usermods (custom `usermod.cpp` files)!
|
||||
|
||||
If you have created an usermod that you believe is useful (for example to support a particular sensor, display, feature...), feel free to contribute by opening a pull request!
|
||||
|
||||
In order for other people to be able to have fun with your usermod, please keep these points in mind:
|
||||
|
||||
- Create a folder in this folder with a descriptive name (for example `usermod_ds18b20_temp_sensor_mqtt`)
|
||||
- Include your custom `usermod.cpp` file
|
||||
- If your usermod requires changes to other WLED files, please write a `readme.md` outlining the steps one has to take to use the usermod
|
||||
- Create a pull request!
|
||||
- If your feature is useful for the majority of WLED users, I will consider adding it to the base code!
|
||||
|
||||
While I do my best to not break too much, keep in mind that as WLED is being updated, usermods might break.
|
||||
I am not actively maintaining any usermod in this directory, that is your responsibility as the creator of the usermod.
|
||||
|
||||
Thank you for your help :)
|
||||
62
usermods/rotary_encoder_change_brightness/usermod.cpp
Normal file
62
usermods/rotary_encoder_change_brightness/usermod.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "wled.h"
|
||||
/*
|
||||
* This file allows you to add own functionality to WLED more easily
|
||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
|
||||
* bytes 2400+ are currently ununsed, but might be used for future wled features
|
||||
*/
|
||||
|
||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
||||
|
||||
/*
|
||||
** Rotary Encoder Example
|
||||
** Use the Sparkfun Rotary Encoder to vary brightness of LED
|
||||
**
|
||||
** Sample the encoder at 500Hz using the millis() function
|
||||
*/
|
||||
|
||||
int fadeAmount = 5; // how many points to fade the Neopixel with each step
|
||||
unsigned long currentTime;
|
||||
unsigned long loopTime;
|
||||
const int pinA = D6; // DT from encoder
|
||||
const int pinB = D7; // CLK from encoder
|
||||
|
||||
unsigned char Enc_A;
|
||||
unsigned char Enc_B;
|
||||
unsigned char Enc_A_prev = 0;
|
||||
|
||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
void userSetup() {
|
||||
pinMode(pinA, INPUT_PULLUP);
|
||||
pinMode(pinB, INPUT_PULLUP);
|
||||
currentTime = millis();
|
||||
loopTime = currentTime;
|
||||
}
|
||||
|
||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
||||
void userConnected() {
|
||||
}
|
||||
|
||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
||||
void userLoop() {
|
||||
currentTime = millis(); // get the current elapsed time
|
||||
if(currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz
|
||||
{
|
||||
int Enc_A = digitalRead(pinA); // Read encoder pins
|
||||
int Enc_B = digitalRead(pinB);
|
||||
if((! Enc_A) && (Enc_A_prev)) { // A has gone from high to low
|
||||
if(Enc_B == HIGH) { // B is high so clockwise
|
||||
if(bri + fadeAmount <= 255) bri += fadeAmount; // increase the brightness, dont go over 255
|
||||
|
||||
} else if (Enc_B == LOW) { // B is low so counter-clockwise
|
||||
if(bri - fadeAmount >= 0) bri -= fadeAmount; // decrease the brightness, dont go below 0
|
||||
}
|
||||
}
|
||||
Enc_A_prev = Enc_A; // Store value of A for next time
|
||||
loopTime = currentTime; // Updates loopTime
|
||||
|
||||
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
||||
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
|
||||
colorUpdated(6);
|
||||
}
|
||||
}
|
||||
45
usermods/rotary_encoder_change_effect/wled06_usermod.ino
Normal file
45
usermods/rotary_encoder_change_effect/wled06_usermod.ino
Normal file
@@ -0,0 +1,45 @@
|
||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
||||
|
||||
long lastTime = 0;
|
||||
int delayMs = 10;
|
||||
const int pinA = D6; //data
|
||||
const int pinB = D7; //clk
|
||||
int oldA = LOW;
|
||||
|
||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
void userSetup() {
|
||||
pinMode(pinA, INPUT_PULLUP);
|
||||
pinMode(pinB, INPUT_PULLUP);
|
||||
}
|
||||
|
||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
||||
void userConnected() {
|
||||
}
|
||||
|
||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
||||
void userLoop() {
|
||||
if (millis()-lastTime > delayMs) {
|
||||
int A = digitalRead(pinA);
|
||||
int B = digitalRead(pinB);
|
||||
|
||||
if (oldA == LOW && A == HIGH) {
|
||||
if (oldB == HIGH) {
|
||||
// bri += 10;
|
||||
// if (bri > 250) bri = 10;
|
||||
effectCurrent += 1;
|
||||
if (effectCurrent >= MODE_COUNT) effectCurrent = 0;
|
||||
}
|
||||
else {
|
||||
// bri -= 10;
|
||||
// if (bri < 10) bri = 250;
|
||||
effectCurrent -= 1;
|
||||
if (effectCurrent < 0) effectCurrent = (MODE_COUNT-1);
|
||||
}
|
||||
oldA = A;
|
||||
|
||||
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
||||
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
|
||||
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
|
||||
lastTime = millis();
|
||||
}
|
||||
}
|
||||
35
usermods/ssd1306_i2c_oled_u8g2/README.md
Normal file
35
usermods/ssd1306_i2c_oled_u8g2/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# SSD1306 128x32 OLED via I2C with u8g2
|
||||
This usermod allows to connect 128x32 Oled display to WLED controlled and show
|
||||
the next information:
|
||||
- Current SSID
|
||||
- IP address if obtained
|
||||
* in AP mode and turned off lightning AP password is shown
|
||||
- Current effect
|
||||
- Current palette
|
||||
- On/Off icon (sun/moon)
|
||||
|
||||
## Hardware
|
||||

|
||||
|
||||
## Requirements
|
||||
Functionality checked with:
|
||||
- commit 095429a7df4f9e2b34dd464f7bbfd068df6558eb
|
||||
- Wemos d1 mini
|
||||
- PlatformIO
|
||||
- Generic SSD1306 128x32 I2C OLED display from aliexpress
|
||||
|
||||
### Platformio
|
||||
Add `U8g2@~2.27.2` dependency to `lib_deps_external` under `[common]` section in `platformio.ini`:
|
||||
```ini
|
||||
# platformio.ini
|
||||
...
|
||||
[common]
|
||||
...
|
||||
lib_deps_external =
|
||||
...
|
||||
U8g2@~2.27.2
|
||||
...
|
||||
```
|
||||
|
||||
### Arduino IDE
|
||||
Install library `U8g2 by oliver` in `Tools | Include Library | Manage libraries` menu.
|
||||
BIN
usermods/ssd1306_i2c_oled_u8g2/assets/hw_connection.png
Normal file
BIN
usermods/ssd1306_i2c_oled_u8g2/assets/hw_connection.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
175
usermods/ssd1306_i2c_oled_u8g2/wled06_usermod.ino
Normal file
175
usermods/ssd1306_i2c_oled_u8g2/wled06_usermod.ino
Normal file
@@ -0,0 +1,175 @@
|
||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||
|
||||
//The SCL and SDA pins are defined here.
|
||||
//Lolin32 boards use SCL=5 SDA=4
|
||||
#define U8X8_PIN_SCL 5
|
||||
#define U8X8_PIN_SDA 4
|
||||
|
||||
|
||||
// If display does not work or looks corrupted check the
|
||||
// constructor reference:
|
||||
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
|
||||
// or check the gallery:
|
||||
// https://github.com/olikraus/u8g2/wiki/gallery
|
||||
U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL,
|
||||
U8X8_PIN_SDA); // Pins are Reset, SCL, SDA
|
||||
|
||||
// gets called once at boot. Do all initialization that doesn't depend on
|
||||
// network here
|
||||
void userSetup() {
|
||||
u8x8.begin();
|
||||
u8x8.setPowerSave(0);
|
||||
u8x8.setContrast(10); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
u8x8.drawString(0, 0, "Loading...");
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
// interfaces here
|
||||
void userConnected() {}
|
||||
|
||||
// needRedraw marks if redraw is required to prevent often redrawing.
|
||||
bool needRedraw = true;
|
||||
|
||||
// Next variables hold the previous known values to determine if redraw is
|
||||
// required.
|
||||
String knownSsid = "";
|
||||
IPAddress knownIp;
|
||||
uint8_t knownBrightness = 0;
|
||||
uint8_t knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
|
||||
long lastUpdate = 0;
|
||||
long lastRedraw = 0;
|
||||
bool displayTurnedOff = false;
|
||||
// How often we are redrawing screen
|
||||
#define USER_LOOP_REFRESH_RATE_MS 5000
|
||||
|
||||
void userLoop() {
|
||||
|
||||
// Check if we time interval for redrawing passes.
|
||||
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) {
|
||||
return;
|
||||
}
|
||||
lastUpdate = millis();
|
||||
|
||||
// Turn off display after 3 minutes with no change.
|
||||
if(!displayTurnedOff && millis() - lastRedraw > 3*60*1000) {
|
||||
u8x8.setPowerSave(1);
|
||||
displayTurnedOff = true;
|
||||
}
|
||||
|
||||
// Check if values which are shown on display changed from the last time.
|
||||
if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) {
|
||||
needRedraw = true;
|
||||
} else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) {
|
||||
needRedraw = true;
|
||||
} else if (knownBrightness != bri) {
|
||||
needRedraw = true;
|
||||
} else if (knownMode != strip.getMode()) {
|
||||
needRedraw = true;
|
||||
} else if (knownPalette != strip.getSegment(0).palette) {
|
||||
needRedraw = true;
|
||||
}
|
||||
|
||||
if (!needRedraw) {
|
||||
return;
|
||||
}
|
||||
needRedraw = false;
|
||||
|
||||
if (displayTurnedOff)
|
||||
{
|
||||
u8x8.setPowerSave(0);
|
||||
displayTurnedOff = false;
|
||||
}
|
||||
lastRedraw = millis();
|
||||
|
||||
// Update last known values.
|
||||
#if defined(ESP8266)
|
||||
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
|
||||
#else
|
||||
knownSsid = WiFi.SSID();
|
||||
#endif
|
||||
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
|
||||
knownBrightness = bri;
|
||||
knownMode = strip.getMode();
|
||||
knownPalette = strip.getSegment(0).palette;
|
||||
|
||||
u8x8.clear();
|
||||
u8x8.setFont(u8x8_font_chroma48medium8_r);
|
||||
|
||||
// First row with Wifi name
|
||||
u8x8.setCursor(1, 0);
|
||||
u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0));
|
||||
// Print `~` char to indicate that SSID is longer, than owr dicplay
|
||||
if (knownSsid.length() > u8x8.getCols())
|
||||
u8x8.print("~");
|
||||
|
||||
// Second row with IP or Psssword
|
||||
u8x8.setCursor(1, 1);
|
||||
// Print password in AP mode and if led is OFF.
|
||||
if (apActive && bri == 0)
|
||||
u8x8.print(apPass);
|
||||
else
|
||||
u8x8.print(knownIp);
|
||||
|
||||
// Third row with mode name
|
||||
u8x8.setCursor(2, 2);
|
||||
uint8_t qComma = 0;
|
||||
bool insideQuotes = false;
|
||||
uint8_t printedChars = 0;
|
||||
char singleJsonSymbol;
|
||||
// Find the mode name in JSON
|
||||
for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownMode))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
// Fourth row with palette name
|
||||
u8x8.setCursor(2, 3);
|
||||
qComma = 0;
|
||||
insideQuotes = false;
|
||||
printedChars = 0;
|
||||
// Looking for palette name in JSON.
|
||||
for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) {
|
||||
singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
|
||||
switch (singleJsonSymbol) {
|
||||
case '"':
|
||||
insideQuotes = !insideQuotes;
|
||||
break;
|
||||
case '[':
|
||||
case ']':
|
||||
break;
|
||||
case ',':
|
||||
qComma++;
|
||||
default:
|
||||
if (!insideQuotes || (qComma != knownPalette))
|
||||
break;
|
||||
u8x8.print(singleJsonSymbol);
|
||||
printedChars++;
|
||||
}
|
||||
if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2))
|
||||
break;
|
||||
}
|
||||
|
||||
u8x8.setFont(u8x8_font_open_iconic_embedded_1x1);
|
||||
u8x8.drawGlyph(0, 0, 80); // wifi icon
|
||||
u8x8.drawGlyph(0, 1, 68); // home icon
|
||||
u8x8.setFont(u8x8_font_open_iconic_weather_2x2);
|
||||
u8x8.drawGlyph(0, 2, 66 + (bri > 0 ? 3 : 0)); // sun/moon icon
|
||||
}
|
||||
14
usermods/stairway_wipe_basic/readme.md
Normal file
14
usermods/stairway_wipe_basic/readme.md
Normal file
@@ -0,0 +1,14 @@
|
||||
### Stairway lighting
|
||||
|
||||
Quick usermod to accomplish something similar to [this video](https://www.youtube.com/watch?v=NHkju5ncC4A).
|
||||
|
||||
This usermod allows you to add a lightstrip alongside or on the steps of a staircase.
|
||||
When the `userVar0` variable is set, the LEDs will gradually turn on in a Wipe effect.
|
||||
Both directions are supported by setting userVar0 to 1 and 2, respectively (HTTP API commands `U0=1` and `U0=2`).
|
||||
|
||||
After the Wipe is complete, the light will either stay on (Solid effect) indefinitely or after `userVar1` seconds have elapsed.
|
||||
If userVar0 is updated (e.g. by triggering a second sensor) the light will slowly fade off.
|
||||
This could be extended to also run a Wipe effect in reverse order to turn the LEDs back off.
|
||||
|
||||
This is just a basic version to accomplish this using HTTP API calls `U0` and `U1` and/or macros.
|
||||
It should be easy to adapt this code however to interface with motion sensors or other input devices.
|
||||
111
usermods/stairway_wipe_basic/wled06_usermod.ino
Normal file
111
usermods/stairway_wipe_basic/wled06_usermod.ino
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* This file allows you to add own functionality to WLED more easily
|
||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in wled_eeprom.h)
|
||||
* bytes 2400+ are currently ununsed, but might be used for future wled features
|
||||
*/
|
||||
|
||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
||||
|
||||
byte wipeState = 0; //0: inactive 1: wiping 2: solid
|
||||
unsigned long timeStaticStart = 0;
|
||||
uint16_t previousUserVar0 = 0;
|
||||
|
||||
//comment this out if you want the turn off effect to be just fading out instead of reverse wipe
|
||||
#define STAIRCASE_WIPE_OFF
|
||||
|
||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
void userSetup()
|
||||
{
|
||||
//setup PIR sensor here, if needed
|
||||
}
|
||||
|
||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
||||
void userConnected()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
||||
void userLoop()
|
||||
{
|
||||
//userVar0 (U0 in HTTP API):
|
||||
//has to be set to 1 if movement is detected on the PIR that is the same side of the staircase as the ESP8266
|
||||
//has to be set to 2 if movement is detected on the PIR that is the opposite side
|
||||
//can be set to 0 if no movement is detected. Otherwise LEDs will turn off after a configurable timeout (userVar1 seconds)
|
||||
|
||||
if (userVar0 > 0)
|
||||
{
|
||||
if ((previousUserVar0 == 1 && userVar0 == 2) || (previousUserVar0 == 2 && userVar0 == 1)) wipeState = 3; //turn off if other PIR triggered
|
||||
previousUserVar0 = userVar0;
|
||||
|
||||
if (wipeState == 0) {
|
||||
startWipe();
|
||||
wipeState = 1;
|
||||
} else if (wipeState == 1) { //wiping
|
||||
uint32_t cycleTime = 360 + (255 - effectSpeed)*75; //this is how long one wipe takes (minus 25 ms to make sure we switch in time)
|
||||
if (millis() + strip.timebase > (cycleTime - 25)) { //wipe complete
|
||||
effectCurrent = FX_MODE_STATIC;
|
||||
timeStaticStart = millis();
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
|
||||
wipeState = 2;
|
||||
}
|
||||
} else if (wipeState == 2) { //static
|
||||
if (userVar1 > 0) //if U1 is not set, the light will stay on until second PIR or external command is triggered
|
||||
{
|
||||
if (millis() - timeStaticStart > userVar1*1000) wipeState = 3;
|
||||
}
|
||||
} else if (wipeState == 3) { //switch to wipe off
|
||||
#ifdef STAIRCASE_WIPE_OFF
|
||||
effectCurrent = FX_MODE_COLOR_WIPE;
|
||||
strip.timebase = 360 + (255 - effectSpeed)*75 - millis(); //make sure wipe starts fully lit
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
|
||||
wipeState = 4;
|
||||
#else
|
||||
turnOff();
|
||||
#endif
|
||||
} else { //wiping off
|
||||
if (millis() + strip.timebase > (725 + (255 - effectSpeed)*150)) turnOff(); //wipe complete
|
||||
}
|
||||
} else {
|
||||
wipeState = 0; //reset for next time
|
||||
if (previousUserVar0) {
|
||||
#ifdef STAIRCASE_WIPE_OFF
|
||||
userVar0 = previousUserVar0;
|
||||
wipeState = 3;
|
||||
#else
|
||||
turnOff();
|
||||
#endif
|
||||
}
|
||||
previousUserVar0 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void startWipe()
|
||||
{
|
||||
bri = briLast; //turn on
|
||||
transitionDelayTemp = 0; //no transition
|
||||
effectCurrent = FX_MODE_COLOR_WIPE;
|
||||
resetTimebase(); //make sure wipe starts from beginning
|
||||
|
||||
//set wipe direction
|
||||
WS2812FX::Segment& seg = strip.getSegment(0);
|
||||
bool doReverse = (userVar0 == 2);
|
||||
seg.setOption(1, doReverse);
|
||||
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
|
||||
}
|
||||
|
||||
void turnOff()
|
||||
{
|
||||
#ifdef STAIRCASE_WIPE_OFF
|
||||
transitionDelayTemp = 0; //turn off immediately after wipe completed
|
||||
#else
|
||||
transitionDelayTemp = 4000; //fade out slowly
|
||||
#endif
|
||||
bri = 0;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
|
||||
wipeState = 0;
|
||||
userVar0 = 0;
|
||||
previousUserVar0 = 0;
|
||||
}
|
||||
25
wled00.sln
Normal file
25
wled00.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28010.2046
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wled00", "wled00\wled00.vcxproj", "{C5F80730-F44F-4478-BDAE-6634EFC2CA88}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.Build.0 = Debug|Win32
|
||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.ActiveCfg = Release|Win32
|
||||
{C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {9A679C2B-61D3-400B-B96F-06E604E9CED2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
BIN
wled00/.vs/wled00/v15/.suo
Normal file
BIN
wled00/.vs/wled00/v15/.suo
Normal file
Binary file not shown.
3324
wled00/FX.cpp
Normal file
3324
wled00/FX.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,7 @@
|
||||
#define WS2812FX_h
|
||||
|
||||
#include "NpbWrapper.h"
|
||||
#include "const.h"
|
||||
|
||||
#define FASTLED_INTERNAL //remove annoying pragma messages
|
||||
#include "FastLED.h"
|
||||
@@ -35,19 +36,36 @@
|
||||
#define DEFAULT_BRIGHTNESS (uint8_t)127
|
||||
#define DEFAULT_MODE (uint8_t)0
|
||||
#define DEFAULT_SPEED (uint8_t)128
|
||||
#define DEFAULT_COLOR (uint32_t)0xFF0000
|
||||
#define DEFAULT_COLOR (uint32_t)0xFFAA00
|
||||
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
|
||||
/* each segment uses 38 bytes of SRAM memory, so if you're application fails because of
|
||||
/* Not used in all effects yet */
|
||||
#define WLED_FPS 42
|
||||
#define FRAMETIME (1000/WLED_FPS)
|
||||
|
||||
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
|
||||
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
|
||||
#define MAX_NUM_SEGMENTS 10
|
||||
#define NUM_COLORS 3 /* number of colors per segment */
|
||||
|
||||
/* How much data bytes all segments combined may allocate */
|
||||
#ifdef ESP8266
|
||||
#define MAX_SEGMENT_DATA 2048
|
||||
#else
|
||||
#define MAX_SEGMENT_DATA 8192
|
||||
#endif
|
||||
|
||||
#define LED_SKIP_AMOUNT 1
|
||||
#define MIN_SHOW_DELAY 15
|
||||
|
||||
#define NUM_COLORS 3 /* number of colors per segment */
|
||||
#define SEGMENT _segments[_segment_index]
|
||||
#define SEGMENT_RUNTIME _segment_runtimes[_segment_index]
|
||||
#define SEGMENT_LENGTH (SEGMENT.stop - SEGMENT.start + 1)
|
||||
#define SPEED_FORMULA_L 5 + (50*(255 - SEGMENT.speed))/SEGMENT_LENGTH
|
||||
#define SEGCOLOR(x) gamma32(_segments[_segment_index].colors[x])
|
||||
#define SEGENV _segment_runtimes[_segment_index]
|
||||
#define SEGLEN _virtualSegmentLength
|
||||
#define SEGACT SEGMENT.stop
|
||||
#define SPEED_FORMULA_L 5 + (50*(255 - SEGMENT.speed))/SEGLEN
|
||||
#define RESET_RUNTIME memset(_segment_runtimes, 0, sizeof(_segment_runtimes))
|
||||
|
||||
// some common colors
|
||||
@@ -65,15 +83,22 @@
|
||||
#define ULTRAWHITE (uint32_t)0xFFFFFFFF
|
||||
|
||||
// options
|
||||
// bit 8: reverse animation
|
||||
// bits 5-7: fade rate (0-7)
|
||||
// bit 4: gamma correction
|
||||
// bits 1-3: TBD
|
||||
// bit 7: segment is in transition mode
|
||||
// bits 3-6: TBD
|
||||
// bit 2: segment is on
|
||||
// bit 1: reverse segment
|
||||
// bit 0: segment is selected
|
||||
#define NO_OPTIONS (uint8_t)0x00
|
||||
#define REVERSE (uint8_t)0x80
|
||||
#define IS_REVERSE ((SEGMENT.options & REVERSE) == REVERSE)
|
||||
#define TRANSITIONAL (uint8_t)0x80
|
||||
#define SEGMENT_ON (uint8_t)0x04
|
||||
#define REVERSE (uint8_t)0x02
|
||||
#define SELECTED (uint8_t)0x01
|
||||
#define IS_TRANSITIONAL ((SEGMENT.options & TRANSITIONAL) == TRANSITIONAL)
|
||||
#define IS_SEGMENT_ON ((SEGMENT.options & SEGMENT_ON ) == SEGMENT_ON )
|
||||
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
|
||||
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
|
||||
|
||||
#define MODE_COUNT 80
|
||||
#define MODE_COUNT 103
|
||||
|
||||
#define FX_MODE_STATIC 0
|
||||
#define FX_MODE_BLINK 1
|
||||
@@ -123,10 +148,10 @@
|
||||
#define FX_MODE_FIRE_FLICKER 45
|
||||
#define FX_MODE_GRADIENT 46
|
||||
#define FX_MODE_LOADING 47
|
||||
#define FX_MODE_DUAL_COLOR_WIPE_IN_OUT 48
|
||||
#define FX_MODE_DUAL_COLOR_WIPE_IN_IN 49
|
||||
#define FX_MODE_DUAL_COLOR_WIPE_OUT_OUT 50
|
||||
#define FX_MODE_DUAL_COLOR_WIPE_OUT_IN 51
|
||||
#define FX_MODE_POLICE 48
|
||||
#define FX_MODE_POLICE_ALL 49
|
||||
#define FX_MODE_TWO_DOTS 50
|
||||
#define FX_MODE_TWO_AREAS 51
|
||||
#define FX_MODE_CIRCUS_COMBUSTUS 52
|
||||
#define FX_MODE_HALLOWEEN 53
|
||||
#define FX_MODE_TRICOLOR_CHASE 54
|
||||
@@ -138,7 +163,6 @@
|
||||
#define FX_MODE_DUAL_LARSON_SCANNER 60
|
||||
#define FX_MODE_RANDOM_CHASE 61
|
||||
#define FX_MODE_OSCILLATE 62
|
||||
//Modes that use FastLED -->
|
||||
#define FX_MODE_PRIDE_2015 63
|
||||
#define FX_MODE_JUGGLE 64
|
||||
#define FX_MODE_PALETTE 65
|
||||
@@ -156,35 +180,117 @@
|
||||
#define FX_MODE_METEOR_SMOOTH 77
|
||||
#define FX_MODE_RAILWAY 78
|
||||
#define FX_MODE_RIPPLE 79
|
||||
|
||||
#define FX_MODE_TWINKLEFOX 80
|
||||
#define FX_MODE_TWINKLECAT 81
|
||||
#define FX_MODE_HALLOWEEN_EYES 82
|
||||
#define FX_MODE_STATIC_PATTERN 83
|
||||
#define FX_MODE_TRI_STATIC_PATTERN 84
|
||||
#define FX_MODE_SPOTS 85
|
||||
#define FX_MODE_SPOTS_FADE 86
|
||||
#define FX_MODE_GLITTER 87
|
||||
#define FX_MODE_CANDLE 88
|
||||
#define FX_MODE_STARBURST 89
|
||||
#define FX_MODE_EXPLODING_FIREWORKS 90
|
||||
#define FX_MODE_BOUNCINGBALLS 91
|
||||
#define FX_MODE_SINELON 92
|
||||
#define FX_MODE_SINELON_DUAL 93
|
||||
#define FX_MODE_SINELON_RAINBOW 94
|
||||
#define FX_MODE_POPCORN 95
|
||||
#define FX_MODE_DRIP 96
|
||||
#define FX_MODE_PLASMA 97
|
||||
#define FX_MODE_PERCENT 98
|
||||
#define FX_MODE_RIPPLE_RAINBOW 99
|
||||
#define FX_MODE_HEARTBEAT 100
|
||||
#define FX_MODE_PACIFICA 101
|
||||
#define FX_MODE_CANDLE_MULTI 102
|
||||
|
||||
class WS2812FX {
|
||||
typedef uint16_t (WS2812FX::*mode_ptr)(void);
|
||||
|
||||
// pre show callback
|
||||
typedef void (*show_callback) (void);
|
||||
|
||||
// segment parameters
|
||||
public:
|
||||
typedef struct Segment { // 21 bytes
|
||||
typedef struct Segment { // 24 bytes
|
||||
uint16_t start;
|
||||
uint16_t stop;
|
||||
uint16_t stop; //segment invalid if stop == 0
|
||||
uint8_t speed;
|
||||
uint8_t intensity;
|
||||
uint8_t palette;
|
||||
uint8_t mode;
|
||||
uint8_t options;
|
||||
uint8_t mode;
|
||||
uint8_t options; //bit pattern: msb first: transitional tbd tbd tbd tbd paused reverse selected
|
||||
uint8_t grouping, spacing;
|
||||
uint8_t opacity;
|
||||
uint32_t colors[NUM_COLORS];
|
||||
void setOption(uint8_t n, bool val)
|
||||
{
|
||||
if (val) {
|
||||
options |= 0x01 << n;
|
||||
} else
|
||||
{
|
||||
options &= ~(0x01 << n);
|
||||
}
|
||||
}
|
||||
bool getOption(uint8_t n)
|
||||
{
|
||||
return ((options >> n) & 0x01);
|
||||
}
|
||||
bool isSelected()
|
||||
{
|
||||
return getOption(0);
|
||||
}
|
||||
bool isActive()
|
||||
{
|
||||
return stop > start;
|
||||
}
|
||||
uint16_t length()
|
||||
{
|
||||
return stop - start;
|
||||
}
|
||||
uint16_t groupLength()
|
||||
{
|
||||
return grouping + spacing;
|
||||
}
|
||||
uint16_t virtualLength()
|
||||
{
|
||||
uint16_t groupLen = groupLength();
|
||||
return (length() + groupLen -1) / groupLen;
|
||||
}
|
||||
} segment;
|
||||
|
||||
// segment runtime parameters
|
||||
typedef struct Segment_runtime { // 17 bytes
|
||||
typedef struct Segment_runtime { // 28 bytes
|
||||
unsigned long next_time;
|
||||
uint32_t counter_mode_step;
|
||||
uint32_t counter_mode_call;
|
||||
uint16_t aux_param;
|
||||
uint16_t aux_param2;
|
||||
uint8_t trans_act;
|
||||
uint32_t step;
|
||||
uint32_t call;
|
||||
uint16_t aux0;
|
||||
uint16_t aux1;
|
||||
byte* data = nullptr;
|
||||
bool allocateData(uint16_t len){
|
||||
if (data && _dataLen == len) return true; //already allocated
|
||||
deallocateData();
|
||||
if (WS2812FX::_usedSegmentData + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
||||
data = new (std::nothrow) byte[len];
|
||||
if (!data) return false; //allocation failed
|
||||
WS2812FX::_usedSegmentData += len;
|
||||
_dataLen = len;
|
||||
memset(data, 0, len);
|
||||
return true;
|
||||
}
|
||||
void deallocateData(){
|
||||
delete[] data;
|
||||
data = nullptr;
|
||||
WS2812FX::_usedSegmentData -= _dataLen;
|
||||
_dataLen = 0;
|
||||
}
|
||||
void reset(){next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; deallocateData();}
|
||||
private:
|
||||
uint16_t _dataLen = 0;
|
||||
} segment_runtime;
|
||||
|
||||
WS2812FX() {
|
||||
//assign each member of the _mode[] array to its respective function reference
|
||||
_mode[FX_MODE_STATIC] = &WS2812FX::mode_static;
|
||||
_mode[FX_MODE_BLINK] = &WS2812FX::mode_blink;
|
||||
_mode[FX_MODE_COLOR_WIPE] = &WS2812FX::mode_color_wipe;
|
||||
@@ -231,10 +337,10 @@ class WS2812FX {
|
||||
_mode[FX_MODE_FIRE_FLICKER] = &WS2812FX::mode_fire_flicker;
|
||||
_mode[FX_MODE_GRADIENT] = &WS2812FX::mode_gradient;
|
||||
_mode[FX_MODE_LOADING] = &WS2812FX::mode_loading;
|
||||
_mode[FX_MODE_DUAL_COLOR_WIPE_IN_OUT] = &WS2812FX::mode_dual_color_wipe_in_out;
|
||||
_mode[FX_MODE_DUAL_COLOR_WIPE_IN_IN] = &WS2812FX::mode_dual_color_wipe_in_in;
|
||||
_mode[FX_MODE_DUAL_COLOR_WIPE_OUT_OUT] = &WS2812FX::mode_dual_color_wipe_out_out;
|
||||
_mode[FX_MODE_DUAL_COLOR_WIPE_OUT_IN] = &WS2812FX::mode_dual_color_wipe_out_in;
|
||||
_mode[FX_MODE_POLICE] = &WS2812FX::mode_police;
|
||||
_mode[FX_MODE_POLICE_ALL] = &WS2812FX::mode_police_all;
|
||||
_mode[FX_MODE_TWO_DOTS] = &WS2812FX::mode_two_dots;
|
||||
_mode[FX_MODE_TWO_AREAS] = &WS2812FX::mode_two_areas;
|
||||
_mode[FX_MODE_CIRCUS_COMBUSTUS] = &WS2812FX::mode_circus_combustus;
|
||||
_mode[FX_MODE_HALLOWEEN] = &WS2812FX::mode_halloween;
|
||||
_mode[FX_MODE_TRICOLOR_CHASE] = &WS2812FX::mode_tricolor_chase;
|
||||
@@ -265,27 +371,38 @@ class WS2812FX {
|
||||
_mode[FX_MODE_METEOR_SMOOTH] = &WS2812FX::mode_meteor_smooth;
|
||||
_mode[FX_MODE_RAILWAY] = &WS2812FX::mode_railway;
|
||||
_mode[FX_MODE_RIPPLE] = &WS2812FX::mode_ripple;
|
||||
_mode[FX_MODE_TWINKLEFOX] = &WS2812FX::mode_twinklefox;
|
||||
_mode[FX_MODE_TWINKLECAT] = &WS2812FX::mode_twinklecat;
|
||||
_mode[FX_MODE_HALLOWEEN_EYES] = &WS2812FX::mode_halloween_eyes;
|
||||
_mode[FX_MODE_STATIC_PATTERN] = &WS2812FX::mode_static_pattern;
|
||||
_mode[FX_MODE_TRI_STATIC_PATTERN] = &WS2812FX::mode_tri_static_pattern;
|
||||
_mode[FX_MODE_SPOTS] = &WS2812FX::mode_spots;
|
||||
_mode[FX_MODE_SPOTS_FADE] = &WS2812FX::mode_spots_fade;
|
||||
_mode[FX_MODE_GLITTER] = &WS2812FX::mode_glitter;
|
||||
_mode[FX_MODE_CANDLE] = &WS2812FX::mode_candle;
|
||||
_mode[FX_MODE_STARBURST] = &WS2812FX::mode_starburst;
|
||||
_mode[FX_MODE_EXPLODING_FIREWORKS] = &WS2812FX::mode_exploding_fireworks;
|
||||
_mode[FX_MODE_BOUNCINGBALLS] = &WS2812FX::mode_bouncing_balls;
|
||||
_mode[FX_MODE_SINELON] = &WS2812FX::mode_sinelon;
|
||||
_mode[FX_MODE_SINELON_DUAL] = &WS2812FX::mode_sinelon_dual;
|
||||
_mode[FX_MODE_SINELON_RAINBOW] = &WS2812FX::mode_sinelon_rainbow;
|
||||
_mode[FX_MODE_POPCORN] = &WS2812FX::mode_popcorn;
|
||||
_mode[FX_MODE_DRIP] = &WS2812FX::mode_drip;
|
||||
_mode[FX_MODE_PLASMA] = &WS2812FX::mode_plasma;
|
||||
_mode[FX_MODE_PERCENT] = &WS2812FX::mode_percent;
|
||||
_mode[FX_MODE_RIPPLE_RAINBOW] = &WS2812FX::mode_ripple_rainbow;
|
||||
_mode[FX_MODE_HEARTBEAT] = &WS2812FX::mode_heartbeat;
|
||||
_mode[FX_MODE_PACIFICA] = &WS2812FX::mode_pacifica;
|
||||
_mode[FX_MODE_CANDLE_MULTI] = &WS2812FX::mode_candle_multi;
|
||||
|
||||
_brightness = DEFAULT_BRIGHTNESS;
|
||||
_num_segments = 1;
|
||||
_segments[0].mode = DEFAULT_MODE;
|
||||
_segments[0].colors[0] = DEFAULT_COLOR;
|
||||
_segments[0].start = 0;
|
||||
_segments[0].speed = DEFAULT_SPEED;
|
||||
currentPalette = CRGBPalette16(CRGB::Black);
|
||||
targetPalette = CloudColors_p;
|
||||
_reverseMode = false;
|
||||
_skipFirstMode = false;
|
||||
colorOrder = 0;
|
||||
paletteFade = 0;
|
||||
paletteBlend = 0;
|
||||
ablMilliampsMax = 750;
|
||||
ablMilliampsMax = 850;
|
||||
currentMilliamps = 0;
|
||||
_locked = NULL;
|
||||
_modeUsesLock = false;
|
||||
_cronixieDigits = new byte[6];
|
||||
timebase = 0;
|
||||
bus = new NeoPixelWrapper();
|
||||
RESET_RUNTIME;
|
||||
resetSegments();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -293,59 +410,64 @@ class WS2812FX {
|
||||
service(void),
|
||||
blur(uint8_t),
|
||||
fade_out(uint8_t r),
|
||||
setMode(uint8_t m),
|
||||
setSpeed(uint8_t s),
|
||||
setIntensity(uint8_t i),
|
||||
setPalette(uint8_t p),
|
||||
setColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
setSecondaryColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
setColor(uint32_t c),
|
||||
setSecondaryColor(uint32_t c),
|
||||
setMode(uint8_t segid, uint8_t m),
|
||||
setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
setColor(uint8_t slot, uint32_t c),
|
||||
setBrightness(uint8_t b),
|
||||
setReverseMode(bool b),
|
||||
driverModeCronixie(bool b),
|
||||
setCronixieDigits(byte* d),
|
||||
setCronixieBacklight(bool b),
|
||||
setIndividual(uint16_t i, uint32_t col),
|
||||
setRange(uint16_t i, uint16_t i2, uint32_t col),
|
||||
lock(uint16_t i),
|
||||
lockRange(uint16_t i, uint16_t i2),
|
||||
unlock(uint16_t i),
|
||||
unlockRange(uint16_t i, uint16_t i2),
|
||||
unlockAll(void),
|
||||
setShowCallback(show_callback cb),
|
||||
setTransitionMode(bool t),
|
||||
trigger(void),
|
||||
setNumSegments(uint8_t n),
|
||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint8_t speed, uint8_t intensity, bool reverse),
|
||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint8_t speed, uint8_t intensity, bool reverse),
|
||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint8_t speed, uint8_t intensity, uint8_t options),
|
||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
|
||||
resetSegments(),
|
||||
setPixelColor(uint16_t n, uint32_t c),
|
||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
show(void);
|
||||
show(void),
|
||||
setRgbwPwm(void);
|
||||
|
||||
bool
|
||||
reverseMode = false,
|
||||
gammaCorrectBri = false,
|
||||
gammaCorrectCol = true,
|
||||
applyToAllSelected = true,
|
||||
segmentsAreIdentical(Segment* a, Segment* b),
|
||||
setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p);
|
||||
|
||||
uint8_t
|
||||
paletteFade,
|
||||
paletteBlend,
|
||||
colorOrder,
|
||||
mainSegment = 0,
|
||||
rgbwMode = RGBW_MODE_DUAL,
|
||||
paletteFade = 0,
|
||||
paletteBlend = 0,
|
||||
colorOrder = 0,
|
||||
milliampsPerLed = 55,
|
||||
getBrightness(void),
|
||||
getMode(void),
|
||||
getSpeed(void),
|
||||
getNumSegments(void),
|
||||
getModeCount(void),
|
||||
getPaletteCount(void),
|
||||
getMaxSegments(void),
|
||||
//getFirstSelectedSegment(void),
|
||||
getMainSegmentId(void),
|
||||
gamma8(uint8_t),
|
||||
get_random_wheel_index(uint8_t);
|
||||
|
||||
uint16_t
|
||||
ablMilliampsMax,
|
||||
currentMilliamps,
|
||||
triwave16(uint16_t);
|
||||
|
||||
uint32_t
|
||||
timebase,
|
||||
color_wheel(uint8_t),
|
||||
color_from_palette(uint16_t, bool, bool, uint8_t, uint8_t pbri = 255),
|
||||
color_blend(uint32_t,uint32_t,uint8_t),
|
||||
gamma32(uint32_t),
|
||||
getLastShow(void),
|
||||
getPixelColor(uint16_t),
|
||||
getColor(void);
|
||||
|
||||
WS2812FX::Segment
|
||||
getSegment(void);
|
||||
WS2812FX::Segment&
|
||||
getSegment(uint8_t n);
|
||||
|
||||
WS2812FX::Segment_runtime
|
||||
getSegmentRuntime(void);
|
||||
@@ -353,21 +475,6 @@ class WS2812FX {
|
||||
WS2812FX::Segment*
|
||||
getSegments(void);
|
||||
|
||||
// mode helper functions
|
||||
uint16_t
|
||||
ablMilliampsMax,
|
||||
currentMilliamps,
|
||||
blink(uint32_t, uint32_t, bool strobe, bool),
|
||||
color_wipe(uint32_t, uint32_t, bool , bool),
|
||||
scan(bool),
|
||||
theater_chase(uint32_t, uint32_t, bool),
|
||||
running_base(bool),
|
||||
dissolve(uint32_t),
|
||||
chase(uint32_t, uint32_t, uint32_t, bool),
|
||||
gradient_base(bool),
|
||||
running(uint32_t, uint32_t),
|
||||
tricolor_chase(uint32_t, uint32_t);
|
||||
|
||||
// builtin modes
|
||||
uint16_t
|
||||
mode_static(void),
|
||||
@@ -419,10 +526,10 @@ class WS2812FX {
|
||||
mode_fire_flicker(void),
|
||||
mode_gradient(void),
|
||||
mode_loading(void),
|
||||
mode_dual_color_wipe_in_out(void),
|
||||
mode_dual_color_wipe_in_in(void),
|
||||
mode_dual_color_wipe_out_out(void),
|
||||
mode_dual_color_wipe_out_in(void),
|
||||
mode_police(void),
|
||||
mode_police_all(void),
|
||||
mode_two_dots(void),
|
||||
mode_two_areas(void),
|
||||
mode_circus_combustus(void),
|
||||
mode_bicolor_chase(void),
|
||||
mode_tricolor_chase(void),
|
||||
@@ -450,183 +557,127 @@ class WS2812FX {
|
||||
mode_meteor(void),
|
||||
mode_meteor_smooth(void),
|
||||
mode_railway(void),
|
||||
mode_ripple(void);
|
||||
mode_ripple(void),
|
||||
mode_twinklefox(void),
|
||||
mode_twinklecat(void),
|
||||
mode_halloween_eyes(void),
|
||||
mode_static_pattern(void),
|
||||
mode_tri_static_pattern(void),
|
||||
mode_spots(void),
|
||||
mode_spots_fade(void),
|
||||
mode_glitter(void),
|
||||
mode_candle(void),
|
||||
mode_starburst(void),
|
||||
mode_exploding_fireworks(void),
|
||||
mode_bouncing_balls(void),
|
||||
mode_sinelon(void),
|
||||
mode_sinelon_dual(void),
|
||||
mode_sinelon_rainbow(void),
|
||||
mode_popcorn(void),
|
||||
mode_drip(void),
|
||||
mode_plasma(void),
|
||||
mode_percent(void),
|
||||
mode_ripple_rainbow(void),
|
||||
mode_heartbeat(void),
|
||||
mode_pacifica(void),
|
||||
mode_candle_multi(void);
|
||||
|
||||
|
||||
private:
|
||||
NeoPixelWrapper *bus;
|
||||
|
||||
CRGB fastled_from_col(uint32_t);
|
||||
uint32_t crgb_to_col(CRGB fastled);
|
||||
CRGB col_to_crgb(uint32_t);
|
||||
CRGBPalette16 currentPalette;
|
||||
CRGBPalette16 targetPalette;
|
||||
|
||||
uint16_t _length;
|
||||
|
||||
uint32_t now;
|
||||
uint16_t _length, _lengthRaw, _virtualSegmentLength;
|
||||
uint16_t _rand16seed;
|
||||
uint8_t _brightness;
|
||||
static uint16_t _usedSegmentData;
|
||||
|
||||
void load_gradient_palette(uint8_t);
|
||||
void handle_palette(void);
|
||||
void fill(uint32_t);
|
||||
bool modeUsesLock(uint8_t);
|
||||
|
||||
bool
|
||||
_modeUsesLock,
|
||||
_rgbwMode,
|
||||
_reverseMode,
|
||||
_cronixieMode,
|
||||
_cronixieBacklightEnabled,
|
||||
_useRgbw = false,
|
||||
_skipFirstMode,
|
||||
_triggered;
|
||||
|
||||
byte* _locked;
|
||||
byte* _cronixieDigits;
|
||||
|
||||
mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element
|
||||
|
||||
show_callback _callback = nullptr;
|
||||
|
||||
// mode helper functions
|
||||
uint16_t
|
||||
blink(uint32_t, uint32_t, bool strobe, bool),
|
||||
candle(bool),
|
||||
color_wipe(bool, bool),
|
||||
scan(bool),
|
||||
theater_chase(uint32_t, uint32_t, bool),
|
||||
running_base(bool),
|
||||
larson_scanner(bool),
|
||||
sinelon_base(bool,bool),
|
||||
dissolve(uint32_t),
|
||||
chase(uint32_t, uint32_t, uint32_t, bool),
|
||||
gradient_base(bool),
|
||||
ripple_base(bool),
|
||||
police_base(uint32_t, uint32_t, bool),
|
||||
running(uint32_t, uint32_t),
|
||||
tricolor_chase(uint32_t, uint32_t),
|
||||
twinklefox_base(bool),
|
||||
spots_base(uint16_t);
|
||||
|
||||
CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat);
|
||||
CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff);
|
||||
|
||||
uint32_t _lastPaletteChange = 0;
|
||||
uint32_t _lastShow = 0;
|
||||
|
||||
#ifdef WLED_USE_ANALOG_LEDS
|
||||
uint32_t _analogLastShow = 0;
|
||||
RgbwColor _analogLastColor = 0;
|
||||
uint8_t _analogLastBri = 0;
|
||||
#endif
|
||||
|
||||
uint8_t _segment_index = 0;
|
||||
uint8_t _segment_index_palette_last = 99;
|
||||
uint8_t _num_segments = 1;
|
||||
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 21 bytes per element
|
||||
// start, stop, speed, intensity, palette, mode, options, color[]
|
||||
{ 0, 7, DEFAULT_SPEED, 128, 0, FX_MODE_STATIC, NO_OPTIONS, {DEFAULT_COLOR}}
|
||||
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 24 bytes per element
|
||||
// start, stop, speed, intensity, palette, mode, options, grouping, spacing, opacity (unused), color[]
|
||||
{ 0, 7, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}}
|
||||
};
|
||||
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 17 bytes per element
|
||||
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
|
||||
friend class Segment_runtime;
|
||||
|
||||
uint16_t realPixelIndex(uint16_t i);
|
||||
};
|
||||
|
||||
|
||||
const char JSON_mode_names[] PROGMEM = R"=====({"effects":[
|
||||
"Solid",
|
||||
"Blink",
|
||||
"Breathe",
|
||||
"Wipe",
|
||||
"Wipe Random",
|
||||
"Random Colors",
|
||||
"Sweep",
|
||||
"Dynamic",
|
||||
"Colorloop",
|
||||
"Rainbow",
|
||||
"Scan",
|
||||
"Dual Scan",
|
||||
"Fade",
|
||||
"Chase",
|
||||
"Chase Rainbow",
|
||||
"Running",
|
||||
"Saw",
|
||||
"Twinkle",
|
||||
"Dissolve",
|
||||
"Dissolve Rnd",
|
||||
"Sparkle",
|
||||
"Dark Sparkle",
|
||||
"Sparkle+",
|
||||
"Strobe",
|
||||
"Strobe Rainbow",
|
||||
"Mega Strobe",
|
||||
"Blink Rainbow",
|
||||
"Android",
|
||||
"Chase",
|
||||
"Chase Random",
|
||||
"Chase Rainbow",
|
||||
"Chase Flash",
|
||||
"Chase Flash Rnd",
|
||||
"Rainbow Runner",
|
||||
"Colorful",
|
||||
"Traffic Light",
|
||||
"Sweep Random",
|
||||
"Running 2",
|
||||
"Red & Blue",
|
||||
"Stream",
|
||||
"Scanner",
|
||||
"Lighthouse",
|
||||
"Fireworks",
|
||||
"Rain",
|
||||
"Merry Christmas",
|
||||
"Fire Flicker",
|
||||
"Gradient",
|
||||
"Loading",
|
||||
"In Out",
|
||||
"In In",
|
||||
"Out Out",
|
||||
"Out In",
|
||||
"Circus",
|
||||
"Halloween",
|
||||
"Tri Chase",
|
||||
"Tri Wipe",
|
||||
"Tri Fade",
|
||||
"Lightning",
|
||||
"ICU",
|
||||
"Multi Comet",
|
||||
"Dual Scanner",
|
||||
"Stream 2",
|
||||
"Oscillate",
|
||||
"Pride 2015",
|
||||
"Juggle",
|
||||
"Palette",
|
||||
"Fire 2012",
|
||||
"Colorwaves",
|
||||
"BPM",
|
||||
"Fill Noise",
|
||||
"Noise 1",
|
||||
"Noise 2",
|
||||
"Noise 3",
|
||||
"Noise 4",
|
||||
"Colortwinkle",
|
||||
"Lake",
|
||||
"Meteor",
|
||||
"Smooth Meteor",
|
||||
"Railway",
|
||||
"Ripple"
|
||||
]})=====";
|
||||
//10 names per line
|
||||
const char JSON_mode_names[] PROGMEM = R"=====([
|
||||
"Solid","Blink","Breathe","Wipe","Wipe Random","Random Colors","Sweep","Dynamic","Colorloop","Rainbow",
|
||||
"Scan","Scan Dual","Fade","Theater","Theater Rainbow","Running","Saw","Twinkle","Dissolve","Dissolve Rnd",
|
||||
"Sparkle","Sparkle Dark","Sparkle+","Strobe","Strobe Rainbow","Strobe Mega","Blink Rainbow","Android","Chase","Chase Random",
|
||||
"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Red & Blue","Stream",
|
||||
"Scanner","Lighthouse","Fireworks","Rain","Merry Christmas","Fire Flicker","Gradient","Loading","Police","Police All",
|
||||
"Two Dots","Two Areas","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet",
|
||||
"Scanner Dual","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise",
|
||||
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple",
|
||||
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
|
||||
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
|
||||
"Heartbeat","Pacifica","Candle Multi"
|
||||
])=====";
|
||||
|
||||
|
||||
const char JSON_palette_names[] PROGMEM = R"=====({"palettes":[
|
||||
"Default",
|
||||
"Random Cycle",
|
||||
"Primary Color",
|
||||
"Based on Primary",
|
||||
"Set Colors",
|
||||
"Based on Set",
|
||||
"Party",
|
||||
"Cloud",
|
||||
"Lava",
|
||||
"Ocean",
|
||||
"Forest",
|
||||
"Rainbow",
|
||||
"Rainbow Bands",
|
||||
"Sunset",
|
||||
"Rivendell",
|
||||
"Breeze",
|
||||
"Red & Blue",
|
||||
"Yellowout",
|
||||
"Analogous",
|
||||
"Splash",
|
||||
"Pastel",
|
||||
"Sunset 2",
|
||||
"Beech",
|
||||
"Vintage",
|
||||
"Departure",
|
||||
"Landscape",
|
||||
"Beach",
|
||||
"Sherbet",
|
||||
"Hult",
|
||||
"Hult 64",
|
||||
"Drywet",
|
||||
"Jul",
|
||||
"Grintage",
|
||||
"Rewhi",
|
||||
"Tertiary",
|
||||
"Fire",
|
||||
"Icefire",
|
||||
"Cyane",
|
||||
"Light Pink",
|
||||
"Autumn",
|
||||
"Magenta",
|
||||
"Magred",
|
||||
"Yelmag",
|
||||
"Yelblu",
|
||||
"Orange & Teal",
|
||||
"Tiamat",
|
||||
"April Night"
|
||||
]})=====";
|
||||
const char JSON_palette_names[] PROGMEM = R"=====([
|
||||
"Default","* Random Cycle","* Color 1","* Colors 1&2","* Color Gradient","* Colors Only","Party","Cloud","Lava","Ocean",
|
||||
"Forest","Rainbow","Rainbow Bands","Sunset","Rivendell","Breeze","Red & Blue","Yellowout","Analogous","Splash",
|
||||
"Pastel","Sunset 2","Beech","Vintage","Departure","Landscape","Beach","Sherbet","Hult","Hult 64",
|
||||
"Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn",
|
||||
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura",
|
||||
"Aurora","Atlantica"
|
||||
])=====";
|
||||
|
||||
#endif
|
||||
893
wled00/FX_fcn.cpp
Normal file
893
wled00/FX_fcn.cpp
Normal file
@@ -0,0 +1,893 @@
|
||||
/*
|
||||
WS2812FX_fcn.cpp contains all utility functions
|
||||
Harm Aldick - 2016
|
||||
www.aldick.org
|
||||
LICENSE
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2016 Harm Aldick
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Modified heavily for WLED
|
||||
*/
|
||||
|
||||
#include "FX.h"
|
||||
#include "palettes.h"
|
||||
|
||||
//enable custom per-LED mapping. This can allow for better effects on matrices or special displays
|
||||
//#define WLED_CUSTOM_LED_MAPPING
|
||||
|
||||
#ifdef WLED_CUSTOM_LED_MAPPING
|
||||
//this is just an example (30 LEDs). It will first set all even, then all uneven LEDs.
|
||||
const uint16_t customMappingTable[] = {
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28,
|
||||
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29};
|
||||
|
||||
//another example. Switches direction every 5 LEDs.
|
||||
/*const uint16_t customMappingTable[] = {
|
||||
0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14,
|
||||
19, 18, 17, 16, 15, 20, 21, 22, 23, 24, 29, 28, 27, 26, 25};*/
|
||||
|
||||
const uint16_t customMappingSize = sizeof(customMappingTable)/sizeof(uint16_t); //30 in example
|
||||
#endif
|
||||
|
||||
void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst)
|
||||
{
|
||||
if (supportWhite == _useRgbw && countPixels == _length && _skipFirstMode == skipFirst) return;
|
||||
RESET_RUNTIME;
|
||||
_useRgbw = supportWhite;
|
||||
_length = countPixels;
|
||||
_skipFirstMode = skipFirst;
|
||||
|
||||
uint8_t ty = 1;
|
||||
if (supportWhite) ty = 2;
|
||||
_lengthRaw = _length;
|
||||
if (_skipFirstMode) {
|
||||
_lengthRaw += LED_SKIP_AMOUNT;
|
||||
}
|
||||
|
||||
bus->Begin((NeoPixelType)ty, _lengthRaw);
|
||||
|
||||
_segments[0].start = 0;
|
||||
_segments[0].stop = _length;
|
||||
|
||||
setBrightness(_brightness);
|
||||
}
|
||||
|
||||
void WS2812FX::service() {
|
||||
uint32_t nowUp = millis(); // Be aware, millis() rolls over every 49 days
|
||||
now = nowUp + timebase;
|
||||
if (nowUp - _lastShow < MIN_SHOW_DELAY) return;
|
||||
bool doShow = false;
|
||||
for(uint8_t i=0; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
_segment_index = i;
|
||||
if (SEGMENT.isActive())
|
||||
{
|
||||
if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary
|
||||
{
|
||||
if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check
|
||||
_virtualSegmentLength = SEGMENT.virtualLength();
|
||||
doShow = true;
|
||||
handle_palette();
|
||||
uint16_t delay = (this->*_mode[SEGMENT.mode])();
|
||||
SEGENV.next_time = nowUp + delay;
|
||||
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
|
||||
}
|
||||
}
|
||||
}
|
||||
_virtualSegmentLength = 0;
|
||||
if(doShow) {
|
||||
yield();
|
||||
show();
|
||||
}
|
||||
_triggered = false;
|
||||
}
|
||||
|
||||
void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
|
||||
uint8_t w = (c >> 24);
|
||||
uint8_t r = (c >> 16);
|
||||
uint8_t g = (c >> 8);
|
||||
uint8_t b = c ;
|
||||
setPixelColor(n, r, g, b, w);
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::realPixelIndex(uint16_t i) {
|
||||
int16_t iGroup = i * SEGMENT.groupLength();
|
||||
|
||||
/* reverse just an individual segment */
|
||||
int16_t realIndex = iGroup;
|
||||
if (IS_REVERSE) realIndex = SEGMENT.length() -iGroup -1;
|
||||
|
||||
realIndex += SEGMENT.start;
|
||||
/* Reverse the whole string */
|
||||
if (reverseMode) realIndex = _length - 1 - realIndex;
|
||||
|
||||
return realIndex;
|
||||
}
|
||||
|
||||
void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
{
|
||||
//auto calculate white channel value if enabled
|
||||
if (_useRgbw) {
|
||||
if (rgbwMode == RGBW_MODE_AUTO_BRIGHTER || (w == 0 && (rgbwMode == RGBW_MODE_DUAL || rgbwMode == RGBW_MODE_LEGACY)))
|
||||
{
|
||||
//white value is set to lowest RGB channel
|
||||
//thank you to @Def3nder!
|
||||
w = r < g ? (r < b ? r : b) : (g < b ? g : b);
|
||||
} else if (rgbwMode == RGBW_MODE_AUTO_ACCURATE && w == 0)
|
||||
{
|
||||
w = r < g ? (r < b ? r : b) : (g < b ? g : b);
|
||||
r -= w; g -= w; b -= w;
|
||||
}
|
||||
}
|
||||
|
||||
RgbwColor col;
|
||||
switch (colorOrder)
|
||||
{
|
||||
case 0: col.G = g; col.R = r; col.B = b; break; //0 = GRB, default
|
||||
case 1: col.G = r; col.R = g; col.B = b; break; //1 = RGB, common for WS2811
|
||||
case 2: col.G = b; col.R = r; col.B = g; break; //2 = BRG
|
||||
case 3: col.G = r; col.R = b; col.B = g; break; //3 = RBG
|
||||
case 4: col.G = b; col.R = g; col.B = r; break; //4 = BGR
|
||||
default: col.G = g; col.R = b; col.B = r; break; //5 = GBR
|
||||
}
|
||||
col.W = w;
|
||||
|
||||
uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0;
|
||||
if (SEGLEN) {//from segment
|
||||
|
||||
//color_blend(getpixel, col, SEGMENT.opacity); (pseudocode for future blending of segments)
|
||||
if (IS_SEGMENT_ON)
|
||||
{
|
||||
if (SEGMENT.opacity < 255) {
|
||||
col.R = scale8(col.R, SEGMENT.opacity);
|
||||
col.G = scale8(col.G, SEGMENT.opacity);
|
||||
col.B = scale8(col.B, SEGMENT.opacity);
|
||||
col.W = scale8(col.W, SEGMENT.opacity);
|
||||
}
|
||||
} else {
|
||||
col = BLACK;
|
||||
}
|
||||
|
||||
/* Set all the pixels in the group, ensuring _skipFirstMode is honored */
|
||||
bool reversed = reverseMode ^ IS_REVERSE;
|
||||
uint16_t realIndex = realPixelIndex(i);
|
||||
|
||||
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
|
||||
int16_t indexSet = realIndex + (reversed ? -j : j);
|
||||
int16_t indexSetRev = indexSet;
|
||||
if (reverseMode) indexSetRev = _length - 1 - indexSet;
|
||||
#ifdef WLED_CUSTOM_LED_MAPPING
|
||||
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
|
||||
#endif
|
||||
if (indexSetRev >= SEGMENT.start && indexSetRev < SEGMENT.stop) bus->SetPixelColor(indexSet + skip, col);
|
||||
}
|
||||
} else { //live data, etc.
|
||||
if (reverseMode) i = _length - 1 - i;
|
||||
#ifdef WLED_CUSTOM_LED_MAPPING
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
#endif
|
||||
bus->SetPixelColor(i + skip, col);
|
||||
}
|
||||
if (skip && i == 0) {
|
||||
for (uint16_t j = 0; j < skip; j++) {
|
||||
bus->SetPixelColor(j, RgbwColor(0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//DISCLAIMER
|
||||
//The following function attemps to calculate the current LED power usage,
|
||||
//and will limit the brightness to stay below a set amperage threshold.
|
||||
//It is NOT a measurement and NOT guaranteed to stay within the ablMilliampsMax margin.
|
||||
//Stay safe with high amperage and have a reasonable safety margin!
|
||||
//I am NOT to be held liable for burned down garages!
|
||||
|
||||
//fine tune power estimation constants for your setup
|
||||
#define MA_FOR_ESP 100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA)
|
||||
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
|
||||
|
||||
void WS2812FX::show(void) {
|
||||
if (_callback) _callback();
|
||||
|
||||
//power limit calculation
|
||||
//each LED can draw up 195075 "power units" (approx. 53mA)
|
||||
//one PU is the power it takes to have 1 channel 1 step brighter per brightness step
|
||||
//so A=2,R=255,G=0,B=0 would use 510 PU per LED (1mA is about 3700 PU)
|
||||
bool useWackyWS2815PowerModel = false;
|
||||
byte actualMilliampsPerLed = milliampsPerLed;
|
||||
|
||||
if(milliampsPerLed == 255) {
|
||||
useWackyWS2815PowerModel = true;
|
||||
actualMilliampsPerLed = 12; // from testing an actual strip
|
||||
}
|
||||
|
||||
if (ablMilliampsMax > 149 && actualMilliampsPerLed > 0) //0 mA per LED and too low numbers turn off calculation
|
||||
{
|
||||
uint32_t puPerMilliamp = 195075 / actualMilliampsPerLed;
|
||||
uint32_t powerBudget = (ablMilliampsMax - MA_FOR_ESP) * puPerMilliamp; //100mA for ESP power
|
||||
if (powerBudget > puPerMilliamp * _length) //each LED uses about 1mA in standby, exclude that from power budget
|
||||
{
|
||||
powerBudget -= puPerMilliamp * _length;
|
||||
} else
|
||||
{
|
||||
powerBudget = 0;
|
||||
}
|
||||
|
||||
uint32_t powerSum = 0;
|
||||
|
||||
for (uint16_t i = 0; i < _length; i++) //sum up the usage of each LED
|
||||
{
|
||||
RgbwColor c = bus->GetPixelColorRgbw(i);
|
||||
|
||||
if(useWackyWS2815PowerModel)
|
||||
{
|
||||
// ignore white component on WS2815 power calculation
|
||||
powerSum += (MAX(MAX(c.R,c.G),c.B)) * 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
powerSum += (c.R + c.G + c.B + c.W);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_useRgbw) //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less
|
||||
{
|
||||
powerSum *= 3;
|
||||
powerSum = powerSum >> 2; //same as /= 4
|
||||
}
|
||||
|
||||
uint32_t powerSum0 = powerSum;
|
||||
powerSum *= _brightness;
|
||||
|
||||
if (powerSum > powerBudget) //scale brightness down to stay in current limit
|
||||
{
|
||||
float scale = (float)powerBudget / (float)powerSum;
|
||||
uint16_t scaleI = scale * 255;
|
||||
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
|
||||
uint8_t newBri = scale8(_brightness, scaleB);
|
||||
bus->SetBrightness(newBri);
|
||||
currentMilliamps = (powerSum0 * newBri) / puPerMilliamp;
|
||||
} else
|
||||
{
|
||||
currentMilliamps = powerSum / puPerMilliamp;
|
||||
bus->SetBrightness(_brightness);
|
||||
}
|
||||
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
|
||||
currentMilliamps += _length; //add standby power back to estimate
|
||||
} else {
|
||||
currentMilliamps = 0;
|
||||
bus->SetBrightness(_brightness);
|
||||
}
|
||||
|
||||
bus->Show();
|
||||
_lastShow = millis();
|
||||
}
|
||||
|
||||
void WS2812FX::trigger() {
|
||||
_triggered = true;
|
||||
}
|
||||
|
||||
void WS2812FX::setMode(uint8_t segid, uint8_t m) {
|
||||
if (segid >= MAX_NUM_SEGMENTS) return;
|
||||
|
||||
if (m >= MODE_COUNT) m = MODE_COUNT - 1;
|
||||
|
||||
if (_segments[segid].mode != m)
|
||||
{
|
||||
_segment_runtimes[segid].reset();
|
||||
_segments[segid].mode = m;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getModeCount()
|
||||
{
|
||||
return MODE_COUNT;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getPaletteCount()
|
||||
{
|
||||
return 13 + GRADIENT_PALETTE_COUNT;
|
||||
}
|
||||
|
||||
//TODO transitions
|
||||
|
||||
|
||||
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) {
|
||||
uint8_t mainSeg = getMainSegmentId();
|
||||
Segment& seg = _segments[getMainSegmentId()];
|
||||
uint8_t modePrev = seg.mode, speedPrev = seg.speed, intensityPrev = seg.intensity, palettePrev = seg.palette;
|
||||
|
||||
bool applied = false;
|
||||
|
||||
if (applyToAllSelected) {
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
if (_segments[i].isSelected())
|
||||
{
|
||||
_segments[i].speed = s;
|
||||
_segments[i].intensity = in;
|
||||
_segments[i].palette = p;
|
||||
setMode(i, m);
|
||||
applied = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!applyToAllSelected || !applied) {
|
||||
seg.speed = s;
|
||||
seg.intensity = in;
|
||||
seg.palette = p;
|
||||
setMode(mainSegment, m);
|
||||
}
|
||||
|
||||
if (seg.mode != modePrev || seg.speed != speedPrev || seg.intensity != intensityPrev || seg.palette != palettePrev) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void WS2812FX::setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
|
||||
setColor(slot, ((uint32_t)w << 24) |((uint32_t)r << 16) | ((uint32_t)g << 8) | b);
|
||||
}
|
||||
|
||||
void WS2812FX::setColor(uint8_t slot, uint32_t c) {
|
||||
if (slot >= NUM_COLORS) return;
|
||||
|
||||
bool applied = false;
|
||||
|
||||
if (applyToAllSelected) {
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
if (_segments[i].isSelected()) _segments[i].colors[slot] = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (!applyToAllSelected || !applied) {
|
||||
_segments[getMainSegmentId()].colors[slot] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::setBrightness(uint8_t b) {
|
||||
if (_brightness == b) return;
|
||||
_brightness = (gammaCorrectBri) ? gamma8(b) : b;
|
||||
_segment_index = 0;
|
||||
if (SEGENV.next_time > millis() + 22 && millis() - _lastShow > MIN_SHOW_DELAY) show();//apply brightness change immediately if no refresh soon
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getMode(void) {
|
||||
return _segments[getMainSegmentId()].mode;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getSpeed(void) {
|
||||
return _segments[getMainSegmentId()].speed;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getBrightness(void) {
|
||||
return _brightness;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getMaxSegments(void) {
|
||||
return MAX_NUM_SEGMENTS;
|
||||
}
|
||||
|
||||
/*uint8_t WS2812FX::getFirstSelectedSegment(void)
|
||||
{
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
if (_segments[i].isActive() && _segments[i].isSelected()) return i;
|
||||
}
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) //if none selected, get first active
|
||||
{
|
||||
if (_segments[i].isActive()) return i;
|
||||
}
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
uint8_t WS2812FX::getMainSegmentId(void) {
|
||||
if (mainSegment >= MAX_NUM_SEGMENTS) return 0;
|
||||
return mainSegment;
|
||||
}
|
||||
|
||||
uint32_t WS2812FX::getColor(void) {
|
||||
return _segments[getMainSegmentId()].colors[0];
|
||||
}
|
||||
|
||||
uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
{
|
||||
i = realPixelIndex(i);
|
||||
|
||||
#ifdef WLED_CUSTOM_LED_MAPPING
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
#endif
|
||||
|
||||
if (_skipFirstMode) i += LED_SKIP_AMOUNT;
|
||||
|
||||
if (i >= _lengthRaw) return 0;
|
||||
|
||||
RgbwColor col = bus->GetPixelColorRgbw(i);
|
||||
switch (colorOrder)
|
||||
{
|
||||
// W G R B
|
||||
case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default
|
||||
case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811
|
||||
case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG
|
||||
case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG
|
||||
case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR
|
||||
case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) {
|
||||
if (id >= MAX_NUM_SEGMENTS) return _segments[0];
|
||||
return _segments[id];
|
||||
}
|
||||
|
||||
WS2812FX::Segment_runtime WS2812FX::getSegmentRuntime(void) {
|
||||
return SEGENV;
|
||||
}
|
||||
|
||||
WS2812FX::Segment* WS2812FX::getSegments(void) {
|
||||
return _segments;
|
||||
}
|
||||
|
||||
uint32_t WS2812FX::getLastShow(void) {
|
||||
return _lastShow;
|
||||
}
|
||||
|
||||
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) {
|
||||
if (n >= MAX_NUM_SEGMENTS) return;
|
||||
Segment& seg = _segments[n];
|
||||
|
||||
//return if neither bounds nor grouping have changed
|
||||
if (seg.start == i1 && seg.stop == i2 && (!grouping || (seg.grouping == grouping && seg.spacing == spacing))) return;
|
||||
|
||||
if (seg.stop) setRange(seg.start, seg.stop -1, 0); //turn old segment range off
|
||||
if (i2 <= i1) //disable segment
|
||||
{
|
||||
seg.stop = 0;
|
||||
if (n == mainSegment) //if main segment is deleted, set first active as main segment
|
||||
{
|
||||
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
if (_segments[i].isActive()) {
|
||||
mainSegment = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
mainSegment = 0; //should not happen (always at least one active segment)
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (i1 < _length) seg.start = i1;
|
||||
seg.stop = i2;
|
||||
if (i2 > _length) seg.stop = _length;
|
||||
if (grouping) {
|
||||
seg.grouping = grouping;
|
||||
seg.spacing = spacing;
|
||||
}
|
||||
_segment_runtimes[n].reset();
|
||||
}
|
||||
|
||||
void WS2812FX::resetSegments() {
|
||||
mainSegment = 0;
|
||||
memset(_segments, 0, sizeof(_segments));
|
||||
//memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
|
||||
_segment_index = 0;
|
||||
_segments[0].mode = DEFAULT_MODE;
|
||||
_segments[0].colors[0] = DEFAULT_COLOR;
|
||||
_segments[0].start = 0;
|
||||
_segments[0].speed = DEFAULT_SPEED;
|
||||
_segments[0].stop = _length;
|
||||
_segments[0].grouping = 1;
|
||||
_segments[0].setOption(SEG_OPTION_SELECTED, 1);
|
||||
_segments[0].setOption(SEG_OPTION_ON, 1);
|
||||
_segments[0].opacity = 255;
|
||||
|
||||
for (uint16_t i = 1; i < MAX_NUM_SEGMENTS; i++)
|
||||
{
|
||||
_segments[i].colors[0] = color_wheel(i*51);
|
||||
_segments[i].grouping = 1;
|
||||
_segments[i].setOption(SEG_OPTION_ON, 1);
|
||||
_segments[i].opacity = 255;
|
||||
_segment_runtimes[i].reset();
|
||||
}
|
||||
_segment_runtimes[0].reset();
|
||||
}
|
||||
|
||||
void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
|
||||
{
|
||||
if (i2 >= i)
|
||||
{
|
||||
for (uint16_t x = i; x <= i2; x++) setPixelColor(x, col);
|
||||
} else
|
||||
{
|
||||
for (uint16_t x = i2; x <= i; x++) setPixelColor(x, col);
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::setShowCallback(show_callback cb)
|
||||
{
|
||||
_callback = cb;
|
||||
}
|
||||
|
||||
void WS2812FX::setTransitionMode(bool t)
|
||||
{
|
||||
_segment_index = getMainSegmentId();
|
||||
SEGMENT.setOption(SEG_OPTION_TRANSITIONAL, t);
|
||||
if (!t) return;
|
||||
unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled
|
||||
if (SEGMENT.mode == FX_MODE_STATIC && SEGENV.next_time > waitMax) SEGENV.next_time = waitMax;
|
||||
}
|
||||
|
||||
/*
|
||||
* color blend function
|
||||
*/
|
||||
uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint8_t blend) {
|
||||
if(blend == 0) return color1;
|
||||
if(blend == 255) return color2;
|
||||
|
||||
uint32_t w1 = (color1 >> 24) & 0xff;
|
||||
uint32_t r1 = (color1 >> 16) & 0xff;
|
||||
uint32_t g1 = (color1 >> 8) & 0xff;
|
||||
uint32_t b1 = color1 & 0xff;
|
||||
|
||||
uint32_t w2 = (color2 >> 24) & 0xff;
|
||||
uint32_t r2 = (color2 >> 16) & 0xff;
|
||||
uint32_t g2 = (color2 >> 8) & 0xff;
|
||||
uint32_t b2 = color2 & 0xff;
|
||||
|
||||
uint32_t w3 = ((w2 * blend) + (w1 * (255 - blend))) >> 8;
|
||||
uint32_t r3 = ((r2 * blend) + (r1 * (255 - blend))) >> 8;
|
||||
uint32_t g3 = ((g2 * blend) + (g1 * (255 - blend))) >> 8;
|
||||
uint32_t b3 = ((b2 * blend) + (b1 * (255 - blend))) >> 8;
|
||||
|
||||
return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3));
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills segment with color
|
||||
*/
|
||||
void WS2812FX::fill(uint32_t c) {
|
||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
||||
setPixelColor(i, c);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fade out function, higher rate = quicker fade
|
||||
*/
|
||||
void WS2812FX::fade_out(uint8_t rate) {
|
||||
rate = (255-rate) >> 1;
|
||||
float mappedRate = float(rate) +1.1;
|
||||
|
||||
uint32_t color = SEGCOLOR(1); // target color
|
||||
int w2 = (color >> 24) & 0xff;
|
||||
int r2 = (color >> 16) & 0xff;
|
||||
int g2 = (color >> 8) & 0xff;
|
||||
int b2 = color & 0xff;
|
||||
|
||||
for(uint16_t i = 0; i < SEGLEN; i++) {
|
||||
color = getPixelColor(i);
|
||||
int w1 = (color >> 24) & 0xff;
|
||||
int r1 = (color >> 16) & 0xff;
|
||||
int g1 = (color >> 8) & 0xff;
|
||||
int b1 = color & 0xff;
|
||||
|
||||
int wdelta = (w2 - w1) / mappedRate;
|
||||
int rdelta = (r2 - r1) / mappedRate;
|
||||
int gdelta = (g2 - g1) / mappedRate;
|
||||
int bdelta = (b2 - b1) / mappedRate;
|
||||
|
||||
// if fade isn't complete, make sure delta is at least 1 (fixes rounding issues)
|
||||
wdelta += (w2 == w1) ? 0 : (w2 > w1) ? 1 : -1;
|
||||
rdelta += (r2 == r1) ? 0 : (r2 > r1) ? 1 : -1;
|
||||
gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1;
|
||||
bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1;
|
||||
|
||||
setPixelColor(i, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* blurs segment content, source: FastLED colorutils.cpp
|
||||
*/
|
||||
void WS2812FX::blur(uint8_t blur_amount)
|
||||
{
|
||||
uint8_t keep = 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
for(uint16_t i = 0; i < SEGLEN; i++)
|
||||
{
|
||||
CRGB cur = col_to_crgb(getPixelColor(i));
|
||||
CRGB part = cur;
|
||||
part.nscale8(seep);
|
||||
cur.nscale8(keep);
|
||||
cur += carryover;
|
||||
if(i > 0) {
|
||||
uint32_t c = getPixelColor(i-1);
|
||||
uint8_t r = (c >> 16 & 0xFF);
|
||||
uint8_t g = (c >> 8 & 0xFF);
|
||||
uint8_t b = (c & 0xFF);
|
||||
setPixelColor(i-1, qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
|
||||
}
|
||||
setPixelColor(i,cur.red, cur.green, cur.blue);
|
||||
carryover = part;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::triwave16(uint16_t in)
|
||||
{
|
||||
if (in < 0x8000) return in *2;
|
||||
return 0xFFFF - (in - 0x8000)*2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put a value 0 to 255 in to get a color value.
|
||||
* The colours are a transition r -> g -> b -> back to r
|
||||
* Inspired by the Adafruit examples.
|
||||
*/
|
||||
uint32_t WS2812FX::color_wheel(uint8_t pos) {
|
||||
if (SEGMENT.palette) return color_from_palette(pos, false, true, 0);
|
||||
pos = 255 - pos;
|
||||
if(pos < 85) {
|
||||
return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3);
|
||||
} else if(pos < 170) {
|
||||
pos -= 85;
|
||||
return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3);
|
||||
} else {
|
||||
pos -= 170;
|
||||
return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a new, random wheel index with a minimum distance of 42 from pos.
|
||||
*/
|
||||
uint8_t WS2812FX::get_random_wheel_index(uint8_t pos) {
|
||||
uint8_t r = 0, x = 0, y = 0, d = 0;
|
||||
|
||||
while(d < 42) {
|
||||
r = random8();
|
||||
x = abs(pos - r);
|
||||
y = 255 - x;
|
||||
d = MIN(x, y);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
uint32_t WS2812FX::crgb_to_col(CRGB fastled)
|
||||
{
|
||||
return (((uint32_t)fastled.red << 16) | ((uint32_t)fastled.green << 8) | fastled.blue);
|
||||
}
|
||||
|
||||
|
||||
CRGB WS2812FX::col_to_crgb(uint32_t color)
|
||||
{
|
||||
CRGB fastled_col;
|
||||
fastled_col.red = (color >> 16 & 0xFF);
|
||||
fastled_col.green = (color >> 8 & 0xFF);
|
||||
fastled_col.blue = (color & 0xFF);
|
||||
return fastled_col;
|
||||
}
|
||||
|
||||
|
||||
void WS2812FX::load_gradient_palette(uint8_t index)
|
||||
{
|
||||
byte i = constrain(index, 0, GRADIENT_PALETTE_COUNT -1);
|
||||
byte tcp[72]; //support gradient palettes with up to 18 entries
|
||||
memcpy_P(tcp, (byte*)pgm_read_dword(&(gGradientPalettes[i])), 72);
|
||||
targetPalette.loadDynamicGradientPalette(tcp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FastLED palette modes helper function. Limitation: Due to memory reasons, multiple active segments with FastLED will disable the Palette transitions
|
||||
*/
|
||||
void WS2812FX::handle_palette(void)
|
||||
{
|
||||
bool singleSegmentMode = (_segment_index == _segment_index_palette_last);
|
||||
_segment_index_palette_last = _segment_index;
|
||||
|
||||
byte paletteIndex = SEGMENT.palette;
|
||||
if (SEGMENT.mode == FX_MODE_GLITTER && paletteIndex == 0) paletteIndex = 11;
|
||||
if (SEGMENT.mode >= FX_MODE_METEOR && paletteIndex == 0) paletteIndex = 4;
|
||||
|
||||
switch (paletteIndex)
|
||||
{
|
||||
case 0: {//default palette. Differs depending on effect
|
||||
switch (SEGMENT.mode)
|
||||
{
|
||||
case FX_MODE_FIRE_2012 : load_gradient_palette(22); break;//heat palette
|
||||
case FX_MODE_COLORWAVES : load_gradient_palette(13); break;//landscape 33
|
||||
case FX_MODE_FILLNOISE8 : targetPalette = OceanColors_p; break;
|
||||
case FX_MODE_NOISE16_1 : load_gradient_palette(17); break;//Drywet
|
||||
case FX_MODE_NOISE16_2 : load_gradient_palette(30); break;//Blue cyan yellow
|
||||
case FX_MODE_NOISE16_3 : load_gradient_palette(22); break;//heat palette
|
||||
case FX_MODE_NOISE16_4 : load_gradient_palette(13); break;//landscape 33
|
||||
//case FX_MODE_GLITTER : targetPalette = RainbowColors_p; break;
|
||||
|
||||
default: targetPalette = PartyColors_p; break;//palette, bpm
|
||||
}
|
||||
break;}
|
||||
case 1: {//periodically replace palette with a random one. Doesn't work with multiple FastLED segments
|
||||
if (!singleSegmentMode)
|
||||
{
|
||||
targetPalette = PartyColors_p; break; //fallback
|
||||
}
|
||||
if (millis() - _lastPaletteChange > 1000 + ((uint32_t)(255-SEGMENT.intensity))*100)
|
||||
{
|
||||
targetPalette = CRGBPalette16(
|
||||
CHSV(random8(), 255, random8(128, 255)),
|
||||
CHSV(random8(), 255, random8(128, 255)),
|
||||
CHSV(random8(), 192, random8(128, 255)),
|
||||
CHSV(random8(), 255, random8(128, 255)));
|
||||
_lastPaletteChange = millis();
|
||||
} break;}
|
||||
case 2: {//primary color only
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
targetPalette = CRGBPalette16(prim); break;}
|
||||
case 3: {//primary + secondary
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
CRGB sec = col_to_crgb(SEGCOLOR(1));
|
||||
targetPalette = CRGBPalette16(prim,prim,sec,sec); break;}
|
||||
case 4: {//primary + secondary + tertiary
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
CRGB sec = col_to_crgb(SEGCOLOR(1));
|
||||
CRGB ter = col_to_crgb(SEGCOLOR(2));
|
||||
targetPalette = CRGBPalette16(ter,sec,prim); break;}
|
||||
case 5: {//primary + secondary (+tert if not off), more distinct
|
||||
CRGB prim = col_to_crgb(SEGCOLOR(0));
|
||||
CRGB sec = col_to_crgb(SEGCOLOR(1));
|
||||
if (SEGCOLOR(2)) {
|
||||
CRGB ter = col_to_crgb(SEGCOLOR(2));
|
||||
targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,ter,ter,ter,ter,ter,prim);
|
||||
} else {
|
||||
targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,sec,sec,sec);
|
||||
}
|
||||
break;}
|
||||
case 6: //Party colors
|
||||
targetPalette = PartyColors_p; break;
|
||||
case 7: //Cloud colors
|
||||
targetPalette = CloudColors_p; break;
|
||||
case 8: //Lava colors
|
||||
targetPalette = LavaColors_p; break;
|
||||
case 9: //Ocean colors
|
||||
targetPalette = OceanColors_p; break;
|
||||
case 10: //Forest colors
|
||||
targetPalette = ForestColors_p; break;
|
||||
case 11: //Rainbow colors
|
||||
targetPalette = RainbowColors_p; break;
|
||||
case 12: //Rainbow stripe colors
|
||||
targetPalette = RainbowStripeColors_p; break;
|
||||
default: //progmem palettes
|
||||
load_gradient_palette(SEGMENT.palette -13);
|
||||
}
|
||||
|
||||
if (singleSegmentMode && paletteFade) //only blend if just one segment uses FastLED mode
|
||||
{
|
||||
nblendPaletteTowardPalette(currentPalette, targetPalette, 48);
|
||||
} else
|
||||
{
|
||||
currentPalette = targetPalette;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri)
|
||||
{
|
||||
if (SEGMENT.palette == 0 && mcol < 3) return SEGCOLOR(mcol); //WS2812FX default
|
||||
uint8_t paletteIndex = i;
|
||||
if (mapping) paletteIndex = (i*255)/(SEGLEN -1);
|
||||
if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
||||
CRGB fastled_col;
|
||||
fastled_col = ColorFromPalette( currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND);
|
||||
return fastled_col.r*65536 + fastled_col.g*256 + fastled_col.b;
|
||||
}
|
||||
|
||||
bool WS2812FX::segmentsAreIdentical(Segment* a, Segment* b)
|
||||
{
|
||||
//if (a->start != b->start) return false;
|
||||
//if (a->stop != b->stop) return false;
|
||||
for (uint8_t i = 0; i < NUM_COLORS; i++)
|
||||
{
|
||||
if (a->colors[i] != b->colors[i]) return false;
|
||||
}
|
||||
if (a->mode != b->mode) return false;
|
||||
if (a->speed != b->speed) return false;
|
||||
if (a->intensity != b->intensity) return false;
|
||||
if (a->palette != b->palette) return false;
|
||||
//if (a->getOption(SEG_OPTION_REVERSED) != b->getOption(SEG_OPTION_REVERSED)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef WLED_USE_ANALOG_LEDS
|
||||
void WS2812FX::setRgbwPwm(void) {
|
||||
uint32_t nowUp = millis(); // Be aware, millis() rolls over every 49 days
|
||||
if (nowUp - _analogLastShow < MIN_SHOW_DELAY) return;
|
||||
|
||||
_analogLastShow = nowUp;
|
||||
|
||||
RgbwColor color = bus->GetPixelColorRgbw(0);
|
||||
byte b = getBrightness();
|
||||
if (color == _analogLastColor && b == _analogLastBri) return;
|
||||
|
||||
// check color values for Warm / Cold white mix (for RGBW) // EsplanexaDevice.cpp
|
||||
#ifdef WLED_USE_5CH_LEDS
|
||||
if (color.R == 255 && color.G == 255 && color.B == 255 && color.W == 255) {
|
||||
bus->SetRgbwPwm(0, 0, 0, 0, color.W * b / 255);
|
||||
} else if (color.R == 127 && color.G == 127 && color.B == 127 && color.W == 255) {
|
||||
bus->SetRgbwPwm(0, 0, 0, color.W * b / 512, color.W * b / 255);
|
||||
} else if (color.R == 0 && color.G == 0 && color.B == 0 && color.W == 255) {
|
||||
bus->SetRgbwPwm(0, 0, 0, color.W * b / 255, 0);
|
||||
} else if (color.R == 130 && color.G == 90 && color.B == 0 && color.W == 255) {
|
||||
bus->SetRgbwPwm(0, 0, 0, color.W * b / 255, color.W * b / 512);
|
||||
} else if (color.R == 255 && color.G == 153 && color.B == 0 && color.W == 255) {
|
||||
bus->SetRgbwPwm(0, 0, 0, color.W * b / 255, 0);
|
||||
} else { // not only white colors
|
||||
bus->SetRgbwPwm(color.R * b / 255, color.G * b / 255, color.B * b / 255, color.W * b / 255);
|
||||
}
|
||||
#else
|
||||
bus->SetRgbwPwm(color.R * b / 255, color.G * b / 255, color.B * b / 255, color.W * b / 255);
|
||||
#endif
|
||||
_analogLastColor = color;
|
||||
_analogLastBri = b;
|
||||
}
|
||||
#else
|
||||
void WS2812FX::setRgbwPwm() {}
|
||||
#endif
|
||||
|
||||
//gamma 2.4 lookup table used for color correction
|
||||
const byte gammaT[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
|
||||
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
|
||||
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
|
||||
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
|
||||
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
|
||||
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
|
||||
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
|
||||
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
|
||||
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
|
||||
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
|
||||
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
|
||||
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
||||
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
||||
|
||||
uint8_t WS2812FX::gamma8(uint8_t b)
|
||||
{
|
||||
return gammaT[b];
|
||||
}
|
||||
|
||||
uint32_t WS2812FX::gamma32(uint32_t color)
|
||||
{
|
||||
if (!gammaCorrectCol) return color;
|
||||
uint8_t w = (color >> 24);
|
||||
uint8_t r = (color >> 16);
|
||||
uint8_t g = (color >> 8);
|
||||
uint8_t b = color;
|
||||
w = gammaT[w];
|
||||
r = gammaT[r];
|
||||
g = gammaT[g];
|
||||
b = gammaT[b];
|
||||
return ((w << 24) | (r << 16) | (g << 8) | (b));
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::_usedSegmentData = 0;
|
||||
@@ -2,29 +2,113 @@
|
||||
#ifndef NpbWrapper_h
|
||||
#define NpbWrapper_h
|
||||
|
||||
//#define WORKAROUND_ESP32_BITBANG
|
||||
//see https://github.com/Aircoookie/WLED/issues/2 for flicker free ESP32 support
|
||||
|
||||
//PIN CONFIGURATION
|
||||
#define LEDPIN 2 //strip pin. Any for ESP32, gpio2 is recommended for ESP8266
|
||||
#define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended)
|
||||
#define IR_PIN 4 //infrared pin.
|
||||
#define AUXPIN 15 //unused auxiliary output pin
|
||||
#ifndef LEDPIN
|
||||
#define LEDPIN 2 //strip pin. Any for ESP32, gpio2 or 3 is recommended for ESP8266 (gpio2/3 are labeled D4/RX on NodeMCU and Wemos)
|
||||
#endif
|
||||
//#define USE_APA102 // Uncomment for using APA102 LEDs.
|
||||
//#define USE_WS2801 // Uncomment for using WS2801 LEDs (make sure you have NeoPixelBus v2.5.6 or newer)
|
||||
//#define USE_LPD8806 // Uncomment for using LPD8806
|
||||
//#define USE_TM1814 // Uncomment for using TM1814 LEDs (make sure you have NeoPixelBus v2.5.7 or newer)
|
||||
//#define USE_P9813 // Uncomment for using P9813 LEDs (make sure you have NeoPixelBus v2.5.8 or newer)
|
||||
//#define WLED_USE_ANALOG_LEDS //Uncomment for using "dumb" PWM controlled LEDs (see pins below, default R: gpio5, G: 12, B: 15, W: 13)
|
||||
//#define WLED_USE_H801 //H801 controller. Please uncomment #define WLED_USE_ANALOG_LEDS as well
|
||||
//#define WLED_USE_5CH_LEDS //5 Channel H801 for cold and warm white
|
||||
|
||||
#ifndef BTNPIN
|
||||
#define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended)
|
||||
#endif
|
||||
|
||||
#ifndef IR_PIN
|
||||
#define IR_PIN 4 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
|
||||
#endif
|
||||
|
||||
#ifndef RLYPIN
|
||||
#define RLYPIN 12 //pin for relay, will be set HIGH if LEDs are on (-1 to disable). Also usable for standby leds, triggers,...
|
||||
#endif
|
||||
|
||||
#ifndef AUXPIN
|
||||
#define AUXPIN -1 //debug auxiliary output pin (-1 to disable)
|
||||
#endif
|
||||
|
||||
#ifndef RLYMDE
|
||||
#define RLYMDE 1 //mode for relay, 0: LOW if LEDs are on 1: HIGH if LEDs are on
|
||||
#endif
|
||||
|
||||
//END CONFIGURATION
|
||||
|
||||
#if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813)
|
||||
#define CLKPIN 0
|
||||
#define DATAPIN 2
|
||||
#if BTNPIN == CLKPIN || BTNPIN == DATAPIN
|
||||
#undef BTNPIN // Deactivate button pin if it conflicts with one of the APA102 pins.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WLED_USE_ANALOG_LEDS
|
||||
//PWM pins - PINs 15,13,12,14 (W2 = 04)are used with H801 Wifi LED Controller
|
||||
#ifdef WLED_USE_H801
|
||||
#define RPIN 15 //R pin for analog LED strip
|
||||
#define GPIN 13 //G pin for analog LED strip
|
||||
#define BPIN 12 //B pin for analog LED strip
|
||||
#define WPIN 14 //W pin for analog LED strip
|
||||
#define W2PIN 04 //W2 pin for analog LED strip
|
||||
#undef BTNPIN
|
||||
#undef IR_PIN
|
||||
#define IR_PIN 0 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
|
||||
#elif defined(WLED_USE_BWLT11)
|
||||
//PWM pins - to use with BW-LT11
|
||||
#define RPIN 12 //R pin for analog LED strip
|
||||
#define GPIN 4 //G pin for analog LED strip
|
||||
#define BPIN 14 //B pin for analog LED strip
|
||||
#define WPIN 5 //W pin for analog LED strip
|
||||
#elif defined(SHOJO_PCB)
|
||||
//PWM pins - to use with Shojo PCB (https://www.bastelbunker.de/esp-rgbww-wifi-led-controller-vbs-edition/)
|
||||
#define RPIN 14 //R pin for analog LED strip
|
||||
#define GPIN 4 //G pin for analog LED strip
|
||||
#define BPIN 5 //B pin for analog LED strip
|
||||
#define WPIN 15 //W pin for analog LED strip
|
||||
#define W2PIN 12 //W2 pin for analog LED strip
|
||||
#else
|
||||
//PWM pins - PINs 5,12,13,15 are used with Magic Home LED Controller
|
||||
#define RPIN 5 //R pin for analog LED strip
|
||||
#define GPIN 12 //G pin for analog LED strip
|
||||
#define BPIN 15 //B pin for analog LED strip
|
||||
#define WPIN 13 //W pin for analog LED strip
|
||||
#endif
|
||||
#undef RLYPIN
|
||||
#define RLYPIN -1 //disable as pin 12 is used by analog LEDs
|
||||
#endif
|
||||
|
||||
//automatically uses the right driver method for each platform
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#ifdef WORKAROUND_ESP32_BITBANG
|
||||
#define PIXELMETHOD NeoEsp32BitBangWs2813Method
|
||||
#pragma message "Software BitBang is used because of your NeoPixelBus version. Look in NpbWrapper.h for instructions on how to mitigate flickering."
|
||||
#ifdef USE_APA102
|
||||
#define PIXELMETHOD DotStarMethod
|
||||
#elif defined(USE_WS2801)
|
||||
#define PIXELMETHOD NeoWs2801Method
|
||||
#elif defined(USE_LPD8806)
|
||||
#define PIXELMETHOD Lpd8806Method
|
||||
#elif defined(USE_TM1814)
|
||||
#define PIXELMETHOD NeoTm1814Method
|
||||
#elif defined(USE_P9813)
|
||||
#define PIXELMETHOD P9813Method
|
||||
#else
|
||||
#define PIXELMETHOD NeoWs2813Method
|
||||
#define PIXELMETHOD NeoEsp32Rmt0Ws2812xMethod
|
||||
#endif
|
||||
#else //esp8266
|
||||
//autoselect the right method depending on strip pin
|
||||
#if LEDPIN == 2
|
||||
#define PIXELMETHOD NeoEsp8266UartWs2813Method //if you get an error here, try to change to NeoEsp8266Uart1Ws2813Method or use Neopixelbus v2.3.5
|
||||
#ifdef USE_APA102
|
||||
#define PIXELMETHOD DotStarMethod
|
||||
#elif defined(USE_WS2801)
|
||||
#define PIXELMETHOD NeoWs2801Method
|
||||
#elif defined(USE_LPD8806)
|
||||
#define PIXELMETHOD Lpd8806Method
|
||||
#elif defined(USE_TM1814)
|
||||
#define PIXELMETHOD NeoTm1814Method
|
||||
#elif defined(USE_P9813)
|
||||
#define PIXELMETHOD P9813Method
|
||||
#elif LEDPIN == 2
|
||||
#define PIXELMETHOD NeoEsp8266Uart1Ws2813Method //if you get an error here, try to change to NeoEsp8266UartWs2813Method or update Neopixelbus
|
||||
#elif LEDPIN == 3
|
||||
#define PIXELMETHOD NeoEsp8266Dma800KbpsMethod
|
||||
#else
|
||||
@@ -35,8 +119,22 @@
|
||||
|
||||
|
||||
//you can now change the color order in the web settings
|
||||
#define PIXELFEATURE3 NeoGrbFeature
|
||||
#define PIXELFEATURE4 NeoGrbwFeature
|
||||
#ifdef USE_APA102
|
||||
#define PIXELFEATURE3 DotStarBgrFeature
|
||||
#define PIXELFEATURE4 DotStarLbgrFeature
|
||||
#elif defined(USE_LPD8806)
|
||||
#define PIXELFEATURE3 Lpd8806GrbFeature
|
||||
#define PIXELFEATURE4 Lpd8806GrbFeature
|
||||
#elif defined(USE_TM1814)
|
||||
#define PIXELFEATURE3 NeoWrgbTm1814Feature
|
||||
#define PIXELFEATURE4 NeoWrgbTm1814Feature
|
||||
#elif defined(USE_P9813)
|
||||
#define PIXELFEATURE3 P9813BgrFeature
|
||||
#define PIXELFEATURE4 NeoGrbwFeature
|
||||
#else
|
||||
#define PIXELFEATURE3 NeoGrbFeature
|
||||
#define PIXELFEATURE4 NeoGrbwFeature
|
||||
#endif
|
||||
|
||||
|
||||
#include <NeoPixelBrightnessBus.h>
|
||||
@@ -74,61 +172,117 @@ public:
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb:
|
||||
#if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813)
|
||||
_pGrb = new NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>(countPixels, CLKPIN, DATAPIN);
|
||||
#else
|
||||
_pGrb = new NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>(countPixels, LEDPIN);
|
||||
#endif
|
||||
_pGrb->Begin();
|
||||
break;
|
||||
|
||||
case NeoPixelType_Grbw:
|
||||
#if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813)
|
||||
_pGrbw = new NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>(countPixels, CLKPIN, DATAPIN);
|
||||
#else
|
||||
_pGrbw = new NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>(countPixels, LEDPIN);
|
||||
#endif
|
||||
_pGrbw->Begin();
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WLED_USE_ANALOG_LEDS
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
ledcSetup(0, 5000, 8);
|
||||
ledcAttachPin(RPIN, 0);
|
||||
ledcSetup(1, 5000, 8);
|
||||
ledcAttachPin(GPIN, 1);
|
||||
ledcSetup(2, 5000, 8);
|
||||
ledcAttachPin(BPIN, 2);
|
||||
if(_type == NeoPixelType_Grbw)
|
||||
{
|
||||
ledcSetup(3, 5000, 8);
|
||||
ledcAttachPin(WPIN, 3);
|
||||
#ifdef WLED_USE_5CH_LEDS
|
||||
ledcSetup(4, 5000, 8);
|
||||
ledcAttachPin(W2PIN, 4);
|
||||
#endif
|
||||
}
|
||||
#else // ESP8266
|
||||
//init PWM pins
|
||||
pinMode(RPIN, OUTPUT);
|
||||
pinMode(GPIN, OUTPUT);
|
||||
pinMode(BPIN, OUTPUT);
|
||||
if(_type == NeoPixelType_Grbw)
|
||||
{
|
||||
pinMode(WPIN, OUTPUT);
|
||||
#ifdef WLED_USE_5CH_LEDS
|
||||
pinMode(W2PIN, OUTPUT);
|
||||
#endif
|
||||
}
|
||||
analogWriteRange(255); //same range as one RGB channel
|
||||
analogWriteFreq(880); //PWM frequency proven as good for LEDs
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WLED_USE_ANALOG_LEDS
|
||||
void SetRgbwPwm(uint8_t r, uint8_t g, uint8_t b, uint8_t w, uint8_t w2=0)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
ledcWrite(0, r);
|
||||
ledcWrite(1, g);
|
||||
ledcWrite(2, b);
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: break;
|
||||
#ifdef WLED_USE_5CH_LEDS
|
||||
case NeoPixelType_Grbw: ledcWrite(3, w); ledcWrite(4, w2); break;
|
||||
#else
|
||||
case NeoPixelType_Grbw: ledcWrite(3, w); break;
|
||||
#endif
|
||||
}
|
||||
#else // ESP8266
|
||||
analogWrite(RPIN, r);
|
||||
analogWrite(GPIN, g);
|
||||
analogWrite(BPIN, b);
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: break;
|
||||
#ifdef WLED_USE_5CH_LEDS
|
||||
case NeoPixelType_Grbw: analogWrite(WPIN, w); analogWrite(W2PIN, w2); break;
|
||||
#else
|
||||
case NeoPixelType_Grbw: analogWrite(WPIN, w); break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void Show()
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#ifdef WORKAROUND_ESP32_BITBANG
|
||||
delay(1);
|
||||
portDISABLE_INTERRUPTS(); //this is a workaround to prevent flickering (see https://github.com/adafruit/Adafruit_NeoPixel/issues/139)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
byte b;
|
||||
switch (_type)
|
||||
{
|
||||
case NeoPixelType_Grb: _pGrb->Show(); break;
|
||||
case NeoPixelType_Grbw: _pGrbw->Show(); break;
|
||||
}
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#ifdef WORKAROUND_ESP32_BITBANG
|
||||
portENABLE_INTERRUPTS();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CanShow() const
|
||||
{
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: _pGrb->CanShow(); break;
|
||||
case NeoPixelType_Grbw: _pGrbw->CanShow(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixelColor(uint16_t indexPixel, RgbColor color)
|
||||
{
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: _pGrb->SetPixelColor(indexPixel, color); break;
|
||||
case NeoPixelType_Grbw:_pGrbw->SetPixelColor(indexPixel, color); break;
|
||||
case NeoPixelType_Grb: _pGrb->Show(); break;
|
||||
case NeoPixelType_Grbw: _pGrbw->Show(); break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetPixelColor(uint16_t indexPixel, RgbwColor color)
|
||||
{
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: _pGrb->SetPixelColor(indexPixel, RgbColor(color.R,color.G,color.B)); break;
|
||||
case NeoPixelType_Grbw: _pGrbw->SetPixelColor(indexPixel, color); break;
|
||||
case NeoPixelType_Grb: {
|
||||
_pGrb->SetPixelColor(indexPixel, RgbColor(color.R,color.G,color.B));
|
||||
}
|
||||
break;
|
||||
case NeoPixelType_Grbw: {
|
||||
#ifdef USE_LPD8806
|
||||
_pGrbw->SetPixelColor(indexPixel, RgbColor(color.R,color.G,color.B));
|
||||
#else
|
||||
_pGrbw->SetPixelColor(indexPixel, color);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetBrightness(byte b)
|
||||
@@ -139,15 +293,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
RgbColor GetPixelColor(uint16_t indexPixel) const
|
||||
{
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: return _pGrb->GetPixelColor(indexPixel); break;
|
||||
case NeoPixelType_Grbw: /*doesn't support it so we don't return it*/ break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Due to feature differences, some support RGBW but the method name
|
||||
// here needs to be unique, thus GetPixeColorRgbw
|
||||
RgbwColor GetPixelColorRgbw(uint16_t indexPixel) const
|
||||
@@ -159,21 +304,15 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ClearTo(RgbColor color)
|
||||
uint8_t* GetPixels(void)
|
||||
{
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: _pGrb->ClearTo(color); break;
|
||||
case NeoPixelType_Grbw:_pGrbw->ClearTo(color); break;
|
||||
case NeoPixelType_Grb: return _pGrb->Pixels(); break;
|
||||
case NeoPixelType_Grbw: return _pGrbw->Pixels(); break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ClearTo(RgbwColor color)
|
||||
{
|
||||
switch (_type) {
|
||||
case NeoPixelType_Grb: break;
|
||||
case NeoPixelType_Grbw:_pGrbw->ClearTo(color); break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
NeoPixelType _type;
|
||||
|
||||
2052
wled00/WS2812FX.cpp
2052
wled00/WS2812FX.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,717 +0,0 @@
|
||||
/*
|
||||
WS2812FX_fcn.cpp contains all utility functions
|
||||
Harm Aldick - 2016
|
||||
www.aldick.org
|
||||
LICENSE
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2016 Harm Aldick
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Modified heavily for WLED
|
||||
*/
|
||||
|
||||
#include "WS2812FX.h"
|
||||
#include "palettes.h"
|
||||
|
||||
#define LED_SKIP_AMOUNT 1
|
||||
|
||||
void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst)
|
||||
{
|
||||
if (supportWhite == _rgbwMode && countPixels == _length && _locked != NULL) return;
|
||||
RESET_RUNTIME;
|
||||
_rgbwMode = supportWhite;
|
||||
_skipFirstMode = skipFirst;
|
||||
_length = countPixels;
|
||||
|
||||
uint8_t ty = 1;
|
||||
if (supportWhite) ty =2;
|
||||
uint16_t lengthRaw = _length;
|
||||
if (_skipFirstMode) lengthRaw += LED_SKIP_AMOUNT;
|
||||
bus->Begin((NeoPixelType)ty, lengthRaw);
|
||||
|
||||
if (_locked != NULL) delete _locked;
|
||||
_locked = new byte[_length];
|
||||
|
||||
_segments[0].start = 0;
|
||||
_segments[0].stop = _length -1;
|
||||
|
||||
unlockAll();
|
||||
setBrightness(_brightness);
|
||||
}
|
||||
|
||||
void WS2812FX::service() {
|
||||
unsigned long now = millis(); // Be aware, millis() rolls over every 49 days
|
||||
bool doShow = false;
|
||||
for(uint8_t i=0; i < _num_segments; i++)
|
||||
{
|
||||
_segment_index = i;
|
||||
if(now > SEGMENT_RUNTIME.next_time || _triggered)
|
||||
{
|
||||
doShow = true;
|
||||
handle_palette();
|
||||
uint16_t delay = (this->*_mode[SEGMENT.mode])();
|
||||
SEGMENT_RUNTIME.next_time = now + max(delay, 5);
|
||||
SEGMENT_RUNTIME.counter_mode_call++;
|
||||
}
|
||||
}
|
||||
if(doShow) {
|
||||
show();
|
||||
}
|
||||
_triggered = false;
|
||||
}
|
||||
|
||||
bool WS2812FX::modeUsesLock(uint8_t m)
|
||||
{
|
||||
if (m == FX_MODE_FIRE_2012 || m == FX_MODE_COLORTWINKLE ||
|
||||
m == FX_MODE_METEOR || m == FX_MODE_METEOR_SMOOTH ||
|
||||
m == FX_MODE_RIPPLE) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
|
||||
uint8_t w = (c >> 24) & 0xFF;
|
||||
uint8_t r = (c >> 16) & 0xFF;
|
||||
uint8_t g = (c >> 8) & 0xFF;
|
||||
uint8_t b = c & 0xFF;
|
||||
setPixelColor(n, r, g, b, w);
|
||||
}
|
||||
|
||||
void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
{
|
||||
if (_locked[i] && !_modeUsesLock) return;
|
||||
if (_reverseMode) i = _length - 1 -i;
|
||||
if (IS_REVERSE) i = SEGMENT.stop - (i - SEGMENT.start); //reverse just individual segment
|
||||
byte tmpg = g;
|
||||
switch (colorOrder) //0 = Grb, default
|
||||
{
|
||||
case 0: break; //0 = Grb, default
|
||||
case 1: g = r; r = tmpg; break; //1 = Rgb, common for WS2811
|
||||
case 2: g = b; b = tmpg; break; //2 = Brg
|
||||
case 3: g = b; b = r; r = tmpg; //3 = Rbg
|
||||
}
|
||||
if (!_cronixieMode)
|
||||
{
|
||||
if (_skipFirstMode)
|
||||
{
|
||||
if (i < LED_SKIP_AMOUNT) bus->SetPixelColor(i, RgbwColor(0,0,0,0));
|
||||
i += LED_SKIP_AMOUNT;
|
||||
}
|
||||
|
||||
bus->SetPixelColor(i, RgbwColor(r,g,b,w));
|
||||
} else {
|
||||
if(i>6)return;
|
||||
byte o = 10*i;
|
||||
if (_cronixieBacklightEnabled && _cronixieDigits[i] <11)
|
||||
{
|
||||
byte r2 = (_segments[0].colors[1] >>16) & 0xFF;
|
||||
byte g2 = (_segments[0].colors[1] >> 8) & 0xFF;
|
||||
byte b2 = (_segments[0].colors[1] ) & 0xFF;
|
||||
byte w2 = (_segments[0].colors[1] >>24) & 0xFF;
|
||||
for (int j=o; j< o+19; j++)
|
||||
{
|
||||
bus->SetPixelColor(j, RgbwColor(r2,g2,b2,w2));
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (int j=o; j< o+19; j++)
|
||||
{
|
||||
bus->SetPixelColor(j, RgbwColor(0,0,0,0));
|
||||
}
|
||||
}
|
||||
if (_skipFirstMode) o += LED_SKIP_AMOUNT;
|
||||
switch(_cronixieDigits[i])
|
||||
{
|
||||
case 0: bus->SetPixelColor(o+5, RgbwColor(r,g,b,w)); break;
|
||||
case 1: bus->SetPixelColor(o+0, RgbwColor(r,g,b,w)); break;
|
||||
case 2: bus->SetPixelColor(o+6, RgbwColor(r,g,b,w)); break;
|
||||
case 3: bus->SetPixelColor(o+1, RgbwColor(r,g,b,w)); break;
|
||||
case 4: bus->SetPixelColor(o+7, RgbwColor(r,g,b,w)); break;
|
||||
case 5: bus->SetPixelColor(o+2, RgbwColor(r,g,b,w)); break;
|
||||
case 6: bus->SetPixelColor(o+8, RgbwColor(r,g,b,w)); break;
|
||||
case 7: bus->SetPixelColor(o+3, RgbwColor(r,g,b,w)); break;
|
||||
case 8: bus->SetPixelColor(o+9, RgbwColor(r,g,b,w)); break;
|
||||
case 9: bus->SetPixelColor(o+4, RgbwColor(r,g,b,w)); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::setReverseMode(bool b)
|
||||
{
|
||||
_reverseMode = b;
|
||||
}
|
||||
|
||||
void WS2812FX::driverModeCronixie(bool b)
|
||||
{
|
||||
_cronixieMode = b;
|
||||
_segments[0].stop = (b) ? 5 : _length-1;
|
||||
}
|
||||
|
||||
void WS2812FX::setCronixieBacklight(bool b)
|
||||
{
|
||||
_cronixieBacklightEnabled = b;
|
||||
}
|
||||
|
||||
void WS2812FX::setCronixieDigits(byte d[])
|
||||
{
|
||||
for (int i = 0; i<6; i++)
|
||||
{
|
||||
_cronixieDigits[i] = d[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//DISCLAIMER
|
||||
//The following function attemps to calculate the current LED power usage,
|
||||
//and will limit the brightness to stay below a set amperage threshold.
|
||||
//It is NOT a measurement and NOT guaranteed to stay within the ablMilliampsMax margin.
|
||||
//Stay safe with high amperage and have a reasonable safety margin!
|
||||
//I am NOT to be held liable for burned down garages!
|
||||
|
||||
//fine tune power estimation constants for your setup
|
||||
#define PU_PER_MA 3600 //power units per milliamperere for accurate power estimation
|
||||
//formula: 195075 divided by mA per fully lit LED, here ~54mA)
|
||||
//lowering the value increases the estimated usage and therefore makes the ABL more aggressive
|
||||
|
||||
#define MA_FOR_ESP 100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA)
|
||||
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
|
||||
|
||||
void WS2812FX::show(void) {
|
||||
//power limit calculation
|
||||
//each LED can draw up 195075 "power units" (approx. 53mA)
|
||||
//one PU is the power it takes to have 1 channel 1 step brighter per brightness step
|
||||
//so A=2,R=255,G=0,B=0 would use 510 PU per LED (1mA is about 3700 PU)
|
||||
|
||||
if (ablMilliampsMax > 149 && ablMilliampsMax < 65000) //lower numbers and 65000 turn off calculation
|
||||
{
|
||||
uint32_t powerBudget = (ablMilliampsMax - MA_FOR_ESP) * PU_PER_MA; //100mA for ESP power
|
||||
if (powerBudget > PU_PER_MA * _length) //each LED uses about 1mA in standby, exclude that from power budget
|
||||
{
|
||||
powerBudget -= PU_PER_MA * _length;
|
||||
} else
|
||||
{
|
||||
powerBudget = 0;
|
||||
}
|
||||
|
||||
uint32_t powerSum = 0;
|
||||
|
||||
for (uint16_t i = 0; i < _length; i++) //sum up the usage of each LED
|
||||
{
|
||||
RgbwColor c = bus->GetPixelColorRgbw(i);
|
||||
powerSum += (c.R + c.G + c.B + c.W);
|
||||
}
|
||||
|
||||
if (_rgbwMode) //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less
|
||||
{
|
||||
powerSum *= 3;
|
||||
powerSum >> 2; //same as /= 4
|
||||
}
|
||||
|
||||
uint32_t powerSum0 = powerSum;
|
||||
powerSum *= _brightness;
|
||||
|
||||
if (powerSum > powerBudget) //scale brightness down to stay in current limit
|
||||
{
|
||||
float scale = (float)powerBudget / (float)powerSum;
|
||||
uint16_t scaleI = scale * 255;
|
||||
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
|
||||
uint8_t newBri = scale8(_brightness, scaleB);
|
||||
bus->SetBrightness(newBri);
|
||||
currentMilliamps = (powerSum0 * newBri) / PU_PER_MA;
|
||||
} else
|
||||
{
|
||||
currentMilliamps = powerSum / PU_PER_MA;
|
||||
bus->SetBrightness(_brightness);
|
||||
}
|
||||
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
|
||||
currentMilliamps += _length; //add standby power back to estimate
|
||||
} else {
|
||||
currentMilliamps = 0;
|
||||
}
|
||||
|
||||
bus->Show();
|
||||
}
|
||||
|
||||
void WS2812FX::trigger() {
|
||||
_triggered = true;
|
||||
}
|
||||
|
||||
void WS2812FX::setMode(uint8_t m) {
|
||||
RESET_RUNTIME;
|
||||
bool ua = modeUsesLock(_segments[0].mode) && !modeUsesLock(m);
|
||||
if (m > MODE_COUNT - 1) m = MODE_COUNT - 1;
|
||||
_segments[0].mode = m;
|
||||
if (ua) unlockAll();
|
||||
_modeUsesLock = modeUsesLock(_segments[0].mode);
|
||||
setBrightness(_brightness);
|
||||
}
|
||||
|
||||
//TODO transitions
|
||||
|
||||
void WS2812FX::setSpeed(uint8_t s) {
|
||||
_segments[0].speed = s;
|
||||
}
|
||||
|
||||
void WS2812FX::setIntensity(uint8_t in) {
|
||||
_segments[0].intensity = in;
|
||||
}
|
||||
|
||||
void WS2812FX::setPalette(uint8_t p) {
|
||||
_segments[0].palette = p;
|
||||
}
|
||||
|
||||
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p) {
|
||||
bool changed = false;
|
||||
m = constrain(m, 0, MODE_COUNT - 1);
|
||||
if (m != _segments[0].mode) { setMode(m); changed = true; }
|
||||
if (s != _segments[0].speed) { setSpeed(s); changed = true; }
|
||||
if (i != _segments[0].intensity) { setIntensity(i); changed = true; }
|
||||
if (p != _segments[0].palette) { setPalette(p); changed = true; }
|
||||
return changed;
|
||||
}
|
||||
|
||||
void WS2812FX::setColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
|
||||
setColor(((uint32_t)w << 24) |((uint32_t)r << 16) | ((uint32_t)g << 8) | b);
|
||||
}
|
||||
|
||||
void WS2812FX::setSecondaryColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
|
||||
setSecondaryColor(((uint32_t)w << 24) |((uint32_t)r << 16) | ((uint32_t)g << 8) | b);
|
||||
}
|
||||
|
||||
void WS2812FX::setColor(uint32_t c) {
|
||||
_segments[0].colors[0] = c;
|
||||
}
|
||||
|
||||
void WS2812FX::setSecondaryColor(uint32_t c) {
|
||||
_segments[0].colors[1] = c;
|
||||
}
|
||||
|
||||
void WS2812FX::setBrightness(uint8_t b) {
|
||||
if (_brightness == b) return;
|
||||
_brightness = b;
|
||||
bus->SetBrightness(_brightness);
|
||||
show();
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getMode(void) {
|
||||
return _segments[0].mode;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getSpeed(void) {
|
||||
return _segments[0].speed;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getBrightness(void) {
|
||||
return _brightness;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getNumSegments(void) {
|
||||
return _num_segments;
|
||||
}
|
||||
|
||||
void WS2812FX::setNumSegments(uint8_t n) {
|
||||
_num_segments = n;
|
||||
}
|
||||
|
||||
uint32_t WS2812FX::getColor(void) {
|
||||
return _segments[0].colors[0];
|
||||
}
|
||||
|
||||
uint32_t WS2812FX::getPixelColor(uint16_t i)
|
||||
{
|
||||
if (_reverseMode) i = _length- 1 -i;
|
||||
if (_skipFirstMode) i += LED_SKIP_AMOUNT;
|
||||
if (_cronixieMode)
|
||||
{
|
||||
if(i>6)return 0;
|
||||
byte o = 10*i;
|
||||
switch(_cronixieDigits[i])
|
||||
{
|
||||
case 0: i=o+5; break;
|
||||
case 1: i=o+0; break;
|
||||
case 2: i=o+6; break;
|
||||
case 3: i=o+1; break;
|
||||
case 4: i=o+7; break;
|
||||
case 5: i=o+2; break;
|
||||
case 6: i=o+8; break;
|
||||
case 7: i=o+3; break;
|
||||
case 8: i=o+9; break;
|
||||
case 9: i=o+4; break;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
RgbwColor lColor = bus->GetPixelColorRgbw(i);
|
||||
byte r = lColor.R, g = lColor.G, b = lColor.B;
|
||||
switch (colorOrder)
|
||||
{
|
||||
case 0: break; //0 = Grb
|
||||
case 1: r = lColor.G; g = lColor.R; break; //1 = Rgb, common for WS2811
|
||||
case 2: g = lColor.B; b = lColor.G; break; //2 = Brg
|
||||
case 3: r = lColor.B; g = lColor.R; b = lColor.G; //3 = Rbg
|
||||
}
|
||||
return ( (lColor.W << 24) | (r << 16) | (g << 8) | (b) );
|
||||
}
|
||||
|
||||
WS2812FX::Segment WS2812FX::getSegment(void) {
|
||||
return SEGMENT;
|
||||
}
|
||||
|
||||
WS2812FX::Segment_runtime WS2812FX::getSegmentRuntime(void) {
|
||||
return SEGMENT_RUNTIME;
|
||||
}
|
||||
|
||||
WS2812FX::Segment* WS2812FX::getSegments(void) {
|
||||
return _segments;
|
||||
}
|
||||
|
||||
void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint8_t speed, uint8_t intensity, bool reverse) {
|
||||
uint32_t colors[] = {color, 0, 0};
|
||||
setSegment(n, start, stop, mode, colors, speed, intensity, reverse);
|
||||
}
|
||||
|
||||
void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint8_t speed, uint8_t intensity, bool reverse) {
|
||||
setSegment(n, start, stop, mode, colors, speed, intensity, (uint8_t)(reverse ? REVERSE : NO_OPTIONS));
|
||||
}
|
||||
|
||||
void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint8_t speed, uint8_t intensity, uint8_t options) {
|
||||
if(n < (sizeof(_segments) / sizeof(_segments[0]))) {
|
||||
if(n + 1 > _num_segments) _num_segments = n + 1;
|
||||
_segments[n].start = start;
|
||||
_segments[n].stop = stop;
|
||||
_segments[n].mode = mode;
|
||||
_segments[n].speed = speed;
|
||||
_segments[n].intensity = intensity;
|
||||
_segments[n].options = options;
|
||||
|
||||
for(uint8_t i=0; i<NUM_COLORS; i++) {
|
||||
_segments[n].colors[i] = colors[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::resetSegments() {
|
||||
memset(_segments, 0, sizeof(_segments));
|
||||
memset(_segment_runtimes, 0, sizeof(_segment_runtimes));
|
||||
_segment_index = 0;
|
||||
_num_segments = 1;
|
||||
setSegment(0, 0, 7, FX_MODE_STATIC, (const uint32_t[]){DEFAULT_COLOR, 0, 0}, DEFAULT_SPEED, 128, NO_OPTIONS);
|
||||
}
|
||||
|
||||
void WS2812FX::setIndividual(uint16_t i, uint32_t col)
|
||||
{
|
||||
if (modeUsesLock(SEGMENT.mode)) return;
|
||||
if (i >= 0 && i < _length)
|
||||
{
|
||||
_locked[i] = false;
|
||||
setPixelColor(i, col);
|
||||
_locked[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
|
||||
{
|
||||
if (i2 >= i)
|
||||
{
|
||||
for (uint16_t x = i; x <= i2; x++) setIndividual(x,col);
|
||||
} else
|
||||
{
|
||||
for (uint16_t x = i2; x <= i; x++) setIndividual(x,col);
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::lock(uint16_t i)
|
||||
{
|
||||
if (modeUsesLock(SEGMENT.mode)) return;
|
||||
if (i >= 0 && i < _length) _locked[i] = true;
|
||||
}
|
||||
|
||||
void WS2812FX::lockRange(uint16_t i, uint16_t i2)
|
||||
{
|
||||
if (modeUsesLock(SEGMENT.mode)) return;
|
||||
for (uint16_t x = i; x <= i2; x++)
|
||||
{
|
||||
if (i >= 0 && i < _length) _locked[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::unlock(uint16_t i)
|
||||
{
|
||||
if (modeUsesLock(SEGMENT.mode)) return;
|
||||
if (i >= 0 && i < _length) _locked[i] = false;
|
||||
}
|
||||
|
||||
void WS2812FX::unlockRange(uint16_t i, uint16_t i2)
|
||||
{
|
||||
if (modeUsesLock(SEGMENT.mode)) return;
|
||||
for (uint16_t x = i; x < i2; x++)
|
||||
{
|
||||
if (x >= 0 && x < _length) _locked[x] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::unlockAll()
|
||||
{
|
||||
for (int i=0; i < _length; i++) _locked[i] = false;
|
||||
}
|
||||
|
||||
void WS2812FX::setTransitionMode(bool t)
|
||||
{
|
||||
SEGMENT_RUNTIME.trans_act = (t) ? 1:2;
|
||||
if (!t) return;
|
||||
unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled
|
||||
if (SEGMENT.mode == FX_MODE_STATIC && SEGMENT_RUNTIME.next_time > waitMax) SEGMENT_RUNTIME.next_time = waitMax;
|
||||
}
|
||||
|
||||
/*
|
||||
* color blend function
|
||||
*/
|
||||
uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint8_t blend) {
|
||||
if(blend == 0) return color1;
|
||||
if(blend == 255) return color2;
|
||||
|
||||
int w1 = (color1 >> 24) & 0xff;
|
||||
int r1 = (color1 >> 16) & 0xff;
|
||||
int g1 = (color1 >> 8) & 0xff;
|
||||
int b1 = color1 & 0xff;
|
||||
|
||||
int w2 = (color2 >> 24) & 0xff;
|
||||
int r2 = (color2 >> 16) & 0xff;
|
||||
int g2 = (color2 >> 8) & 0xff;
|
||||
int b2 = color2 & 0xff;
|
||||
|
||||
uint32_t w3 = ((w2 * blend) + (w1 * (255 - blend))) >> 8;
|
||||
uint32_t r3 = ((r2 * blend) + (r1 * (255 - blend))) >> 8;
|
||||
uint32_t g3 = ((g2 * blend) + (g1 * (255 - blend))) >> 8;
|
||||
uint32_t b3 = ((b2 * blend) + (b1 * (255 - blend))) >> 8;
|
||||
|
||||
return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3));
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills segment with color
|
||||
*/
|
||||
void WS2812FX::fill(uint32_t c) {
|
||||
for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
|
||||
setPixelColor(i, c);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fade out function, higher rate = quicker fade
|
||||
*/
|
||||
void WS2812FX::fade_out(uint8_t rate) {
|
||||
rate = (255-rate) >> 1;
|
||||
float mappedRate = float(rate) +1.1;
|
||||
|
||||
uint32_t color = SEGMENT.colors[1]; // target color
|
||||
int w2 = (color >> 24) & 0xff;
|
||||
int r2 = (color >> 16) & 0xff;
|
||||
int g2 = (color >> 8) & 0xff;
|
||||
int b2 = color & 0xff;
|
||||
|
||||
for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
|
||||
color = getPixelColor(i);
|
||||
int w1 = (color >> 24) & 0xff;
|
||||
int r1 = (color >> 16) & 0xff;
|
||||
int g1 = (color >> 8) & 0xff;
|
||||
int b1 = color & 0xff;
|
||||
|
||||
int wdelta = (w2 - w1) / mappedRate;
|
||||
int rdelta = (r2 - r1) / mappedRate;
|
||||
int gdelta = (g2 - g1) / mappedRate;
|
||||
int bdelta = (b2 - b1) / mappedRate;
|
||||
|
||||
// if fade isn't complete, make sure delta is at least 1 (fixes rounding issues)
|
||||
wdelta += (w2 == w1) ? 0 : (w2 > w1) ? 1 : -1;
|
||||
rdelta += (r2 == r1) ? 0 : (r2 > r1) ? 1 : -1;
|
||||
gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1;
|
||||
bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1;
|
||||
|
||||
setPixelColor(i, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* blurs segment content, source: FastLED colorutils.cpp
|
||||
*/
|
||||
void WS2812FX::blur(uint8_t blur_amount)
|
||||
{
|
||||
uint8_t keep = 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
CRGB carryover = CRGB::Black;
|
||||
for(uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++)
|
||||
{
|
||||
CRGB cur = fastled_from_col(getPixelColor(i));
|
||||
CRGB part = cur;
|
||||
part.nscale8(seep);
|
||||
cur.nscale8(keep);
|
||||
cur += carryover;
|
||||
if(i > SEGMENT.start) {
|
||||
uint32_t c = getPixelColor(i-1);
|
||||
uint8_t r = (c >> 16 & 0xFF);
|
||||
uint8_t g = (c >> 8 & 0xFF);
|
||||
uint8_t b = (c & 0xFF);
|
||||
setPixelColor(i-1, qadd8(r, part.red), qadd8(g, part.green), qadd8(b, part.blue));
|
||||
}
|
||||
setPixelColor(i,cur.red, cur.green, cur.blue);
|
||||
carryover = part;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Put a value 0 to 255 in to get a color value.
|
||||
* The colours are a transition r -> g -> b -> back to r
|
||||
* Inspired by the Adafruit examples.
|
||||
*/
|
||||
uint32_t WS2812FX::color_wheel(uint8_t pos) {
|
||||
if (SEGMENT.palette) return color_from_palette(pos, false, true, 0);
|
||||
pos = 255 - pos;
|
||||
if(pos < 85) {
|
||||
return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3);
|
||||
} else if(pos < 170) {
|
||||
pos -= 85;
|
||||
return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3);
|
||||
} else {
|
||||
pos -= 170;
|
||||
return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a new, random wheel index with a minimum distance of 42 from pos.
|
||||
*/
|
||||
uint8_t WS2812FX::get_random_wheel_index(uint8_t pos) {
|
||||
uint8_t r = 0, x = 0, y = 0, d = 0;
|
||||
|
||||
while(d < 42) {
|
||||
r = random8();
|
||||
x = abs(pos - r);
|
||||
y = 255 - x;
|
||||
d = min(x, y);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
CRGB WS2812FX::fastled_from_col(uint32_t color)
|
||||
{
|
||||
CRGB fastled_col;
|
||||
fastled_col.red = (color >> 16 & 0xFF);
|
||||
fastled_col.green = (color >> 8 & 0xFF);
|
||||
fastled_col.blue = (color & 0xFF);
|
||||
return fastled_col;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FastLED palette modes helper function. Limitation: Due to memory reasons, multiple active segments with FastLED will disable the Palette transitions
|
||||
*/
|
||||
void WS2812FX::handle_palette(void)
|
||||
{
|
||||
bool singleSegmentMode = (_segment_index == _segment_index_palette_last);
|
||||
_segment_index_palette_last = _segment_index;
|
||||
|
||||
byte paletteIndex = SEGMENT.palette;
|
||||
if ((SEGMENT.mode >= FX_MODE_METEOR) && SEGMENT.palette == 0) paletteIndex = 4;
|
||||
|
||||
switch (paletteIndex)
|
||||
{
|
||||
case 0: {//default palette. Differs depending on effect
|
||||
switch (SEGMENT.mode)
|
||||
{
|
||||
case FX_MODE_FIRE_2012 : targetPalette = gGradientPalettes[22]; break;//heat palette
|
||||
case FX_MODE_COLORWAVES : targetPalette = gGradientPalettes[13]; break;//landscape 33
|
||||
case FX_MODE_FILLNOISE8 : targetPalette = OceanColors_p; break;
|
||||
case FX_MODE_NOISE16_1 : targetPalette = gGradientPalettes[17]; break;//Drywet
|
||||
case FX_MODE_NOISE16_2 : targetPalette = gGradientPalettes[30]; break;//Blue cyan yellow
|
||||
case FX_MODE_NOISE16_3 : targetPalette = gGradientPalettes[22]; break;//heat palette
|
||||
case FX_MODE_NOISE16_4 : targetPalette = gGradientPalettes[13]; break;//landscape 33
|
||||
|
||||
default: targetPalette = PartyColors_p; break;//palette, bpm
|
||||
}
|
||||
break;}
|
||||
case 1: {//periodically replace palette with a random one. Doesn't work with multiple FastLED segments
|
||||
if (!singleSegmentMode)
|
||||
{
|
||||
targetPalette = PartyColors_p; break; //fallback
|
||||
}
|
||||
if (millis() - _lastPaletteChange > 1000 + ((uint32_t)(255-SEGMENT.intensity))*100)
|
||||
{
|
||||
targetPalette = CRGBPalette16(
|
||||
CHSV(random8(), 255, random8(128, 255)),
|
||||
CHSV(random8(), 255, random8(128, 255)),
|
||||
CHSV(random8(), 192, random8(128, 255)),
|
||||
CHSV(random8(), 255, random8(128, 255)));
|
||||
_lastPaletteChange = millis();
|
||||
} break;}
|
||||
case 2: {//primary color only
|
||||
CRGB prim = fastled_from_col(SEGMENT.colors[0]);
|
||||
targetPalette = CRGBPalette16(prim); break;}
|
||||
case 3: {//based on primary
|
||||
//considering performance implications
|
||||
CRGB prim = fastled_from_col(SEGMENT.colors[0]);
|
||||
CHSV prim_hsv = rgb2hsv_approximate(prim);
|
||||
targetPalette = CRGBPalette16(
|
||||
CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v), //color itself
|
||||
CHSV(prim_hsv.h, max(prim_hsv.s - 50,0), prim_hsv.v), //less saturated
|
||||
CHSV(prim_hsv.h, prim_hsv.s, max(prim_hsv.v - 50,0)), //darker
|
||||
CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v)); //color itself
|
||||
break;}
|
||||
case 4: {//primary + secondary
|
||||
CRGB prim = fastled_from_col(SEGMENT.colors[0]);
|
||||
CRGB sec = fastled_from_col(SEGMENT.colors[1]);
|
||||
targetPalette = CRGBPalette16(sec,prim); break;}
|
||||
case 5: {//based on primary + secondary
|
||||
CRGB prim = fastled_from_col(SEGMENT.colors[0]);
|
||||
CRGB sec = fastled_from_col(SEGMENT.colors[1]);
|
||||
targetPalette = CRGBPalette16(sec,prim,CRGB::White); break;}
|
||||
case 6: //Party colors
|
||||
targetPalette = PartyColors_p; break;
|
||||
case 7: //Cloud colors
|
||||
targetPalette = CloudColors_p; break;
|
||||
case 8: //Lava colors
|
||||
targetPalette = LavaColors_p; break;
|
||||
case 9: //Ocean colors
|
||||
targetPalette = OceanColors_p; break;
|
||||
case 10: //Forest colors
|
||||
targetPalette = ForestColors_p; break;
|
||||
case 11: //Rainbow colors
|
||||
targetPalette = RainbowColors_p; break;
|
||||
case 12: //Rainbow stripe colors
|
||||
targetPalette = RainbowStripeColors_p; break;
|
||||
default: //progmem palettes
|
||||
targetPalette = gGradientPalettes[constrain(SEGMENT.palette -13, 0, gGradientPaletteCount -1)];
|
||||
}
|
||||
|
||||
if (singleSegmentMode && paletteFade) //only blend if just one segment uses FastLED mode
|
||||
{
|
||||
nblendPaletteTowardPalette(currentPalette, targetPalette, 48);
|
||||
} else
|
||||
{
|
||||
currentPalette = targetPalette;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri)
|
||||
{
|
||||
if (SEGMENT.palette == 0 && mcol < 3) return SEGMENT.colors[mcol]; //WS2812FX default
|
||||
uint8_t paletteIndex = i;
|
||||
if (mapping) paletteIndex = map(i,SEGMENT.start,SEGMENT.stop,0,255);
|
||||
if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
||||
CRGB fastled_col;
|
||||
fastled_col = ColorFromPalette( currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND);
|
||||
return fastled_col.r*65536 + fastled_col.g*256 + fastled_col.b;
|
||||
}
|
||||
124
wled00/__vm/.wled00.vsarduino.h
Normal file
124
wled00/__vm/.wled00.vsarduino.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
Editor: https://www.visualmicro.com/
|
||||
This file is for intellisense purpose only.
|
||||
Visual micro (and the arduino ide) ignore this code during compilation. This code is automatically maintained by visualmicro, manual changes to this file will be overwritten
|
||||
The contents of the _vm sub folder can be deleted prior to publishing a project
|
||||
All non-arduino files created by visual micro and all visual studio project or solution files can be freely deleted and are not required to compile a sketch (do not delete your own code!).
|
||||
Note: debugger breakpoints are stored in '.sln' or '.asln' files, knowledge of last uploaded breakpoints is stored in the upload.vmps.xml file. Both files are required to continue a previous debug session without needing to compile and upload again
|
||||
|
||||
Hardware: ESP32 Dev Module, Platform=esp32, Package=esp32
|
||||
*/
|
||||
|
||||
#if defined(_VMICRO_INTELLISENSE)
|
||||
|
||||
#ifndef _VSARDUINO_H_
|
||||
#define _VSARDUINO_H_
|
||||
#define __ESP32_esp32__
|
||||
#define __ESP32_ESP32__
|
||||
#define ESP_PLATFORM
|
||||
#define HAVE_CONFIG_H
|
||||
#define GCC_NOT_5_2_0 0
|
||||
#define WITH_POSIX
|
||||
#define F_CPU 240000000L
|
||||
#define ARDUINO 108011
|
||||
#define ARDUINO_ESP32_DEV
|
||||
#define ARDUINO_ARCH_ESP32
|
||||
#define ESP32
|
||||
#define CORE_DEBUG_LEVEL 0
|
||||
#define __cplusplus 201103L
|
||||
|
||||
#define _Pragma(x)
|
||||
#undef __cplusplus
|
||||
#define __cplusplus 201103L
|
||||
|
||||
#define __STDC__
|
||||
#define __ARM__
|
||||
#define __arm__
|
||||
#define __inline__
|
||||
#define __asm__(...)
|
||||
#define __extension__
|
||||
#define __ATTR_PURE__
|
||||
#define __ATTR_CONST__
|
||||
#define __volatile__
|
||||
|
||||
#define __ASM
|
||||
#define __INLINE
|
||||
#define __attribute__(noinline)
|
||||
|
||||
//#define _STD_BEGIN
|
||||
//#define EMIT
|
||||
#define WARNING
|
||||
#define _Lockit
|
||||
#define __CLR_OR_THIS_CALL
|
||||
#define C4005
|
||||
#define _NEW
|
||||
|
||||
typedef bool _Bool;
|
||||
typedef int _read;
|
||||
typedef int _seek;
|
||||
typedef int _write;
|
||||
typedef int _close;
|
||||
typedef int __cleanup;
|
||||
|
||||
//#define inline
|
||||
|
||||
#define __builtin_clz
|
||||
#define __builtin_clzl
|
||||
#define __builtin_clzll
|
||||
#define __builtin_labs
|
||||
#define __builtin_va_list
|
||||
typedef int __gnuc_va_list;
|
||||
|
||||
#define __ATOMIC_ACQ_REL
|
||||
|
||||
#define __CHAR_BIT__
|
||||
#define _EXFUN()
|
||||
|
||||
typedef unsigned char byte;
|
||||
extern "C" void __cxa_pure_virtual() {;}
|
||||
|
||||
typedef long __INTPTR_TYPE__ ;
|
||||
typedef long __UINTPTR_TYPE__ ;
|
||||
typedef long __SIZE_TYPE__ ;
|
||||
typedef long __PTRDIFF_TYPE__;
|
||||
|
||||
typedef long pthread_t;
|
||||
typedef long pthread_key_t;
|
||||
typedef long pthread_once_t;
|
||||
typedef long pthread_mutex_t;
|
||||
typedef long pthread_mutex_t;
|
||||
typedef long pthread_cond_t;
|
||||
|
||||
|
||||
|
||||
#include "arduino.h"
|
||||
#include <pins_arduino.h>
|
||||
|
||||
#define interrupts() sei()
|
||||
#define noInterrupts() cli()
|
||||
|
||||
#define ESP_LOGI(tag, ...)
|
||||
|
||||
#include "wled00.ino"
|
||||
#include "wled01_eeprom.ino"
|
||||
#include "wled02_xml.ino"
|
||||
#include "wled03_set.ino"
|
||||
#include "wled04_file.ino"
|
||||
#include "wled05_init.ino"
|
||||
#include "wled06_usermod.ino"
|
||||
#include "wled07_notify.ino"
|
||||
#include "wled08_led.ino"
|
||||
#include "wled09_button.ino"
|
||||
#include "wled10_ntp.ino"
|
||||
#include "wled11_ol.ino"
|
||||
#include "wled12_alexa.ino"
|
||||
#include "wled13_cronixie.ino"
|
||||
#include "wled14_colors.ino"
|
||||
#include "wled15_hue.ino"
|
||||
#include "wled16_blynk.ino"
|
||||
#include "wled17_mqtt.ino"
|
||||
#include "wled18_server.ino"
|
||||
#include "wled19_json.ino"
|
||||
#include "wled20_ir.ino"
|
||||
#endif
|
||||
#endif
|
||||
12
wled00/__vm/Compile.vmps.xml
Normal file
12
wled00/__vm/Compile.vmps.xml
Normal file
File diff suppressed because one or more lines are too long
9
wled00/__vm/Configuration.Release.vmps.xml
Normal file
9
wled00/__vm/Configuration.Release.vmps.xml
Normal file
File diff suppressed because one or more lines are too long
97
wled00/alexa.cpp
Normal file
97
wled00/alexa.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Alexa Voice On/Off/Brightness/Color Control. Emulates a Philips Hue bridge to Alexa.
|
||||
*
|
||||
* This was put together from these two excellent projects:
|
||||
* https://github.com/kakopappa/arduino-esp8266-alexa-wemo-switch
|
||||
* https://github.com/probonopd/ESP8266HueEmulator
|
||||
*/
|
||||
#include "src/dependencies/espalexa/EspalexaDevice.h"
|
||||
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
void onAlexaChange(EspalexaDevice* dev);
|
||||
|
||||
void alexaInit()
|
||||
{
|
||||
if (alexaEnabled && WLED_CONNECTED)
|
||||
{
|
||||
if (espalexaDevice == nullptr) //only init once
|
||||
{
|
||||
espalexaDevice = new EspalexaDevice(alexaInvocationName, onAlexaChange, EspalexaDeviceType::extendedcolor);
|
||||
espalexa.addDevice(espalexaDevice);
|
||||
espalexa.begin(&server);
|
||||
} else {
|
||||
espalexaDevice->setName(alexaInvocationName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleAlexa()
|
||||
{
|
||||
if (!alexaEnabled || !WLED_CONNECTED) return;
|
||||
espalexa.loop();
|
||||
}
|
||||
|
||||
void onAlexaChange(EspalexaDevice* dev)
|
||||
{
|
||||
EspalexaDeviceProperty m = espalexaDevice->getLastChangedProperty();
|
||||
|
||||
if (m == EspalexaDeviceProperty::on)
|
||||
{
|
||||
if (!macroAlexaOn)
|
||||
{
|
||||
if (bri == 0)
|
||||
{
|
||||
bri = briLast;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_ALEXA);
|
||||
}
|
||||
} else applyMacro(macroAlexaOn);
|
||||
} else if (m == EspalexaDeviceProperty::off)
|
||||
{
|
||||
if (!macroAlexaOff)
|
||||
{
|
||||
if (bri > 0)
|
||||
{
|
||||
briLast = bri;
|
||||
bri = 0;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_ALEXA);
|
||||
}
|
||||
} else applyMacro(macroAlexaOff);
|
||||
} else if (m == EspalexaDeviceProperty::bri)
|
||||
{
|
||||
bri = espalexaDevice->getValue();
|
||||
colorUpdated(NOTIFIER_CALL_MODE_ALEXA);
|
||||
} else //color
|
||||
{
|
||||
if (espalexaDevice->getColorMode() == EspalexaColorMode::ct) //shade of white
|
||||
{
|
||||
uint16_t ct = espalexaDevice->getCt();
|
||||
if (useRGBW)
|
||||
{
|
||||
switch (ct) { //these values empirically look good on RGBW
|
||||
case 199: col[0]=255; col[1]=255; col[2]=255; col[3]=255; break;
|
||||
case 234: col[0]=127; col[1]=127; col[2]=127; col[3]=255; break;
|
||||
case 284: col[0]= 0; col[1]= 0; col[2]= 0; col[3]=255; break;
|
||||
case 350: col[0]=130; col[1]= 90; col[2]= 0; col[3]=255; break;
|
||||
case 383: col[0]=255; col[1]=153; col[2]= 0; col[3]=255; break;
|
||||
}
|
||||
} else {
|
||||
colorCTtoRGB(ct, col);
|
||||
}
|
||||
} else {
|
||||
uint32_t color = espalexaDevice->getRGB();
|
||||
|
||||
col[0] = ((color >> 16) & 0xFF);
|
||||
col[1] = ((color >> 8) & 0xFF);
|
||||
col[2] = ( color & 0xFF);
|
||||
}
|
||||
colorUpdated(NOTIFIER_CALL_MODE_ALEXA);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
void alexaInit(){}
|
||||
void handleAlexa(){}
|
||||
#endif
|
||||
@@ -1,3 +1,6 @@
|
||||
#include "wled.h"
|
||||
#include "src/dependencies/blynk/Blynk/BlynkHandlers.h"
|
||||
|
||||
/*
|
||||
* Remote light control with the free Blynk app
|
||||
*/
|
||||
@@ -8,7 +11,7 @@ byte blSat = 255;
|
||||
void initBlynk(const char* auth)
|
||||
{
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
if (WiFi.status() != WL_CONNECTED) return;
|
||||
if (!WLED_CONNECTED) return;
|
||||
blynkEnabled = (auth[0] != 0);
|
||||
if (blynkEnabled) Blynk.config(auth);
|
||||
#endif
|
||||
@@ -17,7 +20,7 @@ void initBlynk(const char* auth)
|
||||
void handleBlynk()
|
||||
{
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
if (WiFi.status() == WL_CONNECTED && blynkEnabled)
|
||||
if (WLED_CONNECTED && blynkEnabled)
|
||||
Blynk.run();
|
||||
#endif
|
||||
}
|
||||
@@ -25,7 +28,7 @@ void handleBlynk()
|
||||
void updateBlynk()
|
||||
{
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
if (onlyAP) return;
|
||||
if (!WLED_CONNECTED) return;
|
||||
Blynk.virtualWrite(V0, bri);
|
||||
//we need a RGB -> HSB convert here
|
||||
Blynk.virtualWrite(V3, bri? 1:0);
|
||||
@@ -41,49 +44,50 @@ void updateBlynk()
|
||||
BLYNK_WRITE(V0)
|
||||
{
|
||||
bri = param.asInt();//bri
|
||||
colorUpdated(9);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BLYNK);
|
||||
}
|
||||
|
||||
BLYNK_WRITE(V1)
|
||||
{
|
||||
blHue = param.asInt();//hue
|
||||
colorHStoRGB(blHue*10,blSat,(false)? colSec:col);
|
||||
colorUpdated(9);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BLYNK);
|
||||
}
|
||||
|
||||
BLYNK_WRITE(V2)
|
||||
{
|
||||
blSat = param.asInt();//sat
|
||||
colorHStoRGB(blHue*10,blSat,(false)? colSec:col);
|
||||
colorUpdated(9);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BLYNK);
|
||||
}
|
||||
|
||||
BLYNK_WRITE(V3)
|
||||
{
|
||||
handleSet((param.asInt()>0)?"win&T=1&IN":"win&T=0&IN");//power
|
||||
bool on = (param.asInt()>0);
|
||||
if (!on != !bri) {toggleOnOff(); colorUpdated(NOTIFIER_CALL_MODE_BLYNK);}
|
||||
}
|
||||
|
||||
BLYNK_WRITE(V4)
|
||||
{
|
||||
effectCurrent = param.asInt()-1;//fx
|
||||
colorUpdated(9);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BLYNK);
|
||||
}
|
||||
|
||||
BLYNK_WRITE(V5)
|
||||
{
|
||||
effectSpeed = param.asInt();//sx
|
||||
colorUpdated(9);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BLYNK);
|
||||
}
|
||||
|
||||
BLYNK_WRITE(V6)
|
||||
{
|
||||
effectIntensity = param.asInt();//ix
|
||||
colorUpdated(9);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BLYNK);
|
||||
}
|
||||
|
||||
BLYNK_WRITE(V7)
|
||||
{
|
||||
handleSet((param.asInt()>0)?"win&ND&IN":"win&NL=0&IN");//nl
|
||||
nightlightActive = (param.asInt()>0);
|
||||
}
|
||||
|
||||
BLYNK_WRITE(V8)
|
||||
121
wled00/button.cpp
Normal file
121
wled00/button.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Physical IO
|
||||
*/
|
||||
|
||||
void shortPressAction()
|
||||
{
|
||||
if (!macroButton)
|
||||
{
|
||||
toggleOnOff();
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
} else {
|
||||
applyMacro(macroButton);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handleButton()
|
||||
{
|
||||
#ifdef BTNPIN
|
||||
if (!buttonEnabled) return;
|
||||
|
||||
if (digitalRead(BTNPIN) == LOW) //pressed
|
||||
{
|
||||
if (!buttonPressedBefore) buttonPressedTime = millis();
|
||||
buttonPressedBefore = true;
|
||||
|
||||
if (millis() - buttonPressedTime > 600) //long press
|
||||
{
|
||||
if (!buttonLongPressed)
|
||||
{
|
||||
if (macroLongPress) {applyMacro(macroLongPress);}
|
||||
else _setRandomColor(false,true);
|
||||
|
||||
buttonLongPressed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (digitalRead(BTNPIN) == HIGH && buttonPressedBefore) //released
|
||||
{
|
||||
long dur = millis() - buttonPressedTime;
|
||||
if (dur < 50) {buttonPressedBefore = false; return;} //too short "press", debounce
|
||||
bool doublePress = buttonWaitTime;
|
||||
buttonWaitTime = 0;
|
||||
|
||||
if (dur > 6000) //long press
|
||||
{
|
||||
WLED::instance().initAP(true);
|
||||
}
|
||||
else if (!buttonLongPressed) { //short press
|
||||
if (macroDoublePress)
|
||||
{
|
||||
if (doublePress) applyMacro(macroDoublePress);
|
||||
else buttonWaitTime = millis();
|
||||
} else shortPressAction();
|
||||
}
|
||||
buttonPressedBefore = false;
|
||||
buttonLongPressed = false;
|
||||
}
|
||||
|
||||
if (buttonWaitTime && millis() - buttonWaitTime > 450 && !buttonPressedBefore)
|
||||
{
|
||||
buttonWaitTime = 0;
|
||||
shortPressAction();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void handleIO()
|
||||
{
|
||||
handleButton();
|
||||
|
||||
//set relay when LEDs turn on
|
||||
if (strip.getBrightness())
|
||||
{
|
||||
lastOnTime = millis();
|
||||
if (offMode)
|
||||
{
|
||||
#if RLYPIN >= 0
|
||||
digitalWrite(RLYPIN, RLYMDE);
|
||||
#endif
|
||||
offMode = false;
|
||||
}
|
||||
} else if (millis() - lastOnTime > 600)
|
||||
{
|
||||
#if RLYPIN >= 0
|
||||
if (!offMode) digitalWrite(RLYPIN, !RLYMDE);
|
||||
#endif
|
||||
offMode = true;
|
||||
}
|
||||
|
||||
#if AUXPIN >= 0
|
||||
//output
|
||||
if (auxActive || auxActiveBefore)
|
||||
{
|
||||
if (!auxActiveBefore)
|
||||
{
|
||||
auxActiveBefore = true;
|
||||
switch (auxTriggeredState)
|
||||
{
|
||||
case 0: pinMode(AUXPIN, INPUT); break;
|
||||
case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break;
|
||||
case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break;
|
||||
}
|
||||
auxStartTime = millis();
|
||||
}
|
||||
if ((millis() - auxStartTime > auxTime*1000 && auxTime != 255) || !auxActive)
|
||||
{
|
||||
auxActive = false;
|
||||
auxActiveBefore = false;
|
||||
switch (auxDefaultState)
|
||||
{
|
||||
case 0: pinMode(AUXPIN, INPUT); break;
|
||||
case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break;
|
||||
case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,13 +1,45 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Color conversion methods
|
||||
*/
|
||||
|
||||
void colorFromUint32(uint32_t in)
|
||||
void colorFromUint32(uint32_t in, bool secondary)
|
||||
{
|
||||
col[3] = in >> 24 & 0xFF;
|
||||
col[0] = in >> 16 & 0xFF;
|
||||
col[1] = in >> 8 & 0xFF;
|
||||
col[2] = in & 0xFF;
|
||||
if (secondary) {
|
||||
colSec[3] = in >> 24 & 0xFF;
|
||||
colSec[0] = in >> 16 & 0xFF;
|
||||
colSec[1] = in >> 8 & 0xFF;
|
||||
colSec[2] = in & 0xFF;
|
||||
} else {
|
||||
col[3] = in >> 24 & 0xFF;
|
||||
col[0] = in >> 16 & 0xFF;
|
||||
col[1] = in >> 8 & 0xFF;
|
||||
col[2] = in & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
//load a color without affecting the white channel
|
||||
void colorFromUint24(uint32_t in, bool secondary)
|
||||
{
|
||||
if (secondary) {
|
||||
colSec[0] = in >> 16 & 0xFF;
|
||||
colSec[1] = in >> 8 & 0xFF;
|
||||
colSec[2] = in & 0xFF;
|
||||
} else {
|
||||
col[0] = in >> 16 & 0xFF;
|
||||
col[1] = in >> 8 & 0xFF;
|
||||
col[2] = in & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
//relatively change white brightness, minumum A=5
|
||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary)
|
||||
{
|
||||
int16_t new_val = (int16_t) col[3] + amount;
|
||||
if (new_val > 0xFF) new_val = 0xFF;
|
||||
else if (new_val < lowerBoundary) new_val = lowerBoundary;
|
||||
col[3] = new_val;
|
||||
}
|
||||
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
|
||||
@@ -27,9 +59,9 @@ void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
|
||||
case 4: rgb[0]=t,rgb[1]=p,rgb[2]=255;break;
|
||||
case 5: rgb[0]=255,rgb[1]=p,rgb[2]=q;
|
||||
}
|
||||
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb
|
||||
{
|
||||
//this is only an approximation using WS2812B with gamma correction enabled
|
||||
@@ -50,8 +82,10 @@ void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb
|
||||
} else {
|
||||
rgb[0]=237;rgb[1]=255;rgb[2]=239;//150
|
||||
}
|
||||
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
|
||||
{
|
||||
float z = 1.0f - x - y;
|
||||
@@ -106,6 +140,7 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www
|
||||
rgb[0] = 255.0*r;
|
||||
rgb[1] = 255.0*g;
|
||||
rgb[2] = 255.0*b;
|
||||
if (useRGBW) colorRGBtoRGBW(col);
|
||||
}
|
||||
|
||||
void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
|
||||
@@ -116,7 +151,8 @@ void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.develo
|
||||
xy[0] = X / (X + Y + Z);
|
||||
xy[1] = Y / (X + Y + Z);
|
||||
}
|
||||
#endif
|
||||
#endif // WLED_DISABLE_HUESYNC
|
||||
|
||||
|
||||
void colorFromDecOrHexString(byte* rgb, char* in)
|
||||
{
|
||||
@@ -150,11 +186,11 @@ float maxf (float v, float w)
|
||||
return v;
|
||||
}
|
||||
|
||||
void colorRGBtoRGBW(byte* rgb) //rgb to rgbw (http://codewelt.com/rgbw)
|
||||
void colorRGBtoRGBW(byte* rgb) //rgb to rgbw (http://codewelt.com/rgbw). (RGBW_MODE_LEGACY)
|
||||
{
|
||||
float low = minf(rgb[0],minf(rgb[1],rgb[2]));
|
||||
float high = maxf(rgb[0],maxf(rgb[1],rgb[2]));
|
||||
if (high < 0.1f) return;
|
||||
float sat = 255.0f * ((high - low) / high);
|
||||
float sat = 100.0f * ((high - low) / high);; // maximum saturation is 100 (corrected from 255)
|
||||
rgb[3] = (byte)((255.0f - sat) / 255.0f * (rgb[0] + rgb[1] + rgb[2]) / 3);
|
||||
}
|
||||
107
wled00/const.h
Normal file
107
wled00/const.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#ifndef WLED_CONST_H
|
||||
#define WLED_CONST_H
|
||||
|
||||
/*
|
||||
* Readability defines and their associated numerical values + compile-time constants
|
||||
*/
|
||||
|
||||
//Defaults
|
||||
#define DEFAULT_CLIENT_SSID "Your_Network"
|
||||
#define DEFAULT_AP_PASS "wled1234"
|
||||
#define DEFAULT_OTA_PASS "wledota"
|
||||
|
||||
//Access point behavior
|
||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||
#define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost)
|
||||
#define AP_BEHAVIOR_ALWAYS 2 //Always open
|
||||
#define AP_BEHAVIOR_BUTTON_ONLY 3 //Only when button pressed for 6 sec
|
||||
|
||||
//Notifier callMode
|
||||
#define NOTIFIER_CALL_MODE_INIT 0 //no updates on init, can be used to disable updates
|
||||
#define NOTIFIER_CALL_MODE_DIRECT_CHANGE 1
|
||||
#define NOTIFIER_CALL_MODE_BUTTON 2
|
||||
#define NOTIFIER_CALL_MODE_NOTIFICATION 3
|
||||
#define NOTIFIER_CALL_MODE_NIGHTLIGHT 4
|
||||
#define NOTIFIER_CALL_MODE_NO_NOTIFY 5
|
||||
#define NOTIFIER_CALL_MODE_FX_CHANGED 6 //no longer used
|
||||
#define NOTIFIER_CALL_MODE_HUE 7
|
||||
#define NOTIFIER_CALL_MODE_PRESET_CYCLE 8
|
||||
#define NOTIFIER_CALL_MODE_BLYNK 9
|
||||
#define NOTIFIER_CALL_MODE_ALEXA 10
|
||||
|
||||
//RGB to RGBW conversion mode
|
||||
#define RGBW_MODE_MANUAL_ONLY 0 //No automatic white channel calculation. Manual white channel slider
|
||||
#define RGBW_MODE_AUTO_BRIGHTER 1 //New algorithm. Adds as much white as the darkest RGBW channel
|
||||
#define RGBW_MODE_AUTO_ACCURATE 2 //New algorithm. Adds as much white as the darkest RGBW channel and subtracts this amount from each RGB channel
|
||||
#define RGBW_MODE_DUAL 3 //Manual slider + auto calculation. Automatically calculates only if manual slider is set to off (0)
|
||||
#define RGBW_MODE_LEGACY 4 //Old floating algorithm. Too slow for realtime and palette support
|
||||
|
||||
//realtime modes
|
||||
#define REALTIME_MODE_INACTIVE 0
|
||||
#define REALTIME_MODE_GENERIC 1
|
||||
#define REALTIME_MODE_UDP 2
|
||||
#define REALTIME_MODE_HYPERION 3
|
||||
#define REALTIME_MODE_E131 4
|
||||
#define REALTIME_MODE_ADALIGHT 5
|
||||
#define REALTIME_MODE_ARTNET 6
|
||||
|
||||
//realtime override modes
|
||||
#define REALTIME_OVERRIDE_NONE 0
|
||||
#define REALTIME_OVERRIDE_ONCE 1
|
||||
#define REALTIME_OVERRIDE_ALWAYS 2
|
||||
|
||||
//E1.31 DMX modes
|
||||
#define DMX_MODE_DISABLED 0 //not used
|
||||
#define DMX_MODE_SINGLE_RGB 1 //all LEDs same RGB color (3 channels)
|
||||
#define DMX_MODE_SINGLE_DRGB 2 //all LEDs same RGB color and master dimmer (4 channels)
|
||||
#define DMX_MODE_EFFECT 3 //trigger standalone effects of WLED (11 channels)
|
||||
#define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels)
|
||||
#define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels)
|
||||
|
||||
//Light capability byte (unused)
|
||||
#define TYPE_NONE 0 //light is not configured
|
||||
#define TYPE_RESERVED 1 //unused. Might indicate a "virtual" light
|
||||
#define TYPE_WS2812_RGB 2
|
||||
#define TYPE_SK6812_RGBW 3
|
||||
#define TYPE_WS2812_WWA 4 //amber + warm + cold white
|
||||
#define TYPE_WS2801 5
|
||||
#define TYPE_ANALOG_1CH 6 //single channel PWM. Uses value of brightest RGBW channel
|
||||
#define TYPE_ANALOG_2CH 7 //analog WW + CW
|
||||
#define TYPE_ANALOG_3CH 8 //analog RGB
|
||||
#define TYPE_ANALOG_4CH 9 //analog RGBW
|
||||
#define TYPE_ANALOG_5CH 10 //analog RGB + WW + CW
|
||||
#define TYPE_APA102 11
|
||||
#define TYPE_LPD8806 12
|
||||
|
||||
//Hue error codes
|
||||
#define HUE_ERROR_INACTIVE 0
|
||||
#define HUE_ERROR_UNAUTHORIZED 1
|
||||
#define HUE_ERROR_LIGHTID 3
|
||||
#define HUE_ERROR_PUSHLINK 101
|
||||
#define HUE_ERROR_JSON_PARSING 250
|
||||
#define HUE_ERROR_TIMEOUT 251
|
||||
#define HUE_ERROR_ACTIVE 255
|
||||
|
||||
//Segment option byte bits
|
||||
#define SEG_OPTION_SELECTED 0
|
||||
#define SEG_OPTION_REVERSED 1
|
||||
#define SEG_OPTION_ON 2
|
||||
#define SEG_OPTION_TRANSITIONAL 7
|
||||
|
||||
//EEPROM size
|
||||
#define EEPSIZE 2560 //Maximum is 4096
|
||||
|
||||
#define NTP_PACKET_SIZE 48
|
||||
|
||||
// maximum number of LEDs - MAX_LEDS is coming from the JSON response getting too big, MAX_LEDS_DMA will become a timing issue
|
||||
#define MAX_LEDS 1500
|
||||
#define MAX_LEDS_DMA 500
|
||||
|
||||
// string temp buffer (now stored in stack locally)
|
||||
#define OMAX 2048
|
||||
|
||||
#define E131_MAX_UNIVERSE_COUNT 9
|
||||
|
||||
#define ABL_MILLIAMPS_DEFAULT 850; // auto lower brightness to stay close to milliampere limit
|
||||
|
||||
#endif
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
100
wled00/data/jsontest.htm
Normal file
100
wled00/data/jsontest.htm
Normal file
@@ -0,0 +1,100 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>JSON client</title>
|
||||
<style>
|
||||
:root {
|
||||
--bCol:#333;--cCol:#222;--dCol:#666;--tCol:#fff;
|
||||
}
|
||||
body {
|
||||
font-family: Verdana, sans-serif;
|
||||
text-align: center;
|
||||
background: var(--cCol);
|
||||
color: var(--tCol);
|
||||
margin: 20px;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
button {
|
||||
background: var(--cCol);
|
||||
color: var(--tCol);
|
||||
border: 0.3ch solid var(--cCol);
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
margin: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
input {
|
||||
background: var(--cCol);
|
||||
color: var(--tCol);
|
||||
border: 0.5ch solid var(--cCol);
|
||||
width: 100%;
|
||||
}
|
||||
h1{
|
||||
margin: 0px;
|
||||
font-size: 20px;
|
||||
}
|
||||
h2{
|
||||
font-size: 16px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
form{
|
||||
background: var(--bCol);
|
||||
width: 500px;
|
||||
padding: 20px;
|
||||
-webkit-border-radius: 10px;
|
||||
-moz-border-radius: 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
textarea{
|
||||
background: var(--cCol);
|
||||
color: var(--tCol);
|
||||
padding-top: 10px;
|
||||
width: 100%;
|
||||
font-family: monaco,monospace;
|
||||
font-size: 12px;
|
||||
-webkit-border-radius: 10px;
|
||||
-moz-border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form name="cf">
|
||||
<h1>JSON API test tool</h1>
|
||||
<h2>URL:</h2>
|
||||
<input name="cu" type="text" size="60" value="http://192.168.4.1/json">
|
||||
<div id="buttons">
|
||||
<button type="button" onclick="rq('GET')">GET</button>
|
||||
<button type="button" onclick="rq('POST')">POST</button>
|
||||
</div>
|
||||
<h2>Body:</h2>
|
||||
<textarea name="bd" rows="8" cols="100"></textarea>
|
||||
<h2>Response:</h2>
|
||||
<textarea name="rsp" rows="25" cols="100"></textarea>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<script>
|
||||
function rq(cm)
|
||||
{
|
||||
var h = new XMLHttpRequest();
|
||||
h.open(cm, document.cf.cu.value, true);
|
||||
h.onreadystatechange = function()
|
||||
{
|
||||
if(h.readyState == 4)
|
||||
{
|
||||
if(h.status==200)
|
||||
{
|
||||
document.cf.rsp.value="Bad JSON: "+h.responseText
|
||||
document.cf.rsp.value=JSON.stringify(JSON.parse(h.responseText), null, '\t');
|
||||
}
|
||||
else
|
||||
{
|
||||
document.cf.rsp.value="Error "+h.status+"\r\n\n"+h.responseText;
|
||||
}
|
||||
}
|
||||
}
|
||||
h.send(document.cf.bd.value);
|
||||
}
|
||||
</script>
|
||||
64
wled00/data/liveview.htm
Normal file
64
wled00/data/liveview.htm
Normal file
@@ -0,0 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<meta name="theme-color" content="#222222">
|
||||
<title>WLED Live Preview</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
#canv {
|
||||
background: black;
|
||||
filter: brightness(175%);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="canv" />
|
||||
<script>
|
||||
update();
|
||||
|
||||
var tmout = null;
|
||||
function update()
|
||||
{
|
||||
if (document.hidden) {
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 250);
|
||||
return;
|
||||
}
|
||||
fetch('/json/live')
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 2500);
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
.then(json => {
|
||||
var str = "linear-gradient(90deg,";
|
||||
var len = json.leds.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
var leddata = json.leds[i];
|
||||
if (leddata.length > 6) leddata = leddata.substring(2);
|
||||
str += "#" + leddata;
|
||||
if (i < len -1) str += ","
|
||||
}
|
||||
str += ")";
|
||||
document.getElementById("canv").style.background = str;
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 40);
|
||||
})
|
||||
.catch(function (error) {
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 2500);
|
||||
})
|
||||
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -23,7 +23,7 @@
|
||||
--tCol: #328CC1;
|
||||
--cFn: Verdana;
|
||||
}
|
||||
button {
|
||||
.bt {
|
||||
background: var(--bCol);
|
||||
color: var(--tCol);
|
||||
border: 0.3ch solid var(--bCol);
|
||||
@@ -34,6 +34,9 @@
|
||||
margin: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
input[type=file] {
|
||||
font-size: 16px;
|
||||
}
|
||||
body {
|
||||
font-family: var(--cFn), sans-serif;
|
||||
text-align: center;
|
||||
@@ -47,6 +50,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<h2>Sample message.</h2>
|
||||
Sample detail.
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
4
wled00/data/update.htm
Normal file
4
wled00/data/update.htm
Normal file
@@ -0,0 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head><meta content='width=device-width' name='viewport'><title>WLED Message</title><script>function B(){window.history.back()}</script>
|
||||
<style>:root{--aCol:#D9B310;--bCol:#0B3C5D;--cCol:#1D2731;--dCol:#328CC1;--sCol:#000;--tCol:#328CC1;--cFn:Verdana;}.bt{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:var(--cFn),sans-serif;text-align:center;background:var(--cCol);color:var(--tCol);line-height:200%}</style></head>
|
||||
<body><h2>WLED Software Update</h2>Installed version: 0.8.5-dev<br>Download the latest binary: <a href="https://github.com/Aircoookie/WLED/releases"><img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a><br><form method='POST' action='/update' enctype='multipart/form-data'><input type='file' class="bt" name='update' required><br><input type='submit' class="bt" value='Update!'></form><button type="button" class="bt" onclick="B()">Back</button></body></html>
|
||||
@@ -1,27 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content='width=device-width' name='viewport'>
|
||||
<meta name="theme-color" content="#333333">
|
||||
<title>WLED Setup</title>
|
||||
<style>
|
||||
:root {
|
||||
--aCol: #D9B310;
|
||||
--bCol: #0B3C5D;
|
||||
--cCol: #1D2731;
|
||||
--dCol: #328CC1;
|
||||
--sCol: #000;
|
||||
}
|
||||
body {
|
||||
font-family: Verdana, Helvetica, sans-serif;
|
||||
text-align: center;
|
||||
background: linear-gradient(var(--bCol),black);
|
||||
background-color: #333;
|
||||
margin: 0;
|
||||
background-attachment: fixed;
|
||||
color: var(--dCol);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
button {
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
margin: 10px;
|
||||
width: 230px;
|
||||
text-transform: uppercase;
|
||||
font-family: helvetica;
|
||||
font-size: 19px;
|
||||
background-color: #222;
|
||||
color: white;
|
||||
border: 0px solid white;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: var(--dCol);
|
||||
fill: #fff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -34,10 +43,12 @@
|
||||
<svg><use xlink:href="#lnr-smile"></use></svg>
|
||||
<h1>Welcome to WLED!</h1>
|
||||
<h3>Thank you for installing my application!</h3>
|
||||
Take a quick look at the <a href="https://github.com/Aircoookie/WLED/wiki" target="_blank">wiki</a>!<br>
|
||||
If you encounter a bug or have a question/feature suggestion, feel free to open a GitHub issue!<br><br>
|
||||
<b>Next steps:</b><br><br>
|
||||
Connect the module to your local WiFi <a href="/settings/wifi">here</a>!<br><br>
|
||||
<i>Just trying this out in AP mode?</i> <a href="/sliders">Here are the controls.</a><br>
|
||||
Connect the module to your local WiFi here!<br>
|
||||
<button onclick="window.location.href='/settings/wifi'">WiFi settings</button><br>
|
||||
<i>Just trying this out in AP mode?</i><br>
|
||||
<button onclick="window.location.href='/sliders'">To the controls!</button>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
67
wled00/dmx.cpp
Normal file
67
wled00/dmx.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Support for DMX via MAX485.
|
||||
* Change the output pin in src/dependencies/ESPDMX.cpp if needed.
|
||||
* Library from:
|
||||
* https://github.com/Rickgg/ESP-Dmx
|
||||
*/
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
#include "src/dependencies/dmx/ESPDMX.h"
|
||||
DMXESPSerial dmx;
|
||||
|
||||
void handleDMX()
|
||||
{
|
||||
// TODO: calculate brightness manually if no shutter channel is set
|
||||
|
||||
uint8_t brightness = strip.getBrightness();
|
||||
|
||||
for (int i = DMXStartLED; i < ledCount; i++) { // uses the amount of LEDs as fixture count
|
||||
|
||||
uint32_t in = strip.getPixelColor(i); // get the colors for the individual fixtures as suggested by Aircoookie in issue #462
|
||||
byte w = in >> 24 & 0xFF;
|
||||
byte r = in >> 16 & 0xFF;
|
||||
byte g = in >> 8 & 0xFF;
|
||||
byte b = in & 0xFF;
|
||||
|
||||
int DMXFixtureStart = DMXStart + (DMXGap * (i - DMXStartLED));
|
||||
for (int j = 0; j < DMXChannels; j++) {
|
||||
int DMXAddr = DMXFixtureStart + j;
|
||||
switch (DMXFixtureMap[j]) {
|
||||
case 0: // Set this channel to 0. Good way to tell strobe- and fade-functions to fuck right off.
|
||||
dmx.write(DMXAddr, 0);
|
||||
break;
|
||||
case 1: // Red
|
||||
dmx.write(DMXAddr, r);
|
||||
break;
|
||||
case 2: // Green
|
||||
dmx.write(DMXAddr, g);
|
||||
break;
|
||||
case 3: // Blue
|
||||
dmx.write(DMXAddr, b);
|
||||
break;
|
||||
case 4: // White
|
||||
dmx.write(DMXAddr, w);
|
||||
break;
|
||||
case 5: // Shutter channel. Controls the brightness.
|
||||
dmx.write(DMXAddr, brightness);
|
||||
break;
|
||||
case 6: // Sets this channel to 255. Like 0, but more wholesome.
|
||||
dmx.write(DMXAddr, 255);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dmx.update(); // update the DMX bus
|
||||
}
|
||||
|
||||
void initDMX() {
|
||||
dmx.init(512); // initialize with bus length
|
||||
}
|
||||
|
||||
#else
|
||||
void handleDMX() {}
|
||||
void initDMX() {}
|
||||
#endif
|
||||
167
wled00/e131.cpp
Normal file
167
wled00/e131.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* E1.31 handler
|
||||
*/
|
||||
|
||||
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
|
||||
//E1.31 protocol support
|
||||
|
||||
uint16_t uni = 0, dmxChannels = 0;
|
||||
uint8_t* e131_data = nullptr;
|
||||
uint8_t seq = 0, mde = REALTIME_MODE_E131;
|
||||
|
||||
if (isArtnet)
|
||||
{
|
||||
uni = p->art_universe;
|
||||
dmxChannels = htons(p->art_length);
|
||||
e131_data = p->art_data;
|
||||
seq = p->art_sequence_number;
|
||||
mde = REALTIME_MODE_ARTNET;
|
||||
} else {
|
||||
uni = htons(p->universe);
|
||||
dmxChannels = htons(p->property_value_count) -1;
|
||||
e131_data = p->property_values;
|
||||
seq = p->sequence_number;
|
||||
}
|
||||
|
||||
// only listen for universes we're handling & allocated memory
|
||||
if (uni >= (e131Universe + E131_MAX_UNIVERSE_COUNT)) return;
|
||||
|
||||
uint8_t previousUniverses = uni - e131Universe;
|
||||
uint16_t possibleLEDsInCurrentUniverse;
|
||||
|
||||
if (e131SkipOutOfSequence)
|
||||
if (seq < e131LastSequenceNumber[uni-e131Universe] && seq > 20 && e131LastSequenceNumber[uni-e131Universe] < 250){
|
||||
DEBUG_PRINT("skipping E1.31 frame (last seq=");
|
||||
DEBUG_PRINT(e131LastSequenceNumber[uni-e131Universe]);
|
||||
DEBUG_PRINT(", current seq=");
|
||||
DEBUG_PRINT(seq);
|
||||
DEBUG_PRINT(", universe=");
|
||||
DEBUG_PRINT(uni);
|
||||
DEBUG_PRINTLN(")");
|
||||
return;
|
||||
}
|
||||
e131LastSequenceNumber[uni-e131Universe] = seq;
|
||||
|
||||
// update status info
|
||||
realtimeIP = clientIP;
|
||||
byte wChannel = 0;
|
||||
|
||||
switch (DMXMode) {
|
||||
case DMX_MODE_DISABLED:
|
||||
return; // nothing to do
|
||||
break;
|
||||
|
||||
case DMX_MODE_SINGLE_RGB:
|
||||
if (uni != e131Universe) return;
|
||||
if (dmxChannels-DMXAddress+1 < 3) return;
|
||||
realtimeLock(realtimeTimeoutMs, mde);
|
||||
if (realtimeOverride) return;
|
||||
wChannel = (dmxChannels-DMXAddress+1 > 3) ? e131_data[DMXAddress+3] : 0;
|
||||
for (uint16_t i = 0; i < ledCount; i++)
|
||||
setRealtimePixel(i, e131_data[DMXAddress+0], e131_data[DMXAddress+1], e131_data[DMXAddress+2], wChannel);
|
||||
break;
|
||||
|
||||
case DMX_MODE_SINGLE_DRGB:
|
||||
if (uni != e131Universe) return;
|
||||
if (dmxChannels-DMXAddress+1 < 4) return;
|
||||
realtimeLock(realtimeTimeoutMs, mde);
|
||||
if (realtimeOverride) return;
|
||||
wChannel = (dmxChannels-DMXAddress+1 > 4) ? e131_data[DMXAddress+4] : 0;
|
||||
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
|
||||
DMXOldDimmer = e131_data[DMXAddress+0];
|
||||
bri = e131_data[DMXAddress+0];
|
||||
strip.setBrightness(bri);
|
||||
}
|
||||
for (uint16_t i = 0; i < ledCount; i++)
|
||||
setRealtimePixel(i, e131_data[DMXAddress+1], e131_data[DMXAddress+2], e131_data[DMXAddress+3], wChannel);
|
||||
break;
|
||||
|
||||
case DMX_MODE_EFFECT:
|
||||
if (uni != e131Universe) return;
|
||||
if (dmxChannels-DMXAddress+1 < 11) return;
|
||||
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
|
||||
DMXOldDimmer = e131_data[DMXAddress+0];
|
||||
bri = e131_data[DMXAddress+0];
|
||||
}
|
||||
if (e131_data[DMXAddress+1] < MODE_COUNT)
|
||||
effectCurrent = e131_data[DMXAddress+ 1];
|
||||
effectSpeed = e131_data[DMXAddress+ 2]; // flickers
|
||||
effectIntensity = e131_data[DMXAddress+ 3];
|
||||
effectPalette = e131_data[DMXAddress+ 4];
|
||||
col[0] = e131_data[DMXAddress+ 5];
|
||||
col[1] = e131_data[DMXAddress+ 6];
|
||||
col[2] = e131_data[DMXAddress+ 7];
|
||||
colSec[0] = e131_data[DMXAddress+ 8];
|
||||
colSec[1] = e131_data[DMXAddress+ 9];
|
||||
colSec[2] = e131_data[DMXAddress+10];
|
||||
if (dmxChannels-DMXAddress+1 > 11)
|
||||
{
|
||||
col[3] = e131_data[DMXAddress+11]; //white
|
||||
colSec[3] = e131_data[DMXAddress+12];
|
||||
}
|
||||
transitionDelayTemp = 0; // act fast
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); // don't send UDP
|
||||
return; // don't activate realtime live mode
|
||||
break;
|
||||
|
||||
case DMX_MODE_MULTIPLE_RGB:
|
||||
realtimeLock(realtimeTimeoutMs, mde);
|
||||
if (realtimeOverride) return;
|
||||
if (previousUniverses == 0) {
|
||||
// first universe of this fixture
|
||||
possibleLEDsInCurrentUniverse = (dmxChannels - DMXAddress + 1) / 3;
|
||||
for (uint16_t i = 0; i < ledCount; i++) {
|
||||
if (i >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s)
|
||||
setRealtimePixel(i, e131_data[DMXAddress+i*3+0], e131_data[DMXAddress+i*3+1], e131_data[DMXAddress+i*3+2], 0);
|
||||
}
|
||||
} else if (previousUniverses > 0 && uni < (e131Universe + E131_MAX_UNIVERSE_COUNT)) {
|
||||
// additional universe(s) of this fixture
|
||||
uint16_t numberOfLEDsInPreviousUniverses = ((512 - DMXAddress + 1) / 3); // first universe
|
||||
if (previousUniverses > 1) numberOfLEDsInPreviousUniverses += (512 / 3) * (previousUniverses - 1); // extended universe(s) before current
|
||||
possibleLEDsInCurrentUniverse = dmxChannels / 3;
|
||||
for (uint16_t i = numberOfLEDsInPreviousUniverses; i < ledCount; i++) {
|
||||
uint8_t j = i - numberOfLEDsInPreviousUniverses;
|
||||
if (j >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s)
|
||||
setRealtimePixel(i, e131_data[j*3+1], e131_data[j*3+2], e131_data[j*3+3], 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DMX_MODE_MULTIPLE_DRGB:
|
||||
realtimeLock(realtimeTimeoutMs, mde);
|
||||
if (realtimeOverride) return;
|
||||
if (previousUniverses == 0) {
|
||||
// first universe of this fixture
|
||||
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
|
||||
DMXOldDimmer = e131_data[DMXAddress+0];
|
||||
bri = e131_data[DMXAddress+0];
|
||||
strip.setBrightness(bri);
|
||||
}
|
||||
possibleLEDsInCurrentUniverse = (dmxChannels - DMXAddress) / 3;
|
||||
for (uint16_t i = 0; i < ledCount; i++) {
|
||||
if (i >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s)
|
||||
setRealtimePixel(i, e131_data[DMXAddress+i*3+1], e131_data[DMXAddress+i*3+2], e131_data[DMXAddress+i*3+3], 0);
|
||||
}
|
||||
} else if (previousUniverses > 0 && uni < (e131Universe + E131_MAX_UNIVERSE_COUNT)) {
|
||||
// additional universe(s) of this fixture
|
||||
uint16_t numberOfLEDsInPreviousUniverses = ((512 - DMXAddress + 1) / 3); // first universe
|
||||
if (previousUniverses > 1) numberOfLEDsInPreviousUniverses += (512 / 3) * (previousUniverses - 1); // extended universe(s) before current
|
||||
possibleLEDsInCurrentUniverse = dmxChannels / 3;
|
||||
for (uint16_t i = numberOfLEDsInPreviousUniverses; i < ledCount; i++) {
|
||||
uint8_t j = i - numberOfLEDsInPreviousUniverses;
|
||||
if (j >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s)
|
||||
setRealtimePixel(i, e131_data[j*3+1], e131_data[j*3+2], e131_data[j*3+3], 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_PRINTLN("unknown E1.31 DMX mode");
|
||||
return; // nothing to do
|
||||
break;
|
||||
}
|
||||
|
||||
e131NewData = true;
|
||||
}
|
||||
184
wled00/fcn_declare.h
Normal file
184
wled00/fcn_declare.h
Normal file
@@ -0,0 +1,184 @@
|
||||
#ifndef WLED_FCN_DECLARE_H
|
||||
#define WLED_FCN_DECLARE_H
|
||||
#include <Arduino.h>
|
||||
#include "src/dependencies/espalexa/EspalexaDevice.h"
|
||||
#include "src/dependencies/e131/ESPAsyncE131.h"
|
||||
|
||||
/*
|
||||
* All globally accessible functions are declared here
|
||||
*/
|
||||
|
||||
//alexa.cpp
|
||||
void onAlexaChange(EspalexaDevice* dev);
|
||||
void alexaInit();
|
||||
void handleAlexa();
|
||||
void onAlexaChange(EspalexaDevice* dev);
|
||||
|
||||
//blynk.cpp
|
||||
void initBlynk(const char* auth);
|
||||
void handleBlynk();
|
||||
void updateBlynk();
|
||||
|
||||
//button.cpp
|
||||
void shortPressAction();
|
||||
void handleButton();
|
||||
void handleIO();
|
||||
|
||||
//colors.cpp
|
||||
void colorFromUint32(uint32_t in, bool secondary = false);
|
||||
void colorFromUint24(uint32_t in, bool secondary = false);
|
||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
||||
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb
|
||||
|
||||
void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO
|
||||
void colorRGBtoXY(byte* rgb, float* xy); // only defined if huesync disabled TODO
|
||||
|
||||
void colorFromDecOrHexString(byte* rgb, char* in);
|
||||
void colorRGBtoRGBW(byte* rgb); //rgb to rgbw (http://codewelt.com/rgbw). (RGBW_MODE_LEGACY)
|
||||
|
||||
//dmx.cpp
|
||||
void initDMX();
|
||||
void handleDMX();
|
||||
|
||||
//e131.cpp
|
||||
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet);
|
||||
|
||||
//file.cpp
|
||||
bool handleFileRead(AsyncWebServerRequest*, String path);
|
||||
|
||||
//hue.cpp
|
||||
void handleHue();
|
||||
void reconnectHue();
|
||||
void onHueError(void* arg, AsyncClient* client, int8_t error);
|
||||
void onHueConnect(void* arg, AsyncClient* client);
|
||||
void sendHuePoll();
|
||||
void onHueData(void* arg, AsyncClient* client, void *data, size_t len);
|
||||
|
||||
//ir.cpp
|
||||
bool decodeIRCustom(uint32_t code);
|
||||
void relativeChange(byte* property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF);
|
||||
void changeEffectSpeed(int8_t amount);
|
||||
void changeEffectIntensity(int8_t amount);
|
||||
void decodeIR(uint32_t code);
|
||||
void decodeIR24(uint32_t code);
|
||||
void decodeIR24OLD(uint32_t code);
|
||||
void decodeIR24CT(uint32_t code);
|
||||
void decodeIR40(uint32_t code);
|
||||
void decodeIR44(uint32_t code);
|
||||
void decodeIR21(uint32_t code);
|
||||
void decodeIR6(uint32_t code);
|
||||
|
||||
void initIR();
|
||||
void handleIR();
|
||||
|
||||
//json.cpp
|
||||
#include "ESPAsyncWebServer.h"
|
||||
#include "src/dependencies/json/ArduinoJson-v6.h"
|
||||
#include "src/dependencies/json/AsyncJson-v6.h"
|
||||
#include "FX.h"
|
||||
// TODO: AsynicWebServerRequest conflict?
|
||||
|
||||
void deserializeSegment(JsonObject elem, byte it);
|
||||
bool deserializeState(JsonObject root);
|
||||
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id);
|
||||
void serializeState(JsonObject root);
|
||||
void serializeInfo(JsonObject root);
|
||||
void serveJson(AsyncWebServerRequest* request);
|
||||
void serveLiveLeds(AsyncWebServerRequest* request);
|
||||
|
||||
//led.cpp
|
||||
void setValuesFromMainSeg();
|
||||
void resetTimebase();
|
||||
void toggleOnOff();
|
||||
void setAllLeds();
|
||||
void setLedsStandard(bool justColors = false);
|
||||
bool colorChanged();
|
||||
void colorUpdated(int callMode);
|
||||
void updateInterfaces(uint8_t callMode);
|
||||
void handleTransitions();
|
||||
void handleNightlight();
|
||||
|
||||
//mqtt.cpp
|
||||
bool initMqtt();
|
||||
void publishMqtt();
|
||||
|
||||
//ntp.cpp
|
||||
void handleNetworkTime();
|
||||
void sendNTPPacket();
|
||||
bool checkNTPResponse();
|
||||
void updateLocalTime();
|
||||
void getTimeString(char* out);
|
||||
bool checkCountdown();
|
||||
void setCountdown();
|
||||
byte weekdayMondayFirst();
|
||||
void checkTimers();
|
||||
|
||||
//overlay.cpp
|
||||
void initCronixie();
|
||||
void handleOverlays();
|
||||
void handleOverlayDraw();
|
||||
void _overlayAnalogCountdown();
|
||||
void _overlayAnalogClock();
|
||||
|
||||
byte getSameCodeLength(char code, int index, char const cronixieDisplay[]);
|
||||
void setCronixie();
|
||||
void _overlayCronixie();
|
||||
void _drawOverlayCronixie();
|
||||
|
||||
//set.cpp
|
||||
void _setRandomColor(bool _sec,bool fromButton=false);
|
||||
bool isAsterisksOnly(const char* str, byte maxLen);
|
||||
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage);
|
||||
bool handleSet(AsyncWebServerRequest *request, const String& req);
|
||||
int getNumVal(const String* req, uint16_t pos);
|
||||
bool updateVal(const String* req, const char* key, byte* val, byte minv=0, byte maxv=255);
|
||||
|
||||
//udp.cpp
|
||||
void notify(byte callMode, bool followUp=false);
|
||||
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
||||
void handleNotifications();
|
||||
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w);
|
||||
|
||||
//usermod.cpp
|
||||
void userSetup();
|
||||
void userConnected();
|
||||
void userLoop();
|
||||
|
||||
//wled_eeprom.cpp
|
||||
void commit();
|
||||
void clearEEPROM();
|
||||
void writeStringToEEPROM(uint16_t pos, char* str, uint16_t len);
|
||||
void readStringFromEEPROM(uint16_t pos, char* str, uint16_t len);
|
||||
void saveSettingsToEEPROM();
|
||||
void loadSettingsFromEEPROM(bool first);
|
||||
void savedToPresets();
|
||||
bool applyPreset(byte index, bool loadBri = true);
|
||||
void savePreset(byte index, bool persist = true);
|
||||
void loadMacro(byte index, char* m);
|
||||
void applyMacro(byte index);
|
||||
void saveMacro(byte index, String mc, bool persist = true); //only commit on single save, not in settings
|
||||
|
||||
//wled_serial.cpp
|
||||
void handleSerial();
|
||||
|
||||
//wled_server.cpp
|
||||
bool isIp(String str);
|
||||
bool captivePortal(AsyncWebServerRequest *request);
|
||||
void initServer();
|
||||
void serveIndexOrWelcome(AsyncWebServerRequest *request);
|
||||
void serveIndex(AsyncWebServerRequest* request);
|
||||
String msgProcessor(const String& var);
|
||||
void serveMessage(AsyncWebServerRequest* request, uint16_t code, String headl, String subl="", byte optionT=255);
|
||||
String settingsProcessor(const String& var);
|
||||
String dmxProcessor(const String& var);
|
||||
void serveSettings(AsyncWebServerRequest* request);
|
||||
|
||||
//xml.cpp
|
||||
char* XML_response(AsyncWebServerRequest *request, char* dest = nullptr);
|
||||
char* URL_response(AsyncWebServerRequest *request);
|
||||
void sappend(char stype, const char* key, int val);
|
||||
void sappends(char stype, const char* key, char* val);
|
||||
void getSettingsJS(byte subPage, char* dest);
|
||||
|
||||
#endif
|
||||
55
wled00/file.cpp
Normal file
55
wled00/file.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Utility for SPIFFS filesystem
|
||||
*/
|
||||
|
||||
//filesystem
|
||||
#ifndef WLED_DISABLE_FILESYSTEM
|
||||
#include <FS.h>
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "SPIFFS.h"
|
||||
#endif
|
||||
#include "SPIFFSEditor.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined WLED_DISABLE_FILESYSTEM && defined WLED_ENABLE_FS_SERVING
|
||||
//Un-comment any file types you need
|
||||
String getContentType(AsyncWebServerRequest* request, String filename){
|
||||
if(request->hasArg("download")) return "application/octet-stream";
|
||||
else if(filename.endsWith(".htm")) return "text/html";
|
||||
else if(filename.endsWith(".html")) return "text/html";
|
||||
// else if(filename.endsWith(".css")) return "text/css";
|
||||
// else if(filename.endsWith(".js")) return "application/javascript";
|
||||
else if(filename.endsWith(".json")) return "application/json";
|
||||
else if(filename.endsWith(".png")) return "image/png";
|
||||
// else if(filename.endsWith(".gif")) return "image/gif";
|
||||
else if(filename.endsWith(".jpg")) return "image/jpeg";
|
||||
else if(filename.endsWith(".ico")) return "image/x-icon";
|
||||
// else if(filename.endsWith(".xml")) return "text/xml";
|
||||
// else if(filename.endsWith(".pdf")) return "application/x-pdf";
|
||||
// else if(filename.endsWith(".zip")) return "application/x-zip";
|
||||
// else if(filename.endsWith(".gz")) return "application/x-gzip";
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
bool handleFileRead(AsyncWebServerRequest* request, String path){
|
||||
DEBUG_PRINTLN("FileRead: " + path);
|
||||
if(path.endsWith("/")) path += "index.htm";
|
||||
String contentType = getContentType(request, path);
|
||||
String pathWithGz = path + ".gz";
|
||||
if(SPIFFS.exists(pathWithGz)){
|
||||
request->send(SPIFFS, pathWithGz, contentType);
|
||||
return true;
|
||||
}
|
||||
if(SPIFFS.exists(path)) {
|
||||
request->send(SPIFFS, path, contentType);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
bool handleFileRead(AsyncWebServerRequest*, String path){return false;}
|
||||
#endif
|
||||
@@ -1,658 +0,0 @@
|
||||
/*
|
||||
* Binary arrays for the classic desktop UI index page.
|
||||
* gzip is used for smaller size and improved speeds.
|
||||
*
|
||||
* Workflow for creating them from HTML source:
|
||||
* 1. Minify HTML (https://htmlcompressor.com/compressor/) (optional)
|
||||
* 2. Compress with gzip (https://online-converting.com/archives/convert-to-gzip/)
|
||||
* 3. Convert gzip binary to c array (https://sourceforge.net/projects/bin2header/)
|
||||
* alternative: https://littlevgl.com/image-to-c-array (raw)
|
||||
* 4. update length value
|
||||
*/
|
||||
|
||||
const uint16_t PAGE_index0_L = 10264;
|
||||
|
||||
const char PAGE_index0[] PROGMEM = {
|
||||
0x1f, 0x8b, 0x08, 0x08, 0x67, 0x5e, 0x61, 0x5c, 0x00, 0x03, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65,
|
||||
0x73, 0x73, 0x65, 0x64, 0x20, 0x28, 0x37, 0x29, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x00, 0xcc, 0x5a,
|
||||
0xe9, 0x72, 0xdb, 0x46, 0xb6, 0xfe, 0xaf, 0xa7, 0x80, 0xe9, 0x4a, 0x4c, 0x46, 0x04, 0x88, 0x9d,
|
||||
0x00, 0x29, 0x28, 0x65, 0x2b, 0xde, 0xaa, 0x1c, 0x45, 0x65, 0x69, 0x62, 0xa5, 0x32, 0x29, 0x17,
|
||||
0x88, 0x85, 0xc4, 0x18, 0x04, 0x68, 0x00, 0xa4, 0xa4, 0x30, 0x7a, 0xf7, 0xf9, 0x4e, 0x77, 0x93,
|
||||
0x04, 0xa8, 0x8d, 0xf4, 0x64, 0xe6, 0x5e, 0x57, 0x19, 0x40, 0xf7, 0x39, 0xdd, 0x67, 0x5f, 0xba,
|
||||
0xa9, 0xa3, 0x67, 0x3f, 0xfd, 0x72, 0x72, 0xf1, 0xdb, 0xd9, 0x6b, 0x69, 0x52, 0x4d, 0xd3, 0xe3,
|
||||
0x23, 0xf1, 0x8c, 0xfc, 0xf0, 0xf8, 0x68, 0x1a, 0x55, 0xbe, 0x14, 0x4c, 0xfc, 0xa2, 0x8c, 0x2a,
|
||||
0x6f, 0x5e, 0xc5, 0xb2, 0x23, 0xe6, 0x32, 0x7f, 0x1a, 0x79, 0xd5, 0x24, 0x9a, 0x46, 0x72, 0x90,
|
||||
0xa7, 0x79, 0x21, 0x05, 0x79, 0x56, 0x45, 0x59, 0xe5, 0x3d, 0x8f, 0xe3, 0xf8, 0xf8, 0x28, 0x4d,
|
||||
0xb2, 0x2f, 0x52, 0x11, 0xa5, 0xde, 0x8b, 0x72, 0x92, 0x17, 0x55, 0x30, 0xaf, 0xa4, 0x04, 0x18,
|
||||
0x2f, 0xa4, 0xea, 0x66, 0x16, 0x79, 0xc9, 0xd4, 0x1f, 0x47, 0xbd, 0x6b, 0x99, 0xa6, 0xa4, 0x49,
|
||||
0x11, 0xc5, 0xde, 0x8b, 0x5e, 0xec, 0x2f, 0x68, 0xa8, 0xe0, 0xf1, 0xa2, 0x77, 0x7c, 0x54, 0x25,
|
||||
0x55, 0x1a, 0x1d, 0x7f, 0xfa, 0xf0, 0xfa, 0x27, 0x49, 0x55, 0x1c, 0xc5, 0x38, 0xea, 0xf1, 0x19,
|
||||
0xe9, 0xa8, 0x0c, 0x8a, 0x64, 0x56, 0x1d, 0x2f, 0xfc, 0x42, 0x0a, 0xbd, 0x30, 0x0f, 0xe6, 0x53,
|
||||
0x90, 0x1d, 0xd2, 0xf0, 0xca, 0xbb, 0x4a, 0xb2, 0x30, 0xbf, 0x52, 0xc6, 0x51, 0x75, 0x92, 0x4f,
|
||||
0x67, 0xf3, 0x2a, 0x0a, 0xcf, 0xab, 0x9b, 0x34, 0x6a, 0x87, 0xca, 0xd7, 0x79, 0x54, 0xdc, 0x9c,
|
||||
0x47, 0x69, 0x14, 0x54, 0x79, 0xd1, 0x6e, 0x91, 0x8c, 0xad, 0x4e, 0x67, 0x58, 0x44, 0xe5, 0xcc,
|
||||
0x6b, 0xb5, 0xd8, 0xf2, 0x2c, 0xf5, 0xbd, 0xd8, 0x4f, 0xcb, 0x88, 0x8f, 0x8a, 0xc6, 0xa8, 0xac,
|
||||
0x8f, 0xca, 0x2a, 0xaf, 0x8d, 0xe6, 0x57, 0x8b, 0x3a, 0x6c, 0x14, 0x7b, 0x55, 0x31, 0xe7, 0x83,
|
||||
0x38, 0x29, 0xca, 0x2a, 0xcd, 0xfd, 0x70, 0x33, 0x95, 0xfa, 0x65, 0x55, 0x5e, 0x7b, 0x2a, 0xdf,
|
||||
0xf6, 0xbc, 0xf2, 0xab, 0x48, 0x0c, 0x82, 0x85, 0xf8, 0x48, 0xa7, 0xe2, 0x23, 0xbe, 0x4e, 0x56,
|
||||
0x5f, 0xb3, 0xf5, 0xd7, 0x75, 0xe6, 0x69, 0x43, 0xff, 0x84, 0xb8, 0x1e, 0xb1, 0x67, 0xc8, 0x9e,
|
||||
0xf1, 0x3c, 0x0b, 0xaa, 0x04, 0xfa, 0x1c, 0xbf, 0x0f, 0xdb, 0x65, 0xe7, 0x60, 0x59, 0x44, 0xd5,
|
||||
0xbc, 0xc8, 0xa4, 0x90, 0xb4, 0xf1, 0x3a, 0x8d, 0x48, 0x4b, 0xaf, 0x6e, 0x18, 0x6c, 0x78, 0x7b,
|
||||
0xb0, 0xc6, 0xfe, 0xc7, 0x49, 0x9e, 0xb6, 0x81, 0x8d, 0x0d, 0x99, 0xde, 0xce, 0x8a, 0x7c, 0x16,
|
||||
0x15, 0xd5, 0xcd, 0xaf, 0x7e, 0x3a, 0x8f, 0xda, 0x2d, 0x59, 0xf6, 0x81, 0xd0, 0xea, 0x10, 0xa9,
|
||||
0xfb, 0xe1, 0x23, 0x0e, 0x0f, 0x1f, 0x82, 0x87, 0x02, 0xbe, 0x6d, 0x01, 0xf2, 0xa2, 0xdf, 0xb7,
|
||||
0xbd, 0xe8, 0x8f, 0x56, 0x47, 0x81, 0xa7, 0xbd, 0xac, 0xaa, 0x22, 0x19, 0xc1, 0x7c, 0xed, 0x96,
|
||||
0x70, 0xab, 0x56, 0x77, 0x74, 0xd2, 0xe0, 0x1b, 0x8a, 0x2b, 0xaa, 0xf9, 0x8c, 0x58, 0xff, 0x46,
|
||||
0xd3, 0x73, 0xc9, 0x87, 0x27, 0xbf, 0xb6, 0xd5, 0xce, 0x10, 0x44, 0xdf, 0x83, 0x50, 0xb1, 0xf0,
|
||||
0xd3, 0xf6, 0xdb, 0xf7, 0xbf, 0x74, 0x2d, 0x55, 0xc5, 0x2c, 0xbe, 0xda, 0x0c, 0x76, 0x91, 0x4c,
|
||||
0xa3, 0x7c, 0x5e, 0xb5, 0x57, 0xe4, 0xdb, 0x9d, 0x65, 0x9c, 0xa4, 0x69, 0x7c, 0x4d, 0x6b, 0x6f,
|
||||
0x09, 0xfb, 0x09, 0x34, 0x8d, 0xd0, 0xfa, 0x96, 0xda, 0x90, 0x81, 0x6d, 0x7f, 0xb0, 0xcc, 0xf2,
|
||||
0xc0, 0x0f, 0x26, 0x91, 0xd7, 0xfa, 0x7e, 0xfd, 0x75, 0xf8, 0xb3, 0x5f, 0x4d, 0x94, 0xc2, 0x87,
|
||||
0x48, 0xd3, 0x76, 0xe7, 0x07, 0x4d, 0x65, 0xff, 0x98, 0xfd, 0x8b, 0x08, 0xf2, 0x94, 0x95, 0x97,
|
||||
0x45, 0x57, 0xd2, 0xe5, 0xcf, 0x1f, 0xde, 0x55, 0xd5, 0xec, 0x23, 0x9f, 0x6a, 0x93, 0x3b, 0xb3,
|
||||
0x2f, 0x25, 0xcf, 0x0a, 0x84, 0xef, 0x4d, 0x49, 0xde, 0x85, 0xe8, 0xcd, 0xc6, 0x91, 0xb7, 0xe1,
|
||||
0xe9, 0x60, 0x99, 0xc4, 0xed, 0x6a, 0x92, 0x94, 0x0a, 0x43, 0xe2, 0x2e, 0xe8, 0x99, 0x9d, 0xf5,
|
||||
0x34, 0x2d, 0x9b, 0x97, 0x9e, 0xa7, 0x43, 0xac, 0x1a, 0x6e, 0x39, 0xcb, 0xb3, 0x32, 0x02, 0xcd,
|
||||
0x67, 0x5e, 0x36, 0x4f, 0xd3, 0xce, 0x32, 0x54, 0x4e, 0x62, 0xe5, 0xfc, 0xa5, 0xb2, 0x20, 0x5b,
|
||||
0x7b, 0xdb, 0x58, 0x35, 0xbf, 0x2b, 0x5f, 0xdd, 0x5c, 0xf8, 0xe3, 0x53, 0x18, 0xbb, 0xfd, 0xc2,
|
||||
0x0f, 0x5e, 0x74, 0x7e, 0x57, 0xff, 0x50, 0x82, 0x49, 0x92, 0x86, 0xa7, 0x79, 0x18, 0x95, 0x34,
|
||||
0xca, 0xf0, 0xc1, 0x5c, 0x66, 0xc8, 0x37, 0xfd, 0xb8, 0xdf, 0xa6, 0x41, 0xba, 0xcb, 0xa6, 0x6f,
|
||||
0xbf, 0x61, 0x53, 0xed, 0xa9, 0x4d, 0x5f, 0x7d, 0xc3, 0xa6, 0xfa, 0xc3, 0x9b, 0xde, 0xa3, 0xee,
|
||||
0x07, 0x76, 0xba, 0x5a, 0x3c, 0x2a, 0xf3, 0xb1, 0xa7, 0xae, 0x2c, 0xf4, 0x69, 0x3f, 0x16, 0x9f,
|
||||
0xd8, 0x78, 0x48, 0xf9, 0x8e, 0xa5, 0xb3, 0xdb, 0x08, 0x49, 0x6f, 0xb9, 0x49, 0x7f, 0x70, 0x6d,
|
||||
0x24, 0xac, 0x1d, 0xa9, 0xc4, 0xd7, 0x8f, 0x53, 0xa1, 0x8c, 0xb7, 0xeb, 0x56, 0xb3, 0x5d, 0xac,
|
||||
0x7f, 0xb9, 0x9f, 0x16, 0xca, 0x27, 0xf8, 0x63, 0x9b, 0xbe, 0xdf, 0x73, 0xd3, 0xe4, 0x89, 0x4d,
|
||||
0xa9, 0x04, 0xed, 0x6a, 0xff, 0x4c, 0xf8, 0x7c, 0x92, 0x65, 0x51, 0xf1, 0xee, 0xe2, 0xe7, 0x0f,
|
||||
0x9d, 0x67, 0x9e, 0xfa, 0x23, 0x19, 0x66, 0xc0, 0xcd, 0x01, 0x57, 0x5a, 0xd7, 0x1f, 0xe1, 0x0a,
|
||||
0xa7, 0x27, 0x20, 0x1d, 0x05, 0x5f, 0xa2, 0x70, 0x77, 0x32, 0xf1, 0x13, 0x64, 0xb8, 0x76, 0x4f,
|
||||
0xf7, 0x53, 0x44, 0x16, 0xee, 0x62, 0xb2, 0x8b, 0x3d, 0x37, 0xad, 0x9e, 0xda, 0x74, 0xd5, 0x2e,
|
||||
0x88, 0xc5, 0xc8, 0x74, 0x28, 0x11, 0x54, 0x71, 0x56, 0x65, 0x6b, 0x5d, 0xf1, 0xba, 0xbb, 0xc6,
|
||||
0xb3, 0xff, 0x28, 0xcd, 0xce, 0xae, 0x44, 0x47, 0x7b, 0x11, 0x1d, 0xfd, 0x3d, 0x44, 0x83, 0xbd,
|
||||
0x88, 0x3e, 0x9e, 0xb8, 0x77, 0x26, 0x1a, 0xee, 0x45, 0xf4, 0x71, 0x3f, 0xd9, 0x99, 0x68, 0xb9,
|
||||
0x17, 0xd1, 0xf9, 0xdf, 0x43, 0xb4, 0xda, 0x8b, 0xe8, 0xe3, 0xce, 0xbb, 0xbb, 0x4d, 0xdf, 0x64,
|
||||
0xbb, 0xd3, 0x8c, 0x9f, 0xa0, 0xb9, 0xe9, 0x91, 0x66, 0x74, 0x04, 0x40, 0x8b, 0xb4, 0x6b, 0xda,
|
||||
0x98, 0x3e, 0x61, 0xb8, 0x8e, 0xa8, 0x1e, 0x08, 0xf3, 0x8b, 0x4b, 0xc8, 0x40, 0xdd, 0x59, 0x14,
|
||||
0xbe, 0xcf, 0xc2, 0xe8, 0xda, 0x43, 0x15, 0x19, 0xf2, 0xe4, 0xba, 0x35, 0x3f, 0x4b, 0xa8, 0xc6,
|
||||
0xac, 0x7b, 0x6a, 0x9e, 0x7f, 0xd6, 0x3d, 0xb4, 0xf8, 0xd8, 0x39, 0xb1, 0x15, 0xf7, 0x25, 0x36,
|
||||
0x6d, 0xb0, 0xda, 0xe8, 0x70, 0xf7, 0x9d, 0xca, 0xfb, 0x76, 0xd2, 0xb1, 0x53, 0xd8, 0x5c, 0x71,
|
||||
0x82, 0xe6, 0xbf, 0x64, 0x6b, 0x5a, 0x50, 0x48, 0xd0, 0x6a, 0xae, 0xda, 0x35, 0xcd, 0x85, 0xdb,
|
||||
0xe4, 0x86, 0xff, 0xf8, 0x15, 0x46, 0xba, 0xc5, 0xbf, 0x83, 0x46, 0xce, 0xa7, 0xad, 0x0e, 0xd1,
|
||||
0x56, 0xbe, 0xbf, 0x68, 0x1d, 0xac, 0x3b, 0xc3, 0x59, 0x94, 0xb5, 0x5b, 0x6f, 0x5f, 0x5f, 0xb4,
|
||||
0xba, 0x2d, 0xb4, 0xcc, 0xad, 0x43, 0x86, 0x24, 0x1a, 0xcf, 0x2e, 0xa5, 0xf5, 0x4d, 0x17, 0x59,
|
||||
0x46, 0x59, 0xd8, 0x66, 0xad, 0xde, 0xfa, 0x9c, 0x54, 0xef, 0x5e, 0x4f, 0xda, 0xec, 0x94, 0xc1,
|
||||
0x69, 0xbc, 0x44, 0xd3, 0x5a, 0xeb, 0x06, 0x87, 0xab, 0xf9, 0x8f, 0x62, 0xfe, 0xe3, 0xd6, 0xfc,
|
||||
0x5b, 0x31, 0xff, 0x76, 0x6b, 0xfe, 0x95, 0x98, 0x17, 0x6d, 0x15, 0x15, 0x31, 0x34, 0x18, 0x6b,
|
||||
0x51, 0x3e, 0x09, 0xb0, 0x68, 0x69, 0xb8, 0xe4, 0xbc, 0x4d, 0xaf, 0xb3, 0x76, 0x59, 0x67, 0xed,
|
||||
0xcd, 0x25, 0x5f, 0xb4, 0xed, 0x67, 0x6b, 0x9a, 0xe7, 0x02, 0x61, 0xd5, 0x22, 0xac, 0x01, 0xef,
|
||||
0x05, 0x60, 0x55, 0xe6, 0x1f, 0x22, 0x17, 0x55, 0x1f, 0xdf, 0xbe, 0x5a, 0x1d, 0x45, 0x8a, 0xee,
|
||||
0xb8, 0x3b, 0xea, 0x26, 0xdd, 0xb8, 0x3b, 0xeb, 0x7e, 0xed, 0xf2, 0x93, 0xe9, 0xc4, 0xe3, 0x05,
|
||||
0xed, 0x1d, 0xdf, 0xa7, 0x5b, 0x8a, 0xf1, 0xb9, 0x18, 0x2f, 0x3c, 0xdd, 0xb2, 0x86, 0x89, 0xc7,
|
||||
0xda, 0xfe, 0x38, 0xcd, 0x71, 0x4e, 0x99, 0xfc, 0x60, 0x77, 0x86, 0xb1, 0x87, 0x97, 0x9c, 0x0c,
|
||||
0x67, 0xde, 0xe2, 0x87, 0xb6, 0x26, 0xe3, 0xe8, 0xf6, 0x95, 0x7f, 0xc5, 0x3f, 0xe0, 0xbb, 0xe2,
|
||||
0xdf, 0x34, 0xec, 0xd0, 0xb8, 0xbc, 0x4a, 0xaa, 0x60, 0xd2, 0x4e, 0xbe, 0xb3, 0x3b, 0xcb, 0xc0,
|
||||
0x2f, 0x23, 0x49, 0x1d, 0x14, 0xde, 0xa2, 0x3b, 0xf6, 0xaa, 0xee, 0xc8, 0x9b, 0x0d, 0x47, 0x68,
|
||||
0xf7, 0xbf, 0x0c, 0x19, 0x40, 0x03, 0xe0, 0x2b, 0x00, 0x8b, 0x6d, 0x80, 0x0e, 0xc0, 0x4c, 0x00,
|
||||
0xaa, 0x3a, 0xc0, 0x10, 0x80, 0xaf, 0x00, 0x2c, 0xea, 0x00, 0x13, 0x80, 0x0a, 0x80, 0xd9, 0x36,
|
||||
0xc0, 0x12, 0xc4, 0x09, 0xf0, 0x15, 0xea, 0x6a, 0x36, 0xf6, 0xc5, 0x56, 0x4f, 0x3e, 0xde, 0x6a,
|
||||
0xa7, 0x47, 0x43, 0xf2, 0xaf, 0x86, 0x96, 0xcf, 0x1a, 0x46, 0x3d, 0xe3, 0xa6, 0x79, 0x73, 0xb6,
|
||||
0x65, 0xd4, 0x3b, 0xd6, 0x41, 0xf2, 0x5a, 0xf0, 0x33, 0x0f, 0x8e, 0xed, 0x9d, 0x93, 0x34, 0x2f,
|
||||
0xa3, 0xf3, 0xa8, 0xaa, 0x92, 0x6c, 0x5c, 0x02, 0x91, 0x4e, 0xcb, 0xad, 0x32, 0x7d, 0x49, 0x07,
|
||||
0x4f, 0x96, 0x4e, 0xc3, 0xa4, 0x9c, 0xa5, 0xfe, 0x8d, 0xd7, 0xca, 0xf2, 0x2c, 0x6a, 0x09, 0x78,
|
||||
0x31, 0x1e, 0x3d, 0x8e, 0x30, 0x29, 0x1f, 0x87, 0xa7, 0x9f, 0x1e, 0x85, 0x57, 0xe9, 0xe5, 0x13,
|
||||
0xf0, 0xb3, 0x27, 0xe0, 0xa7, 0x0f, 0xc1, 0x21, 0xf7, 0xe2, 0x48, 0x67, 0xe7, 0x38, 0x0a, 0xa4,
|
||||
0x87, 0xd9, 0x19, 0xa5, 0x79, 0xf0, 0xa5, 0xf5, 0x88, 0x42, 0x04, 0xc2, 0xed, 0x81, 0xf0, 0xb3,
|
||||
0xc5, 0xda, 0xcb, 0x1e, 0x51, 0x92, 0x58, 0xc4, 0xae, 0x34, 0x1a, 0x0e, 0xf8, 0xb0, 0xde, 0x36,
|
||||
0x4b, 0xb4, 0xa6, 0x6b, 0x3e, 0xac, 0x0a, 0xb1, 0xa4, 0xe1, 0xaf, 0x0f, 0x2b, 0xf6, 0x2e, 0xb6,
|
||||
0x39, 0x78, 0x58, 0x8d, 0x6b, 0xb1, 0x83, 0x05, 0x1c, 0x7c, 0x1a, 0x8e, 0x04, 0x02, 0x9d, 0xec,
|
||||
0xbd, 0x76, 0x3a, 0x3d, 0x56, 0x3b, 0x3f, 0xfa, 0x27, 0x83, 0xf0, 0xa4, 0xee, 0x74, 0xd0, 0x85,
|
||||
0x3e, 0x89, 0xae, 0xdb, 0x45, 0x14, 0x76, 0xc7, 0x45, 0x14, 0x65, 0xdd, 0x11, 0x55, 0x3d, 0x9e,
|
||||
0x20, 0xc6, 0x23, 0x8f, 0x46, 0x7f, 0xb5, 0x19, 0xe4, 0xe8, 0xc8, 0xe9, 0xfc, 0x45, 0x88, 0x47,
|
||||
0x47, 0x9a, 0x4d, 0x99, 0x96, 0xae, 0x6d, 0x5e, 0x3c, 0x7f, 0x71, 0xd8, 0x56, 0xaf, 0xc5, 0xc1,
|
||||
0xff, 0x10, 0x4b, 0x3a, 0x4a, 0x95, 0x9f, 0x57, 0x05, 0xdc, 0xb6, 0x0d, 0x34, 0xa5, 0x4c, 0x93,
|
||||
0x20, 0x6a, 0x6b, 0x9d, 0x1a, 0xcd, 0x14, 0xb0, 0xc2, 0x0f, 0xdb, 0x2c, 0x01, 0x75, 0xc4, 0xfd,
|
||||
0x4f, 0x0b, 0xb3, 0x91, 0x5f, 0xc8, 0x04, 0x49, 0x50, 0x48, 0xda, 0xad, 0xc3, 0xd1, 0xc9, 0x21,
|
||||
0x92, 0xff, 0xe1, 0x9a, 0x45, 0x86, 0x7e, 0xd8, 0xea, 0x34, 0xb2, 0x3b, 0x65, 0xba, 0x03, 0x1c,
|
||||
0x1a, 0x46, 0x79, 0x78, 0x23, 0x04, 0x1e, 0xf9, 0xc1, 0x97, 0x71, 0x91, 0xcf, 0xb3, 0xd0, 0x5b,
|
||||
0x91, 0xaa, 0x45, 0x74, 0xb7, 0x16, 0xcd, 0xdd, 0x5a, 0x24, 0xb3, 0x8b, 0x91, 0x77, 0xe7, 0xbb,
|
||||
0xa1, 0xc6, 0xd7, 0x4d, 0xed, 0xb2, 0x9c, 0xb0, 0x9d, 0xb7, 0x37, 0x0a, 0xcf, 0xd2, 0x26, 0x3a,
|
||||
0x8e, 0x4f, 0x6b, 0x50, 0xf5, 0x20, 0x48, 0xb8, 0x2f, 0xaf, 0xf2, 0x10, 0xb2, 0xee, 0xc4, 0x33,
|
||||
0x24, 0x60, 0x6d, 0xed, 0x03, 0x6c, 0x29, 0x56, 0xac, 0x41, 0xfa, 0x1d, 0xd0, 0x5d, 0x9f, 0xbe,
|
||||
0x67, 0x0b, 0x7f, 0xd7, 0x2d, 0xf4, 0x6f, 0xe1, 0xc2, 0x3f, 0xb9, 0xc7, 0xf1, 0xf7, 0xe3, 0xc2,
|
||||
0x27, 0xe7, 0xad, 0xc6, 0x4d, 0x95, 0xd5, 0xca, 0xf9, 0x46, 0xe5, 0xf1, 0xec, 0x72, 0x2b, 0x40,
|
||||
0xda, 0x0f, 0x98, 0x48, 0x04, 0xce, 0x40, 0xe4, 0xa1, 0x38, 0x8f, 0xb7, 0x77, 0xbf, 0xb3, 0xca,
|
||||
0x36, 0xd7, 0x64, 0xa6, 0xc5, 0x53, 0xd8, 0x47, 0xda, 0x3d, 0x71, 0x77, 0x31, 0xbe, 0x10, 0x17,
|
||||
0x5c, 0x4d, 0xee, 0x37, 0x85, 0xe3, 0xc2, 0x53, 0x5b, 0xc3, 0xfa, 0xbd, 0x95, 0xca, 0x3b, 0xd1,
|
||||
0x3a, 0x86, 0x4e, 0xa1, 0x70, 0x7f, 0xad, 0x3f, 0xbf, 0x7a, 0x73, 0xc9, 0xae, 0x57, 0xd9, 0xf5,
|
||||
0xad, 0x77, 0x0f, 0x5f, 0x87, 0x25, 0xe5, 0xdc, 0xcc, 0xf3, 0x64, 0xed, 0xaf, 0xbf, 0xf0, 0x8a,
|
||||
0xaf, 0xb3, 0x0e, 0x8f, 0xc5, 0xe1, 0x7d, 0xcd, 0x6e, 0xc6, 0xb0, 0x8f, 0xd4, 0xce, 0x7d, 0x40,
|
||||
0x95, 0x01, 0x8f, 0x69, 0x8b, 0xfb, 0xc0, 0xac, 0x5d, 0x98, 0x26, 0x59, 0xdb, 0xb6, 0xba, 0xc0,
|
||||
0x91, 0x35, 0x30, 0x7c, 0xd9, 0xe4, 0xf7, 0x62, 0xfc, 0xee, 0xfc, 0x95, 0x50, 0x49, 0x40, 0x85,
|
||||
0xe0, 0x60, 0x89, 0x77, 0xe7, 0x47, 0x76, 0xed, 0x39, 0xc0, 0x53, 0x5b, 0x77, 0xe2, 0xbf, 0x22,
|
||||
0x99, 0x51, 0x1b, 0x59, 0x17, 0x96, 0x22, 0xe5, 0xec, 0xbc, 0x7d, 0xcd, 0x72, 0x01, 0x95, 0xdb,
|
||||
0x37, 0x42, 0x6b, 0xeb, 0xf3, 0x40, 0x63, 0xba, 0x73, 0x78, 0x4d, 0x1c, 0x37, 0xe6, 0x60, 0xa7,
|
||||
0xe6, 0x52, 0xed, 0x0e, 0xca, 0xb1, 0x6e, 0x6d, 0xe1, 0xe8, 0x56, 0x5d, 0x88, 0xb3, 0x97, 0xd5,
|
||||
0xa6, 0xf6, 0xf3, 0xa5, 0xaf, 0xd6, 0x37, 0x19, 0xf0, 0xb4, 0xef, 0xcf, 0x5e, 0x7a, 0x1a, 0x3c,
|
||||
0x8d, 0xde, 0xb0, 0x6e, 0x1d, 0xef, 0xa4, 0x89, 0x77, 0x22, 0xf0, 0x4e, 0xb6, 0xf1, 0xde, 0x34,
|
||||
0xf1, 0x2e, 0x05, 0xde, 0x25, 0xe1, 0xd5, 0x39, 0x39, 0x87, 0x43, 0x94, 0xd4, 0x4f, 0x30, 0x9e,
|
||||
0x48, 0x12, 0x36, 0x5a, 0xf9, 0xce, 0xd9, 0xb9, 0xb7, 0xda, 0xb7, 0x21, 0xd0, 0xb6, 0x8f, 0x9d,
|
||||
0x7d, 0x78, 0x08, 0xef, 0xe0, 0x8e, 0xcb, 0xfd, 0x82, 0x96, 0x7d, 0xd3, 0xb1, 0x1c, 0x2c, 0xe9,
|
||||
0xd7, 0x07, 0x76, 0xff, 0x56, 0x36, 0x73, 0x1c, 0x82, 0x38, 0x08, 0x5f, 0xdd, 0xdf, 0x05, 0x94,
|
||||
0x55, 0xbc, 0x0d, 0x48, 0x32, 0x2a, 0x0d, 0xac, 0x41, 0x28, 0x47, 0x71, 0x87, 0x61, 0x14, 0x81,
|
||||
0xd7, 0xea, 0x95, 0x82, 0x16, 0x56, 0x8d, 0xe2, 0xcd, 0xd5, 0xde, 0xba, 0x9f, 0x6a, 0x76, 0x50,
|
||||
0x9c, 0x1f, 0x8e, 0xb5, 0xc5, 0x50, 0x78, 0x2f, 0x43, 0x2b, 0xba, 0xf7, 0xb0, 0xc4, 0x79, 0x6d,
|
||||
0x78, 0xef, 0x79, 0x7b, 0xd3, 0xbb, 0x1d, 0x2c, 0xb7, 0xbb, 0x37, 0xee, 0xb9, 0x4d, 0x05, 0x35,
|
||||
0x3c, 0xf8, 0x62, 0x7c, 0xca, 0x7e, 0xde, 0xa0, 0x8b, 0xb5, 0x67, 0x78, 0xb0, 0x78, 0x42, 0x29,
|
||||
0x58, 0x1b, 0xe2, 0x14, 0x86, 0x38, 0x6c, 0x5c, 0x61, 0xad, 0xbb, 0xff, 0xd3, 0x8b, 0x35, 0xe8,
|
||||
0xa2, 0x01, 0x6a, 0x6f, 0xdd, 0xa5, 0x91, 0xc7, 0x9c, 0xbe, 0xe1, 0x1e, 0x83, 0x37, 0x79, 0x0c,
|
||||
0xe3, 0xab, 0x46, 0x43, 0x7d, 0x38, 0xa3, 0x80, 0x45, 0xc6, 0x21, 0x3f, 0x74, 0x1e, 0x32, 0x0e,
|
||||
0xd9, 0xf7, 0xb1, 0xd1, 0x59, 0x9f, 0x6d, 0x1f, 0xa8, 0x59, 0xeb, 0x13, 0xcc, 0xa9, 0xa7, 0x7e,
|
||||
0xff, 0xf1, 0x94, 0xc8, 0x34, 0xbb, 0xfc, 0x2d, 0xb8, 0xd6, 0xda, 0x6a, 0xf6, 0x37, 0x70, 0xed,
|
||||
0xee, 0x7a, 0xe3, 0x0e, 0x5c, 0x7b, 0x58, 0x0c, 0x5e, 0xe5, 0x45, 0x87, 0x83, 0x9e, 0x02, 0x4d,
|
||||
0xc5, 0xa8, 0x5b, 0x78, 0x7e, 0x31, 0x66, 0x77, 0x16, 0x74, 0xfc, 0xef, 0xe1, 0x90, 0x83, 0x03,
|
||||
0xc1, 0x66, 0x4a, 0xe3, 0x53, 0xa3, 0xda, 0x94, 0xce, 0xa7, 0x26, 0xdd, 0x12, 0x87, 0x22, 0x9e,
|
||||
0xdf, 0xfc, 0x55, 0x8f, 0xd2, 0x0d, 0x93, 0x38, 0xf6, 0x16, 0xf2, 0x3a, 0xed, 0xd5, 0xa6, 0x83,
|
||||
0xcd, 0x0f, 0x1c, 0xc1, 0xaa, 0xf7, 0x69, 0x2f, 0xe4, 0xa0, 0xd3, 0xb3, 0x7b, 0x04, 0x3f, 0xd4,
|
||||
0x7a, 0xfa, 0xf0, 0x96, 0x65, 0x1e, 0xda, 0x84, 0x2e, 0xc7, 0x27, 0x5e, 0xb9, 0x4a, 0xfe, 0x4b,
|
||||
0x1c, 0xc8, 0x30, 0xdd, 0x5b, 0x0c, 0x8b, 0x82, 0x7d, 0x05, 0xed, 0x02, 0x67, 0x83, 0xb1, 0xf8,
|
||||
0x1e, 0x77, 0x86, 0xa3, 0x91, 0xf8, 0x1e, 0xb1, 0xa0, 0x2f, 0x3c, 0xcf, 0x5b, 0xd0, 0x16, 0xa3,
|
||||
0x91, 0x3c, 0x1e, 0xf3, 0x4d, 0x24, 0xcc, 0x8f, 0x57, 0xf3, 0x6d, 0xad, 0x67, 0x74, 0x0e, 0x8b,
|
||||
0x42, 0x1e, 0x8d, 0x36, 0xd0, 0xd1, 0x1a, 0xaa, 0x13, 0x74, 0x3c, 0x96, 0x8b, 0x62, 0xc8, 0x0e,
|
||||
0xed, 0x93, 0x23, 0x62, 0xe8, 0x10, 0xb9, 0x71, 0x8d, 0x3c, 0x39, 0xd6, 0x30, 0x25, 0xd3, 0x14,
|
||||
0x43, 0x29, 0x51, 0xc6, 0x1a, 0xa7, 0x48, 0x6f, 0x32, 0x6c, 0x9c, 0x22, 0xbd, 0xb2, 0x11, 0xa6,
|
||||
0xe7, 0xed, 0x84, 0x82, 0x53, 0x9c, 0x09, 0xef, 0xf1, 0x99, 0x4f, 0x0f, 0x39, 0xcb, 0xab, 0x87,
|
||||
0xbc, 0xe4, 0xe3, 0x96, 0x03, 0xd5, 0x1c, 0xe4, 0x6c, 0xab, 0x9f, 0x5e, 0x03, 0x4e, 0x5a, 0x5b,
|
||||
0x87, 0xc2, 0xcd, 0x66, 0x2c, 0x28, 0xee, 0x38, 0xd2, 0xfc, 0xe4, 0xb7, 0xf6, 0x3a, 0xbf, 0x36,
|
||||
0x52, 0xf9, 0x6f, 0xf5, 0x80, 0x3b, 0xf9, 0x8d, 0x07, 0x1c, 0xde, 0xeb, 0x54, 0x8e, 0xbc, 0xaa,
|
||||
0xf1, 0x63, 0xe1, 0x99, 0xb6, 0x15, 0xcc, 0x67, 0xba, 0x00, 0xe8, 0xdb, 0x80, 0x0b, 0x01, 0x58,
|
||||
0xc5, 0xf8, 0x1d, 0x86, 0x3e, 0xd6, 0xcf, 0x9d, 0x67, 0x2c, 0x96, 0xef, 0xe0, 0x88, 0x9f, 0xf9,
|
||||
0xe2, 0x19, 0x50, 0x23, 0xaf, 0x75, 0x94, 0xcf, 0x68, 0xfa, 0xf8, 0x75, 0x51, 0xe4, 0x85, 0x44,
|
||||
0x97, 0x31, 0xc8, 0x4d, 0x68, 0xd0, 0xcb, 0xea, 0xd9, 0x51, 0x4f, 0xc0, 0x5a, 0xc3, 0x28, 0xf5,
|
||||
0xe2, 0xd9, 0x8f, 0xec, 0x10, 0x3b, 0x60, 0xe5, 0x7d, 0x18, 0x47, 0x64, 0x2c, 0x4c, 0xbe, 0xe8,
|
||||
0xfd, 0xab, 0xcc, 0xb3, 0xde, 0xcc, 0x4f, 0x91, 0xd7, 0xa2, 0xf2, 0xc5, 0x40, 0x4c, 0x44, 0x71,
|
||||
0x8c, 0xfa, 0x5f, 0xbe, 0xc0, 0x69, 0x60, 0x12, 0x21, 0x00, 0xa2, 0xd2, 0x3b, 0xa6, 0xf4, 0xf8,
|
||||
0x0c, 0x5f, 0x4a, 0xfe, 0xa5, 0xb3, 0x8c, 0xd2, 0xda, 0x85, 0x12, 0xe5, 0x6d, 0xf1, 0x33, 0x30,
|
||||
0xc1, 0x69, 0x07, 0x62, 0x5b, 0x2c, 0xa6, 0x21, 0x56, 0x53, 0xc0, 0x5e, 0xaf, 0x7e, 0x03, 0x67,
|
||||
0x1c, 0x11, 0x40, 0x59, 0x91, 0x1e, 0xb0, 0x91, 0xa0, 0x8b, 0x2e, 0xae, 0x68, 0x27, 0x52, 0x82,
|
||||
0xc3, 0x46, 0x67, 0x79, 0x7d, 0xb8, 0x16, 0x54, 0xe2, 0x0e, 0xf8, 0xcf, 0x56, 0xeb, 0x30, 0x39,
|
||||
0x6c, 0xfd, 0xb3, 0x75, 0xdc, 0x3a, 0x4c, 0x7f, 0x4f, 0xfe, 0x38, 0x6c, 0x49, 0x6d, 0x36, 0xd3,
|
||||
0xa9, 0x49, 0x7d, 0x7b, 0xd0, 0xe0, 0xf1, 0x1a, 0x6a, 0xb8, 0x73, 0xcf, 0xf7, 0x63, 0x3c, 0x4b,
|
||||
0x06, 0x74, 0x0d, 0x48, 0xa2, 0x41, 0xa9, 0xf4, 0xa3, 0x77, 0xaa, 0xa4, 0x51, 0x36, 0xae, 0x26,
|
||||
0xe2, 0xb6, 0xab, 0xa3, 0x04, 0x3e, 0x53, 0xd6, 0xe6, 0xb7, 0xd6, 0x6d, 0xd9, 0x3b, 0xb7, 0x47,
|
||||
0x3d, 0xf1, 0xd7, 0x02, 0xd2, 0x11, 0x2b, 0x35, 0xc7, 0x83, 0x22, 0xcf, 0xab, 0x25, 0xbf, 0xe3,
|
||||
0x1f, 0x3c, 0x0f, 0xdd, 0x91, 0xa1, 0xa9, 0x43, 0x7e, 0xfb, 0x3e, 0x78, 0xae, 0x8e, 0x8c, 0xc0,
|
||||
0x0a, 0x87, 0xfc, 0x5e, 0x7c, 0xf0, 0x5c, 0x0b, 0xf5, 0xbe, 0xa1, 0x0d, 0xf9, 0x8d, 0xf5, 0xe0,
|
||||
0xb9, 0xa1, 0x3b, 0x41, 0x40, 0xc3, 0x92, 0x23, 0xab, 0xb4, 0xb0, 0x6a, 0x82, 0x82, 0x37, 0xd9,
|
||||
0xe0, 0xd7, 0xa8, 0x08, 0xfd, 0xcc, 0xbf, 0x55, 0x82, 0xaa, 0x48, 0x3f, 0x8f, 0xf2, 0xeb, 0xe5,
|
||||
0x14, 0xe9, 0x2d, 0xc9, 0x06, 0xfe, 0xbc, 0xca, 0x87, 0x57, 0x49, 0x58, 0x4d, 0x06, 0x8e, 0xba,
|
||||
0xb8, 0x1a, 0x6e, 0xce, 0x53, 0xfc, 0xc7, 0xef, 0x01, 0x0c, 0xd0, 0xe6, 0xc4, 0x3b, 0xc3, 0x59,
|
||||
0x5e, 0x26, 0x24, 0xd6, 0xc0, 0x1f, 0x95, 0x79, 0x3a, 0xaf, 0xa2, 0x61, 0x95, 0xcf, 0x06, 0x96,
|
||||
0xf5, 0xdd, 0x30, 0x8d, 0xe2, 0x6a, 0x60, 0xa9, 0xdf, 0x0d, 0xab, 0xc2, 0xcf, 0x4a, 0x18, 0x64,
|
||||
0x3a, 0x60, 0x5f, 0x29, 0x2a, 0x43, 0x5b, 0x06, 0xa0, 0x4b, 0x0f, 0x9c, 0xa5, 0x92, 0xb4, 0x8a,
|
||||
0x8a, 0x41, 0x58, 0xe4, 0x33, 0xb9, 0x9c, 0xf8, 0x61, 0x7e, 0x05, 0xe8, 0xec, 0x5a, 0x62, 0x0f,
|
||||
0xfa, 0xcf, 0xc9, 0x91, 0x34, 0x9d, 0xce, 0xad, 0x52, 0x86, 0xe5, 0x92, 0x33, 0x87, 0x43, 0xe7,
|
||||
0x77, 0xc3, 0x49, 0x94, 0x8c, 0x27, 0xd5, 0x40, 0xd3, 0x17, 0x93, 0x21, 0xe7, 0x5f, 0x26, 0x06,
|
||||
0x30, 0x04, 0x6a, 0x2a, 0x44, 0x92, 0x19, 0x2f, 0x4c, 0x2e, 0x31, 0x51, 0xb0, 0x55, 0xf5, 0x19,
|
||||
0xb1, 0x4a, 0x08, 0xde, 0xef, 0x2f, 0xae, 0x6e, 0x9f, 0x97, 0xe9, 0xcb, 0x65, 0x0d, 0xac, 0x02,
|
||||
0xbc, 0x51, 0xc6, 0x60, 0xfb, 0xc4, 0x5a, 0xe5, 0x12, 0xdb, 0x16, 0x47, 0x68, 0x20, 0x75, 0x6f,
|
||||
0xa2, 0x34, 0xcd, 0xaf, 0x3a, 0xb4, 0xcb, 0xc7, 0xe5, 0xee, 0xcb, 0x70, 0xc0, 0x66, 0x6b, 0xde,
|
||||
0xee, 0xb1, 0x86, 0x9d, 0xcf, 0xd9, 0xaa, 0x57, 0x7b, 0xac, 0x62, 0x27, 0x7d, 0x5a, 0xf4, 0x69,
|
||||
0x8f, 0x45, 0x57, 0x93, 0xa4, 0xe2, 0xab, 0xde, 0xed, 0xb4, 0x8a, 0x2e, 0x16, 0xf2, 0x82, 0x7e,
|
||||
0xd9, 0x17, 0x0a, 0x11, 0xd7, 0x0c, 0xc1, 0x8d, 0xcf, 0xef, 0x1a, 0xba, 0x8b, 0x24, 0x47, 0x04,
|
||||
0xaf, 0xe5, 0x3e, 0xdf, 0x69, 0x5b, 0x6c, 0x72, 0x53, 0x13, 0xfb, 0x74, 0x0f, 0x09, 0x90, 0x66,
|
||||
0xbe, 0xce, 0xf3, 0xa4, 0xe4, 0x52, 0x5c, 0xec, 0xb1, 0x72, 0x65, 0x51, 0xa5, 0xca, 0xf3, 0xb4,
|
||||
0xfc, 0x8f, 0x7d, 0xeb, 0xf2, 0x9b, 0xd4, 0xfe, 0x7e, 0x5f, 0x5f, 0xa2, 0x9b, 0x91, 0x65, 0x9c,
|
||||
0x67, 0x95, 0x1c, 0xfb, 0xd3, 0x24, 0xbd, 0x59, 0x85, 0xef, 0x9b, 0xac, 0xd3, 0x7d, 0x17, 0xa5,
|
||||
0x8b, 0xa8, 0x4a, 0x02, 0xbf, 0x5b, 0x22, 0x32, 0xe5, 0x32, 0x2a, 0x92, 0x78, 0x58, 0x45, 0xd7,
|
||||
0x95, 0xec, 0xa7, 0xc9, 0x38, 0x1b, 0x04, 0x11, 0xfd, 0xb1, 0xc9, 0x63, 0x4e, 0xcf, 0x37, 0xa3,
|
||||
0xbc, 0xd4, 0xe1, 0x44, 0x3b, 0xeb, 0x90, 0xa4, 0xf0, 0x14, 0x29, 0x45, 0xad, 0x27, 0x91, 0x22,
|
||||
0x9a, 0x45, 0x7e, 0x35, 0xc8, 0x72, 0xf1, 0x55, 0x87, 0xf9, 0x55, 0xe5, 0x07, 0x13, 0x6a, 0xb1,
|
||||
0x06, 0x71, 0x72, 0x1d, 0x85, 0xc3, 0x7a, 0xc6, 0xa1, 0x24, 0xd6, 0xb9, 0xa5, 0xbf, 0x8b, 0x59,
|
||||
0xd6, 0x68, 0xdc, 0x26, 0x71, 0xe1, 0x4f, 0xa3, 0xa5, 0xe8, 0xce, 0x07, 0xd4, 0x9c, 0x0f, 0x47,
|
||||
0x79, 0x11, 0x22, 0xa9, 0xa8, 0xfb, 0x65, 0x97, 0xe1, 0x03, 0x19, 0x50, 0x50, 0xb3, 0x29, 0x01,
|
||||
0xfc, 0xc7, 0x09, 0xef, 0xb6, 0x5c, 0x8c, 0xd9, 0x9f, 0xdb, 0x08, 0xa9, 0x42, 0x96, 0x47, 0x45,
|
||||
0x4a, 0xd3, 0x37, 0xd4, 0x34, 0x75, 0x81, 0xde, 0x71, 0xcf, 0xf4, 0x98, 0x64, 0xb3, 0x79, 0xb5,
|
||||
0xdc, 0x4f, 0xe8, 0x07, 0x7c, 0x63, 0xe3, 0x11, 0xb7, 0xa3, 0x79, 0x55, 0xe5, 0x59, 0xdd, 0xf1,
|
||||
0x6a, 0x66, 0x6f, 0x98, 0x88, 0x0b, 0x23, 0xb4, 0xaf, 0x58, 0xc1, 0x44, 0x82, 0x92, 0x92, 0x50,
|
||||
0xaa, 0xe3, 0x8b, 0xa0, 0x18, 0xe5, 0xd8, 0x74, 0x3a, 0xd0, 0xa0, 0xd3, 0xbf, 0x9b, 0x5f, 0x5e,
|
||||
0xa6, 0x77, 0xe1, 0xb7, 0xda, 0x81, 0xdf, 0xbf, 0x9b, 0x3b, 0x66, 0xa3, 0xdf, 0xd9, 0x1f, 0x18,
|
||||
0x66, 0xf3, 0xe9, 0x28, 0x2a, 0xfe, 0xf8, 0xbb, 0x38, 0xe5, 0x4e, 0x64, 0x44, 0xd3, 0x3a, 0x0d,
|
||||
0x96, 0x7c, 0xff, 0x58, 0xca, 0x57, 0xd1, 0xe8, 0x4b, 0x82, 0xc0, 0x9e, 0x21, 0xe6, 0x30, 0x17,
|
||||
0x44, 0x3c, 0x52, 0x84, 0xcb, 0xcb, 0x26, 0x04, 0x51, 0xef, 0xae, 0x1b, 0xc4, 0x79, 0x30, 0x2f,
|
||||
0x97, 0xf9, 0xbc, 0xa2, 0xc8, 0x1f, 0xdc, 0x87, 0x31, 0x58, 0x6d, 0x5d, 0x82, 0x9f, 0xa8, 0x90,
|
||||
0x8b, 0x79, 0x96, 0xf9, 0xa3, 0x34, 0x92, 0xe1, 0xfd, 0xc1, 0x97, 0x87, 0x8a, 0x75, 0x30, 0x2f,
|
||||
0x4a, 0x08, 0x37, 0xcb, 0x93, 0xed, 0x14, 0x53, 0x93, 0x68, 0x07, 0x6a, 0xd5, 0x04, 0x3a, 0xdc,
|
||||
0xd3, 0xe3, 0x37, 0x11, 0xb6, 0xca, 0xc9, 0xda, 0x56, 0x6d, 0xe7, 0xe8, 0x3e, 0xb7, 0x42, 0x93,
|
||||
0xd3, 0xc7, 0x15, 0xc9, 0x72, 0x3d, 0x7c, 0xfa, 0x5e, 0xce, 0xa7, 0xf9, 0x9f, 0x32, 0x1b, 0xfc,
|
||||
0xb7, 0x54, 0x53, 0x23, 0xf0, 0xbf, 0x56, 0xcb, 0x2e, 0xe2, 0x97, 0xdf, 0x2a, 0x37, 0xcb, 0xa3,
|
||||
0x33, 0xbf, 0xa0, 0xbf, 0xa0, 0xe5, 0x21, 0x20, 0x5a, 0xd1, 0x3a, 0xe0, 0xce, 0xcc, 0x43, 0x4c,
|
||||
0x50, 0xf2, 0x95, 0x51, 0xc9, 0xa3, 0xa2, 0x1e, 0x78, 0xcf, 0x9f, 0x54, 0xae, 0x58, 0x39, 0x87,
|
||||
0xe1, 0xf7, 0x5e, 0xc9, 0xed, 0xb1, 0xb7, 0x56, 0x6b, 0x26, 0xa1, 0x43, 0x02, 0x3b, 0x1b, 0x88,
|
||||
0x33, 0x82, 0x94, 0x84, 0xde, 0x24, 0x4f, 0xa1, 0x8b, 0x7f, 0x21, 0xb3, 0xb0, 0x19, 0x46, 0x95,
|
||||
0xca, 0x77, 0x2f, 0x28, 0xcb, 0xe3, 0x15, 0xfe, 0x51, 0x8f, 0xff, 0x8d, 0x34, 0x35, 0x02, 0x52,
|
||||
0x9e, 0xb1, 0x3f, 0x49, 0x58, 0xff, 0x59, 0xaa, 0x14, 0xd0, 0x6f, 0xfd, 0xde, 0xe7, 0xcf, 0xa8,
|
||||
0x9d, 0x49, 0xf6, 0x99, 0x16, 0x7f, 0xfe, 0xf8, 0xfa, 0xe5, 0x4f, 0xbf, 0x7d, 0xfe, 0x4c, 0x84,
|
||||
0x66, 0x7e, 0x26, 0x30, 0xe8, 0x0f, 0x01, 0x8e, 0x3f, 0xf0, 0x13, 0xa2, 0xa2, 0x28, 0xd8, 0x1c,
|
||||
0x30, 0x42, 0x59, 0x8c, 0x25, 0x46, 0xc7, 0xbb, 0x5b, 0x19, 0xb9, 0xb8, 0xea, 0x4a, 0x0a, 0x75,
|
||||
0x98, 0x2f, 0xa2, 0x22, 0x86, 0xe6, 0x07, 0x93, 0x24, 0x0c, 0x23, 0x1c, 0xc7, 0xa2, 0xa2, 0xc4,
|
||||
0x0a, 0x4f, 0x53, 0x34, 0xe9, 0x7a, 0x9a, 0x66, 0xa5, 0x37, 0xa9, 0xaa, 0xd9, 0xa0, 0xd7, 0xbb,
|
||||
0xba, 0xba, 0x52, 0xae, 0x0c, 0x25, 0x2f, 0xc6, 0x3d, 0x1d, 0x27, 0x98, 0x1e, 0xa8, 0x80, 0x56,
|
||||
0x18, 0xc5, 0xe5, 0xb1, 0xd4, 0xeb, 0x7d, 0x60, 0x4d, 0x08, 0xfd, 0x19, 0x76, 0xa9, 0x04, 0xf9,
|
||||
0xb4, 0x17, 0xa3, 0x11, 0x04, 0x27, 0x37, 0xd3, 0x51, 0x9e, 0x92, 0x5a, 0xd2, 0xac, 0x90, 0x67,
|
||||
0x64, 0x5f, 0x99, 0x5f, 0x2b, 0x48, 0x8b, 0x24, 0xba, 0x7a, 0x95, 0xe3, 0xf4, 0xa8, 0x4a, 0xaa,
|
||||
0xa4, 0xa9, 0xba, 0xc9, 0x1e, 0xad, 0xe3, 0x23, 0xfa, 0x8d, 0x41, 0x0a, 0xbd, 0xd6, 0xcf, 0xa6,
|
||||
0x63, 0x2b, 0xa6, 0x64, 0x6b, 0xa6, 0x62, 0x06, 0x32, 0x9e, 0x9a, 0xe1, 0x48, 0xaa, 0xac, 0x5b,
|
||||
0x8a, 0x2d, 0x6b, 0x9a, 0x62, 0xda, 0x1a, 0xff, 0xa6, 0xc7, 0x42, 0x36, 0x6d, 0x55, 0x71, 0x02,
|
||||
0x75, 0x85, 0xc7, 0x10, 0x74, 0x06, 0x93, 0xd6, 0x58, 0x25, 0x1b, 0x72, 0x90, 0xb4, 0x06, 0x2d,
|
||||
0xc4, 0x52, 0x89, 0x2d, 0x75, 0xe5, 0x1a, 0x7c, 0xb3, 0xfe, 0x4f, 0x30, 0xd6, 0x23, 0xce, 0xee,
|
||||
0xf0, 0xe7, 0xf6, 0x75, 0xac, 0x96, 0xc1, 0xbc, 0x62, 0xf5, 0xc1, 0x9f, 0xe6, 0xba, 0xb2, 0xe1,
|
||||
0x2a, 0xae, 0x69, 0xca, 0x7a, 0x5f, 0x53, 0x2c, 0x03, 0x1b, 0xea, 0x8a, 0xd9, 0x97, 0x81, 0x67,
|
||||
0xe9, 0xce, 0xea, 0x25, 0x26, 0x35, 0xdb, 0x51, 0x5c, 0x7b, 0x35, 0xe2, 0x0b, 0xb0, 0x89, 0x63,
|
||||
0x2a, 0x86, 0x6b, 0x49, 0xba, 0xad, 0x38, 0x16, 0x38, 0xb2, 0xa1, 0x82, 0xbe, 0x23, 0xf5, 0xfb,
|
||||
0x8a, 0xdd, 0xc7, 0xb6, 0x06, 0xb0, 0x5c, 0x53, 0x32, 0x5d, 0x45, 0xb3, 0x64, 0xc0, 0x5c, 0xcd,
|
||||
0x82, 0x54, 0xd8, 0xa8, 0x4f, 0xdc, 0x1b, 0x58, 0x0a, 0x65, 0xba, 0xb6, 0x62, 0xeb, 0xa6, 0xac,
|
||||
0x19, 0xb6, 0x62, 0xa9, 0x9a, 0x84, 0x69, 0xcb, 0x92, 0x4d, 0x45, 0x35, 0x4c, 0x49, 0xef, 0x2b,
|
||||
0x8e, 0x6a, 0x49, 0x86, 0x62, 0x3b, 0x86, 0x84, 0xcd, 0x1c, 0x52, 0x58, 0x5f, 0xd1, 0x0d, 0xb3,
|
||||
0x94, 0xf9, 0x24, 0xc7, 0x90, 0xf9, 0xa4, 0x40, 0x81, 0x8c, 0x24, 0x97, 0x65, 0x49, 0xa6, 0xa6,
|
||||
0xd8, 0x16, 0xf1, 0xd1, 0x57, 0xfa, 0xaa, 0x8e, 0xa5, 0xd0, 0xc0, 0x66, 0x68, 0x68, 0xae, 0xa2,
|
||||
0xea, 0x3a, 0x59, 0xd5, 0x01, 0x51, 0x15, 0x1a, 0x07, 0xa7, 0x3a, 0x78, 0x32, 0x0c, 0x20, 0xd6,
|
||||
0x9f, 0x25, 0x7b, 0xca, 0x0d, 0xb8, 0xcc, 0x9e, 0xcc, 0x92, 0xb6, 0xa2, 0x39, 0x7d, 0xd9, 0xc5,
|
||||
0xb6, 0x16, 0x54, 0xd3, 0x57, 0x8c, 0xbe, 0xa0, 0xa2, 0xc9, 0x9c, 0x08, 0x89, 0x07, 0xb1, 0x74,
|
||||
0x2e, 0x97, 0xac, 0x6b, 0x8a, 0x6e, 0x43, 0xa7, 0x8e, 0xa2, 0x3b, 0x8e, 0x60, 0x5e, 0x16, 0xf2,
|
||||
0x11, 0x86, 0x2e, 0xd0, 0x25, 0xc2, 0x70, 0x05, 0x3a, 0x97, 0xae, 0xcf, 0xd1, 0x2d, 0xa6, 0x63,
|
||||
0x13, 0x36, 0x37, 0x14, 0x8d, 0x71, 0xde, 0x57, 0x4c, 0x28, 0x1e, 0x0a, 0x77, 0x74, 0xae, 0x53,
|
||||
0x03, 0x6f, 0xe8, 0xd4, 0x74, 0x5d, 0xc9, 0x82, 0xdf, 0x68, 0xb6, 0x64, 0xf7, 0x15, 0x4d, 0xe3,
|
||||
0x2b, 0xfb, 0x16, 0x5b, 0xa2, 0x43, 0x0d, 0x62, 0xc8, 0x8d, 0xe5, 0x70, 0x1f, 0x87, 0x87, 0x70,
|
||||
0xdf, 0xa0, 0xbd, 0x20, 0x80, 0xaa, 0x0b, 0xcb, 0x4b, 0xc2, 0x55, 0xb8, 0x73, 0x48, 0xec, 0x65,
|
||||
0x0b, 0xe7, 0x90, 0x9a, 0xce, 0xc1, 0x47, 0x35, 0x7f, 0xec, 0xf1, 0x20, 0x3b, 0xde, 0x8e, 0x36,
|
||||
0xba, 0x32, 0xda, 0x21, 0xca, 0x5c, 0xd7, 0x81, 0x17, 0x3b, 0xd0, 0xa7, 0x3e, 0x91, 0xfb, 0xb6,
|
||||
0xf3, 0x54, 0xa8, 0x95, 0xf7, 0x86, 0xd6, 0x84, 0x56, 0xf2, 0x00, 0x02, 0xa1, 0x4d, 0x9c, 0x69,
|
||||
0x9b, 0x38, 0x2b, 0xe5, 0xda, 0xcc, 0xe3, 0x91, 0xc5, 0x79, 0xb2, 0x6c, 0xe3, 0xff, 0x1d, 0x4f,
|
||||
0x86, 0xda, 0x7f, 0x8c, 0x27, 0xfd, 0x5b, 0x79, 0xd2, 0xbf, 0x89, 0xa7, 0xbe, 0x4d, 0x91, 0x64,
|
||||
0x39, 0x94, 0x20, 0x4d, 0x5d, 0x31, 0x4c, 0x4a, 0x40, 0x34, 0x29, 0x1b, 0xc8, 0x18, 0xe4, 0x4f,
|
||||
0xf4, 0x4d, 0x8f, 0xb2, 0x36, 0x21, 0xad, 0x67, 0x25, 0xbe, 0x01, 0x03, 0x49, 0x1b, 0x50, 0x6d,
|
||||
0x62, 0x83, 0xf6, 0x27, 0xa7, 0xa6, 0x5b, 0x36, 0x97, 0x1c, 0x1e, 0xcf, 0x25, 0x67, 0x02, 0x38,
|
||||
0xd6, 0x86, 0xd3, 0x92, 0x4f, 0x6c, 0x24, 0xda, 0x3c, 0xe4, 0x1a, 0x48, 0xae, 0x4d, 0x6c, 0xd4,
|
||||
0x26, 0x3f, 0x2a, 0xab, 0x28, 0x06, 0xf7, 0xc8, 0xaa, 0x6d, 0x64, 0xc5, 0xbc, 0x40, 0xb8, 0x57,
|
||||
0xe8, 0xf2, 0x5e, 0xa1, 0x91, 0xff, 0xd9, 0x22, 0xf7, 0x51, 0xe9, 0x2d, 0x4d, 0xff, 0x3f, 0x94,
|
||||
0xde, 0xe9, 0xab, 0x4f, 0x4b, 0xff, 0xa4, 0xa5, 0xb5, 0x1d, 0x2d, 0xbd, 0xf6, 0xf1, 0xff, 0x91,
|
||||
0xac, 0x0f, 0xe5, 0xb1, 0x69, 0x4e, 0x97, 0xc4, 0x4f, 0xe6, 0x31, 0x4b, 0x37, 0xc1, 0x34, 0xcd,
|
||||
0x12, 0xd7, 0xaa, 0xa2, 0xf5, 0x5d, 0x62, 0x1b, 0x49, 0xd3, 0xb5, 0x1d, 0xd9, 0x32, 0x91, 0xc1,
|
||||
0x61, 0x5b, 0x0c, 0x55, 0x17, 0xb5, 0xc5, 0x32, 0x50, 0x45, 0x4a, 0xf1, 0x46, 0x51, 0x51, 0x51,
|
||||
0x44, 0x57, 0x23, 0x81, 0x44, 0x25, 0x48, 0xb3, 0x14, 0x1d, 0xc9, 0x1a, 0xe5, 0x41, 0xc7, 0xf6,
|
||||
0xaa, 0x46, 0xb4, 0x6d, 0xc5, 0x75, 0x91, 0xc6, 0xa1, 0x19, 0x0b, 0x85, 0xc2, 0x30, 0x58, 0x39,
|
||||
0x37, 0x51, 0x75, 0x6d, 0xd4, 0x00, 0x83, 0x55, 0x68, 0x07, 0xcd, 0x93, 0x45, 0x35, 0xd9, 0x55,
|
||||
0x0c, 0xdd, 0x62, 0x39, 0xde, 0xd0, 0x0d, 0x09, 0x05, 0x4d, 0xb5, 0x54, 0xaa, 0x48, 0x26, 0xfa,
|
||||
0x06, 0xd4, 0x12, 0xdb, 0x94, 0x2d, 0x4b, 0x31, 0x49, 0x1a, 0xd4, 0x12, 0x13, 0x64, 0x40, 0x5a,
|
||||
0x87, 0xd6, 0x5c, 0x14, 0x16, 0x14, 0x28, 0xc5, 0x45, 0xe5, 0xd6, 0x55, 0x86, 0xa1, 0x2a, 0x86,
|
||||
0x61, 0x53, 0x47, 0xe0, 0xa2, 0xcd, 0x40, 0xfd, 0xd2, 0xf5, 0x12, 0x95, 0x90, 0x2a, 0x37, 0x8a,
|
||||
0x04, 0x4a, 0x95, 0xa1, 0xa8, 0x36, 0x4a, 0xbb, 0x03, 0x2e, 0x11, 0xa1, 0x60, 0x4b, 0xc5, 0x24,
|
||||
0x9a, 0x03, 0x03, 0x2d, 0x8d, 0xe9, 0xa0, 0x76, 0xba, 0x92, 0x06, 0x8d, 0xa3, 0x42, 0xaf, 0x87,
|
||||
0xae, 0xc1, 0x8d, 0x8b, 0x22, 0x85, 0xa2, 0xd4, 0xc7, 0x04, 0xc4, 0x05, 0x9b, 0x06, 0x5e, 0x8d,
|
||||
0x27, 0x2a, 0x9c, 0xa9, 0x99, 0xa4, 0x79, 0xec, 0xdf, 0xef, 0xc3, 0x96, 0x16, 0x76, 0xd0, 0x56,
|
||||
0x3b, 0xf0, 0x0d, 0x1d, 0x70, 0xad, 0xa9, 0x7d, 0xd4, 0x62, 0xa8, 0x80, 0xb8, 0xd6, 0x0c, 0x74,
|
||||
0x13, 0xa6, 0xed, 0x0a, 0xa6, 0x38, 0x87, 0xe4, 0x32, 0x1a, 0xf5, 0x0c, 0x00, 0x9b, 0x4c, 0x0e,
|
||||
0x53, 0x08, 0x15, 0xd0, 0xae, 0x0e, 0xf2, 0x1e, 0x59, 0xa1, 0x6f, 0x50, 0xa1, 0x74, 0x4c, 0x28,
|
||||
0x51, 0x85, 0x0c, 0x8e, 0xd0, 0x8c, 0x2d, 0x14, 0x65, 0x91, 0x12, 0x35, 0xdb, 0x96, 0x4c, 0xf8,
|
||||
0x10, 0x7a, 0x20, 0xa8, 0xc0, 0x42, 0x7c, 0x40, 0x3c, 0x98, 0x66, 0xa5, 0xee, 0x95, 0xfa, 0x5d,
|
||||
0x15, 0x75, 0x13, 0xba, 0x80, 0x8c, 0xae, 0x43, 0xfd, 0x99, 0x62, 0x50, 0x69, 0xdf, 0x32, 0xa4,
|
||||
0x18, 0xff, 0xf9, 0x33, 0xd4, 0x8c, 0x0e, 0xaa, 0x4f, 0xf8, 0x8e, 0x4b, 0xc9, 0x0e, 0xd5, 0xb8,
|
||||
0x6f, 0x6a, 0x64, 0x5b, 0xd7, 0x41, 0x3e, 0x07, 0x15, 0x0d, 0x60, 0x1d, 0x3e, 0xa6, 0xa2, 0x39,
|
||||
0x5b, 0x8d, 0x4d, 0x9d, 0xf6, 0x25, 0x25, 0xe9, 0x36, 0x78, 0x83, 0x85, 0x75, 0xaa, 0xd4, 0x16,
|
||||
0x78, 0x24, 0xaf, 0x68, 0x3c, 0x35, 0xc7, 0x65, 0x8d, 0x95, 0x8a, 0xe4, 0x0d, 0x4d, 0x6a, 0xa6,
|
||||
0x68, 0x03, 0xac, 0xd5, 0x2e, 0xab, 0x5d, 0x65, 0x0b, 0xd3, 0xc4, 0xac, 0x4b, 0x4d, 0x04, 0x9a,
|
||||
0x4c, 0xd2, 0x3b, 0xda, 0x33, 0x97, 0x01, 0x35, 0x34, 0xae, 0x16, 0x48, 0xae, 0x86, 0x78, 0xbb,
|
||||
0xd4, 0x78, 0x21, 0xb2, 0x74, 0xe8, 0x1a, 0xab, 0x55, 0x6a, 0x14, 0x11, 0xe5, 0x60, 0xdd, 0x80,
|
||||
0xd5, 0x90, 0x39, 0xa8, 0x24, 0xb9, 0xe8, 0x78, 0x6c, 0x97, 0xbd, 0xfa, 0x62, 0x92, 0x9a, 0x27,
|
||||
0x72, 0x70, 0x7b, 0x3d, 0xe6, 0x8b, 0x28, 0x99, 0x82, 0x45, 0xcd, 0xd0, 0x60, 0x5d, 0x00, 0x55,
|
||||
0x98, 0x12, 0xdd, 0x4c, 0x93, 0x81, 0x1d, 0x82, 0x38, 0xc8, 0xc7, 0x3b, 0xc4, 0xb0, 0x01, 0x53,
|
||||
0x91, 0x5b, 0xa9, 0x20, 0xd3, 0xb7, 0xac, 0x00, 0x11, 0xa0, 0xa9, 0x14, 0xc6, 0x26, 0xc2, 0xd0,
|
||||
0x91, 0x55, 0xf4, 0x6b, 0xba, 0x6c, 0x93, 0xaf, 0xc9, 0xd4, 0x7a, 0xc9, 0xb0, 0xbe, 0xdb, 0x67,
|
||||
0x99, 0xc5, 0x51, 0x0d, 0xb2, 0xb3, 0x46, 0xf9, 0x1b, 0x76, 0x31, 0xa9, 0xd5, 0x83, 0xc3, 0x20,
|
||||
0xa8, 0x11, 0xf9, 0xba, 0x46, 0x28, 0xae, 0x8e, 0xa4, 0x88, 0xa8, 0x40, 0x43, 0x6e, 0x93, 0x6f,
|
||||
0xea, 0x3a, 0x01, 0x5c, 0xea, 0x8e, 0x29, 0x0f, 0x1a, 0x26, 0xb9, 0x23, 0x9c, 0x19, 0x7a, 0x70,
|
||||
0x75, 0xf8, 0x1d, 0x19, 0xcf, 0x65, 0xed, 0x23, 0xfc, 0x4c, 0x8c, 0xe0, 0xe8, 0xae, 0x4b, 0x1a,
|
||||
0xb6, 0x6c, 0xa6, 0x24, 0x62, 0x80, 0x14, 0x8b, 0xd6, 0xce, 0x6c, 0x3e, 0xe1, 0xdf, 0x3a, 0xe5,
|
||||
0x4d, 0xec, 0xac, 0x92, 0x9f, 0xc2, 0xaa, 0xeb, 0xe5, 0x62, 0x33, 0xbc, 0x34, 0xc3, 0x90, 0xa8,
|
||||
0x4f, 0xa7, 0xee, 0x8e, 0x22, 0x55, 0x02, 0x44, 0x17, 0xec, 0xe8, 0x82, 0x37, 0x24, 0x1e, 0x0d,
|
||||
0x51, 0x45, 0x3e, 0xa5, 0x53, 0xee, 0x37, 0x55, 0x47, 0x76, 0xc8, 0x6b, 0x2c, 0x2e, 0x9b, 0x26,
|
||||
0x44, 0xa5, 0x68, 0x33, 0x0c, 0x83, 0xb6, 0x75, 0x1d, 0x17, 0xd1, 0xe6, 0xc2, 0x59, 0x6d, 0x2a,
|
||||
0x69, 0x92, 0x46, 0x34, 0x98, 0x66, 0xf0, 0x62, 0xed, 0x3b, 0x0e, 0x29, 0x64, 0x6f, 0x83, 0xb9,
|
||||
0x79, 0x1f, 0xfb, 0x23, 0xe8, 0xe8, 0x68, 0x20, 0x46, 0xe8, 0xb9, 0x01, 0x2b, 0x65, 0x16, 0xb9,
|
||||
0x20, 0x67, 0xc8, 0x0c, 0xe0, 0x30, 0x80, 0xa9, 0x06, 0x44, 0xa4, 0xcf, 0x62, 0x5d, 0xef, 0x53,
|
||||
0x48, 0x21, 0xc7, 0xea, 0x24, 0xb3, 0x6d, 0x38, 0xb2, 0xc6, 0x05, 0x62, 0xc4, 0xfa, 0x92, 0xb0,
|
||||
0x0d, 0xb7, 0x94, 0x24, 0x6c, 0xc3, 0x2d, 0x25, 0x35, 0xd8, 0x47, 0x80, 0x71, 0xe3, 0x30, 0x4b,
|
||||
0x49, 0xdc, 0x3a, 0xcc, 0x52, 0x12, 0xb7, 0x0e, 0x57, 0x87, 0xc4, 0xcc, 0x63, 0x30, 0x53, 0xb1,
|
||||
0xd6, 0x1d, 0x49, 0x8f, 0xeb, 0x53, 0x62, 0xda, 0x5d, 0x0d, 0xb8, 0x81, 0x44, 0xdb, 0xbd, 0x32,
|
||||
0x94, 0x54, 0x33, 0x11, 0x1d, 0xd5, 0xc8, 0x48, 0xb6, 0xcc, 0x6d, 0xc3, 0x0c, 0x45, 0x41, 0xb4,
|
||||
0x31, 0xb4, 0xcc, 0xd5, 0xc6, 0xec, 0x84, 0x00, 0x81, 0x69, 0x74, 0x66, 0x27, 0x93, 0x82, 0xa1,
|
||||
0xe6, 0x36, 0xcc, 0x36, 0xdc, 0x50, 0x36, 0xcb, 0x42, 0x14, 0xd1, 0xdc, 0x52, 0x52, 0xc3, 0x0d,
|
||||
0x35, 0xe2, 0xce, 0xa5, 0x88, 0x84, 0xa5, 0x58, 0xde, 0x23, 0xeb, 0x90, 0xa5, 0xa4, 0x95, 0xba,
|
||||
0x6c, 0xfe, 0x32, 0x49, 0xcd, 0xb4, 0x71, 0x5f, 0x65, 0x09, 0x71, 0x6d, 0x29, 0x64, 0x59, 0x66,
|
||||
0x02, 0x31, 0x2a, 0x61, 0x1a, 0x6e, 0x24, 0x36, 0x0f, 0xf5, 0x73, 0x0b, 0x06, 0x20, 0xe7, 0x30,
|
||||
0x2b, 0x69, 0x94, 0x6b, 0x6d, 0xd3, 0xe2, 0x56, 0xb2, 0x38, 0x21, 0x97, 0x5b, 0xc9, 0x95, 0x84,
|
||||
0x5d, 0x98, 0x95, 0x74, 0x89, 0xec, 0x62, 0x09, 0x23, 0x09, 0xce, 0x0d, 0x69, 0xc5, 0xb9, 0xc6,
|
||||
0x92, 0x0b, 0x33, 0x12, 0xb1, 0x89, 0x52, 0xc0, 0x8c, 0xa4, 0x3a, 0x5c, 0x19, 0x92, 0x70, 0x5a,
|
||||
0x32, 0x8c, 0xce, 0xad, 0x64, 0x33, 0x6d, 0x22, 0xa3, 0x33, 0x3b, 0xf5, 0x57, 0xa3, 0x55, 0x10,
|
||||
0xad, 0x6c, 0x54, 0xb7, 0x4d, 0xf3, 0xc9, 0xec, 0x43, 0x59, 0x92, 0xdb, 0x86, 0x19, 0x4a, 0x2c,
|
||||
0x17, 0x86, 0x92, 0x98, 0x71, 0x1c, 0x6e, 0x29, 0x89, 0x1b, 0x87, 0x59, 0x4a, 0xf0, 0x63, 0x0a,
|
||||
0xe6, 0x98, 0x6d, 0x6c, 0x61, 0x29, 0xc9, 0xe4, 0x59, 0x95, 0x5b, 0x8a, 0x0b, 0xb8, 0x32, 0x94,
|
||||
0xc4, 0x4d, 0xc3, 0x83, 0x08, 0x76, 0x72, 0xa1, 0x59, 0x6e, 0x27, 0xe1, 0xd8, 0xc2, 0x52, 0xb2,
|
||||
0xb0, 0x0d, 0xb7, 0x94, 0x08, 0x0f, 0x61, 0x29, 0xb9, 0x61, 0xa9, 0x52, 0xd8, 0x07, 0xc7, 0xea,
|
||||
0xda, 0x3c, 0xce, 0xd3, 0x3c, 0x86, 0x24, 0xb2, 0x94, 0xc4, 0x43, 0x48, 0xe2, 0x21, 0x24, 0xd5,
|
||||
0x29, 0xb9, 0x22, 0xbd, 0x09, 0x53, 0x89, 0xf4, 0xc6, 0x4d, 0x25, 0x37, 0x58, 0x67, 0xd9, 0xcd,
|
||||
0xe2, 0x86, 0xb2, 0x64, 0x61, 0x1b, 0x6e, 0x29, 0xb9, 0xa6, 0x0c, 0x5d, 0x16, 0xc6, 0x61, 0x96,
|
||||
0x92, 0x1b, 0xb6, 0x91, 0xff, 0x5d, 0xda, 0x15, 0xf5, 0xc6, 0x6d, 0x23, 0xe1, 0xbf, 0x42, 0xdc,
|
||||
0xbd, 0xf4, 0x80, 0xca, 0x15, 0x29, 0x91, 0xa2, 0x8a, 0x34, 0x40, 0x93, 0xbb, 0xb4, 0x05, 0x2e,
|
||||
0x81, 0x11, 0x07, 0xd7, 0xdc, 0xd3, 0x61, 0x23, 0x3b, 0x89, 0x91, 0x8d, 0x6d, 0x58, 0x4e, 0xda,
|
||||
0xe4, 0xd7, 0xdf, 0x7c, 0xdf, 0x8c, 0x76, 0x25, 0xed, 0xca, 0x51, 0x93, 0x07, 0xef, 0x2e, 0x2d,
|
||||
0x69, 0x48, 0x0e, 0x67, 0x86, 0x33, 0xdf, 0x8c, 0xa4, 0x11, 0x73, 0xa5, 0x35, 0x28, 0x91, 0x69,
|
||||
0xcc, 0xd8, 0xda, 0xd9, 0x12, 0x95, 0xce, 0x2c, 0x9d, 0xae, 0x8d, 0x59, 0xbb, 0xe9, 0x42, 0x9b,
|
||||
0x48, 0x63, 0xa1, 0x92, 0x1a, 0xb8, 0x61, 0xa1, 0x38, 0x9c, 0x41, 0xbd, 0x6d, 0x6d, 0x74, 0xa5,
|
||||
0x0a, 0x5b, 0x1b, 0x5d, 0xa9, 0x9d, 0x89, 0x30, 0x63, 0x1e, 0x48, 0x17, 0x2b, 0x95, 0xcc, 0xc4,
|
||||
0xe9, 0x4a, 0x15, 0x63, 0xe1, 0x6e, 0xd4, 0xc2, 0x65, 0x5b, 0x29, 0xb5, 0x70, 0x71, 0x6c, 0xc8,
|
||||
0x06, 0x6d, 0xc9, 0x7d, 0x01, 0xcc, 0x43, 0x6d, 0xdd, 0x44, 0xbd, 0xc4, 0x91, 0x92, 0x98, 0x1d,
|
||||
0x6e, 0xa5, 0x81, 0x29, 0x1c, 0xb0, 0x4c, 0x19, 0xbe, 0x9a, 0x8c, 0x14, 0xfb, 0x04, 0x1b, 0x9f,
|
||||
0x9f, 0x4a, 0x68, 0x60, 0x0e, 0x7a, 0x04, 0x42, 0x11, 0x69, 0x7a, 0x64, 0xcf, 0x14, 0x0d, 0xaa,
|
||||
0x82, 0x62, 0x52, 0xe2, 0x4b, 0xb5, 0x5e, 0x9c, 0x37, 0xd9, 0x9c, 0x21, 0xac, 0x00, 0x13, 0x1a,
|
||||
0x59, 0x85, 0x00, 0xc1, 0x91, 0x88, 0xbf, 0x24, 0x74, 0x91, 0x1b, 0x42, 0x09, 0xa1, 0xd5, 0xbd,
|
||||
0xa7, 0x4e, 0x45, 0x14, 0xff, 0x84, 0xa6, 0xb0, 0x6c, 0x70, 0x7a, 0x2d, 0x9b, 0x34, 0xdc, 0xbb,
|
||||
0x26, 0x5a, 0x43, 0x76, 0x79, 0x9f, 0x83, 0xa2, 0x46, 0xa9, 0x15, 0x47, 0x07, 0x0e, 0x61, 0x4d,
|
||||
0x6f, 0x16, 0xfe, 0x52, 0x85, 0x7d, 0x5b, 0x7f, 0x37, 0x70, 0xd0, 0x54, 0x9f, 0x80, 0x6e, 0x04,
|
||||
0x76, 0xc6, 0xcb, 0xbd, 0x03, 0xad, 0x4c, 0xb9, 0x6f, 0x68, 0xca, 0x1a, 0xe1, 0x70, 0x90, 0xab,
|
||||
0x2a, 0xd0, 0x4f, 0x29, 0x38, 0x1b, 0x8d, 0x8d, 0xad, 0x86, 0x77, 0x04, 0xe6, 0x07, 0x48, 0x12,
|
||||
0x66, 0x24, 0x2e, 0x9a, 0xcc, 0x45, 0x2c, 0xb8, 0xb5, 0x74, 0xba, 0x12, 0x8f, 0xa8, 0x86, 0x2a,
|
||||
0x33, 0xbc, 0xcd, 0x7e, 0x38, 0xda, 0xe9, 0xfc, 0x0b, 0x63, 0x86, 0xce, 0xbf, 0x20, 0x37, 0x52,
|
||||
0x31, 0xed, 0x51, 0x19, 0xe0, 0xc0, 0x8d, 0xa0, 0x0c, 0xa8, 0x75, 0xd0, 0x03, 0x03, 0xb4, 0x61,
|
||||
0x4c, 0x50, 0x1f, 0x3f, 0x15, 0x63, 0x66, 0x18, 0x1b, 0xd4, 0xf0, 0x0b, 0x23, 0x38, 0xff, 0xc2,
|
||||
0x98, 0x31, 0x22, 0x35, 0xcc, 0xbf, 0x30, 0x6e, 0x28, 0x03, 0x0a, 0xe5, 0xc6, 0x74, 0x6d, 0x94,
|
||||
0x01, 0x4e, 0xb9, 0xa1, 0xf3, 0x77, 0xd3, 0xf9, 0x5b, 0xb3, 0x1f, 0x18, 0x50, 0x0c, 0xfc, 0x50,
|
||||
0x69, 0x30, 0x6e, 0x75, 0xc6, 0x01, 0x78, 0xc4, 0x58, 0x52, 0x8a, 0x83, 0x23, 0x3b, 0x6a, 0xeb,
|
||||
0xd2, 0x16, 0x40, 0x19, 0xe0, 0xc8, 0x8d, 0xc8, 0x51, 0x33, 0x08, 0x29, 0x9b, 0x60, 0x0d, 0x5b,
|
||||
0xcf, 0xd2, 0x29, 0x27, 0x8c, 0x03, 0x53, 0x41, 0xd0, 0xdf, 0x8d, 0x79, 0x57, 0xca, 0x81, 0x22,
|
||||
0xb0, 0x33, 0xe3, 0x80, 0xb2, 0x83, 0x0c, 0xa8, 0x1c, 0xd9, 0x51, 0x2b, 0x03, 0x9c, 0x71, 0xc3,
|
||||
0x46, 0x63, 0x63, 0x23, 0x03, 0x1c, 0xb9, 0x61, 0x02, 0xde, 0xb8, 0x09, 0x3b, 0xdc, 0x20, 0x0e,
|
||||
0xc5, 0xa0, 0x0d, 0xaa, 0x1c, 0xc5, 0xe4, 0x70, 0xd3, 0x71, 0xfe, 0xa6, 0x1b, 0xce, 0xd4, 0xc1,
|
||||
0xb8, 0x31, 0xed, 0x51, 0x19, 0xa0, 0xca, 0xa1, 0x0c, 0xa8, 0x8b, 0x31, 0x03, 0xac, 0x31, 0x88,
|
||||
0x83, 0xce, 0xd9, 0x8d, 0x99, 0x61, 0x9f, 0x6a, 0xc2, 0xca, 0xb6, 0x50, 0x75, 0x30, 0x66, 0xa8,
|
||||
0x3a, 0x18, 0x2f, 0x75, 0xfe, 0xa6, 0x1c, 0xc6, 0x00, 0x55, 0x0e, 0x37, 0x5d, 0x1b, 0x65, 0x80,
|
||||
0x2a, 0x87, 0x9b, 0xa8, 0xc3, 0x30, 0x7f, 0x6b, 0x1e, 0x8b, 0xf1, 0x61, 0x41, 0x52, 0x92, 0x80,
|
||||
0xa6, 0xfb, 0xb2, 0x10, 0xf7, 0xcb, 0x4a, 0xbe, 0x30, 0xcf, 0x45, 0x39, 0x50, 0xd3, 0x55, 0x63,
|
||||
0x39, 0xba, 0x2f, 0x5b, 0xfc, 0x7e, 0x69, 0xb7, 0xee, 0xbe, 0xe8, 0x71, 0xf5, 0x8b, 0xee, 0xf2,
|
||||
0x8a, 0x00, 0xe2, 0xed, 0xc5, 0xe6, 0x76, 0x0d, 0x9c, 0x39, 0x01, 0xe5, 0xb1, 0xb5, 0x12, 0x4e,
|
||||
0x3f, 0x89, 0xb2, 0xa5, 0x78, 0xca, 0x08, 0xf6, 0x26, 0xc0, 0xc2, 0x88, 0xa0, 0xe5, 0x84, 0x2c,
|
||||
0xde, 0x74, 0x38, 0xc1, 0x06, 0x08, 0x44, 0x39, 0xcb, 0x8e, 0xa0, 0xb8, 0x79, 0x90, 0xe5, 0xf2,
|
||||
0x01, 0x4e, 0xad, 0x97, 0x78, 0x83, 0xdc, 0x4b, 0xb5, 0xb8, 0xc1, 0xb2, 0xb9, 0x62, 0xb3, 0x44,
|
||||
0x60, 0x8b, 0x6f, 0xd9, 0xa5, 0x12, 0x02, 0x8a, 0x40, 0xc0, 0xdf, 0xe7, 0x9d, 0x15, 0xa9, 0x24,
|
||||
0x2c, 0xcd, 0xb2, 0x1b, 0xc8, 0x35, 0x4d, 0x44, 0x1c, 0xcf, 0x60, 0x49, 0xf6, 0x85, 0xa1, 0x19,
|
||||
0x2a, 0x19, 0x55, 0x26, 0xab, 0x6b, 0xdd, 0x03, 0xbc, 0xc4, 0xcc, 0x11, 0x11, 0xa6, 0xf4, 0x05,
|
||||
0xa7, 0x43, 0x3e, 0xed, 0x37, 0xc4, 0x50, 0xd4, 0x10, 0x53, 0xae, 0x08, 0x16, 0x42, 0x31, 0xb0,
|
||||
0xd5, 0x47, 0xc4, 0xa0, 0x1e, 0x0a, 0xd2, 0x8a, 0xd3, 0x25, 0xbb, 0x6a, 0x88, 0x9e, 0xbe, 0x44,
|
||||
0x43, 0x3d, 0xad, 0xc5, 0x50, 0xd4, 0x70, 0x50, 0x2a, 0x84, 0xf0, 0x51, 0x7c, 0x4d, 0xd9, 0xd6,
|
||||
0x52, 0x39, 0xec, 0x04, 0x40, 0x60, 0xa2, 0xb8, 0x84, 0x12, 0xc9, 0x9a, 0x49, 0x4f, 0x08, 0x01,
|
||||
0x1a, 0x64, 0x0a, 0xec, 0xc4, 0x3a, 0x29, 0x6e, 0x22, 0x4a, 0x51, 0x37, 0x4e, 0x42, 0xe7, 0x2c,
|
||||
0xfe, 0xbe, 0x75, 0xa7, 0xbd, 0x97, 0xbb, 0xa6, 0x4d, 0xa3, 0xd4, 0xa1, 0x0f, 0xd3, 0x71, 0xa3,
|
||||
0xe9, 0xc8, 0x31, 0xd1, 0x17, 0xc4, 0x9e, 0xe8, 0x19, 0x46, 0x20, 0x66, 0xba, 0xce, 0xca, 0x13,
|
||||
0x67, 0x3c, 0x41, 0xe8, 0x8f, 0x7c, 0x47, 0x12, 0xad, 0x8e, 0xe2, 0xf7, 0xc3, 0xb7, 0x80, 0xeb,
|
||||
0x2c, 0x2b, 0x5b, 0xa7, 0x81, 0xd9, 0x6e, 0x60, 0xb6, 0x87, 0x25, 0x80, 0xcb, 0x56, 0x8a, 0x96,
|
||||
0x32, 0x2d, 0x51, 0xd2, 0x75, 0x00, 0x7a, 0xde, 0xc0, 0xac, 0xe9, 0x4a, 0xba, 0x61, 0x25, 0x2b,
|
||||
0xf8, 0x3b, 0x62, 0xfb, 0x11, 0x2b, 0x6a, 0x14, 0x41, 0x51, 0x50, 0xb9, 0xd0, 0xc6, 0xe7, 0xa7,
|
||||
0x36, 0x05, 0xe8, 0x47, 0x47, 0xd1, 0x68, 0x33, 0xd4, 0x31, 0xc0, 0x41, 0x83, 0xff, 0x96, 0x7c,
|
||||
0x6d, 0x0d, 0xfd, 0x84, 0x7d, 0x89, 0x10, 0x1c, 0x4e, 0xbb, 0x12, 0x27, 0x21, 0xc0, 0x91, 0x90,
|
||||
0xfd, 0x2a, 0x20, 0xcd, 0x20, 0xff, 0xaf, 0x64, 0xb8, 0x95, 0x4c, 0x19, 0x8e, 0x9b, 0x44, 0xd3,
|
||||
0xd9, 0x33, 0x74, 0x17, 0xeb, 0x02, 0x30, 0x48, 0x0c, 0xe2, 0x49, 0x8a, 0xc2, 0x25, 0xf1, 0x30,
|
||||
0xe8, 0x8f, 0x0b, 0x5f, 0xe0, 0xe5, 0x89, 0xad, 0x8c, 0x50, 0x98, 0xf6, 0xa4, 0xca, 0x20, 0x5d,
|
||||
0x01, 0x12, 0x01, 0x52, 0x07, 0xe6, 0xd9, 0xc9, 0xc5, 0x70, 0xb2, 0x84, 0xcd, 0x70, 0xd1, 0x11,
|
||||
0xd7, 0x07, 0xc0, 0xc7, 0xda, 0xb1, 0xcc, 0x1f, 0x51, 0x40, 0xbd, 0x6b, 0x0f, 0x03, 0x29, 0x87,
|
||||
0x79, 0x15, 0x9c, 0x4f, 0xd2, 0xf9, 0x4c, 0x3e, 0x73, 0x83, 0x0c, 0x0c, 0x37, 0x4c, 0xb1, 0x6f,
|
||||
0x31, 0x21, 0x11, 0xd2, 0x00, 0xd0, 0x6a, 0x2b, 0x65, 0x71, 0x25, 0xac, 0x6f, 0xc1, 0x52, 0x40,
|
||||
0x7d, 0xe2, 0x24, 0x01, 0x78, 0x94, 0x51, 0x21, 0xad, 0x22, 0x04, 0x22, 0x80, 0x8c, 0x5a, 0x61,
|
||||
0x1b, 0xb6, 0x24, 0xa0, 0x2c, 0x11, 0x68, 0xc0, 0x53, 0x8d, 0xde, 0x8e, 0x15, 0x7a, 0xac, 0x43,
|
||||
0x3e, 0xa6, 0x8e, 0x09, 0x09, 0xad, 0x4a, 0x36, 0x5d, 0xe0, 0x31, 0x1e, 0x7d, 0x59, 0x1f, 0xd6,
|
||||
0xe7, 0xd0, 0x5e, 0x61, 0x32, 0xfa, 0xbb, 0xcd, 0xed, 0x0a, 0x8b, 0xd1, 0x08, 0x61, 0x64, 0x68,
|
||||
0xf6, 0x36, 0xa3, 0x8c, 0xb4, 0x19, 0x08, 0xf7, 0x3c, 0x13, 0x4b, 0x22, 0x1b, 0x21, 0x8a, 0x77,
|
||||
0x89, 0x70, 0x64, 0x2b, 0x3a, 0xd9, 0xd2, 0x7b, 0x45, 0x82, 0xaa, 0xf5, 0x61, 0x68, 0x3b, 0x6b,
|
||||
0xc3, 0xa5, 0x01, 0xbd, 0x9a, 0xbb, 0xbd, 0xb0, 0xd8, 0x7b, 0xa6, 0x9f, 0x90, 0xb0, 0x68, 0x80,
|
||||
0x9e, 0x08, 0xd1, 0xe4, 0x81, 0x45, 0xb4, 0xb2, 0x4b, 0x89, 0xd0, 0x34, 0xf4, 0xbe, 0x4b, 0xf4,
|
||||
0x16, 0x4f, 0x40, 0x57, 0xf8, 0x08, 0x7c, 0x22, 0xca, 0x35, 0xed, 0x56, 0xb4, 0x92, 0xb9, 0xad,
|
||||
0x16, 0x03, 0x03, 0x1b, 0xe4, 0x1c, 0x09, 0xfa, 0xf4, 0x3b, 0x76, 0x12, 0xf9, 0x34, 0x42, 0x46,
|
||||
0x3f, 0x5b, 0x6e, 0x38, 0x1e, 0x0d, 0xe0, 0x24, 0xa1, 0xa1, 0x8a, 0xb7, 0xbe, 0xee, 0x3d, 0x6c,
|
||||
0x4f, 0x50, 0x84, 0x2d, 0x10, 0x9c, 0x63, 0xc6, 0xab, 0xae, 0xf2, 0x16, 0x94, 0x31, 0x1d, 0x74,
|
||||
0x14, 0xa1, 0xb6, 0x01, 0x07, 0x43, 0x4d, 0xe8, 0xb0, 0xab, 0xe9, 0x64, 0x67, 0x62, 0x7a, 0x58,
|
||||
0x59, 0x22, 0xc2, 0xb0, 0x35, 0xc2, 0x2c, 0x4c, 0x85, 0xad, 0xde, 0xc3, 0xc2, 0x06, 0x71, 0x4d,
|
||||
0xa0, 0xb6, 0x7a, 0xc8, 0xe9, 0xa1, 0xad, 0xd2, 0x73, 0x46, 0xcf, 0x59, 0x6f, 0x4e, 0x7b, 0xeb,
|
||||
0x5a, 0x0d, 0xe2, 0xc4, 0xc9, 0xa6, 0x8c, 0x84, 0x1a, 0x91, 0x7d, 0x05, 0xdf, 0x0c, 0x43, 0x54,
|
||||
0xe7, 0x3a, 0xf7, 0x0a, 0x73, 0x81, 0x95, 0x55, 0xa5, 0xf3, 0x72, 0x3a, 0xaf, 0xed, 0xc0, 0x0f,
|
||||
0x67, 0xfc, 0x70, 0xca, 0x2e, 0x67, 0xec, 0xea, 0xc0, 0x6a, 0x20, 0x57, 0x00, 0xea, 0xa8, 0xdf,
|
||||
0x50, 0x25, 0x78, 0x76, 0xe4, 0xb1, 0x53, 0x1e, 0xcb, 0x9a, 0xd7, 0x1e, 0x71, 0xb8, 0x27, 0xca,
|
||||
0x90, 0x24, 0x40, 0x11, 0x53, 0x52, 0x11, 0x22, 0x11, 0xb5, 0xe3, 0x6f, 0xdd, 0x25, 0x81, 0x89,
|
||||
0x23, 0x04, 0x41, 0xf2, 0x26, 0xc3, 0xef, 0x97, 0xa1, 0x53, 0xf5, 0x20, 0x20, 0xa4, 0x20, 0x02,
|
||||
0x02, 0x83, 0x53, 0x03, 0xb9, 0x0c, 0x90, 0xa1, 0x04, 0x24, 0x20, 0x46, 0xac, 0x44, 0x44, 0x9c,
|
||||
0x23, 0xe6, 0xe4, 0xa4, 0xd2, 0xe0, 0x4b, 0x4e, 0x81, 0xa9, 0xc0, 0x82, 0x61, 0xe7, 0x6c, 0x10,
|
||||
0xd1, 0x09, 0xb7, 0x24, 0x90, 0xda, 0x7a, 0xd8, 0x5f, 0xa6, 0x00, 0xf5, 0x3b, 0xc0, 0x50, 0x56,
|
||||
0x1e, 0x38, 0xb3, 0x08, 0x0a, 0x44, 0xac, 0xcc, 0x25, 0x28, 0xd5, 0x04, 0x63, 0xe1, 0x6f, 0x0a,
|
||||
0x91, 0x86, 0x1e, 0x74, 0x82, 0x77, 0x8d, 0x90, 0x71, 0x4b, 0xc0, 0x50, 0xe4, 0x5d, 0x54, 0xab,
|
||||
0x84, 0x58, 0x0f, 0x6d, 0x67, 0x6d, 0x84, 0x37, 0x89, 0x3d, 0x57, 0xe8, 0xab, 0x04, 0xb3, 0x18,
|
||||
0x57, 0x67, 0xa5, 0xe3, 0x06, 0x3a, 0xd6, 0xbd, 0xd3, 0xee, 0x9d, 0x8e, 0xaa, 0xb6, 0xef, 0xd4,
|
||||
0x45, 0x73, 0x4c, 0x81, 0xd7, 0x8a, 0x24, 0x88, 0x53, 0xc9, 0xc5, 0x8f, 0x9c, 0x92, 0xb3, 0x29,
|
||||
0x19, 0x1f, 0x9c, 0xf1, 0xc1, 0x29, 0x9b, 0x80, 0x11, 0x90, 0x4d, 0x9d, 0x74, 0x15, 0x10, 0xbb,
|
||||
0x97, 0x19, 0x44, 0x10, 0x54, 0x93, 0x9d, 0xc6, 0x5b, 0x6d, 0xac, 0x41, 0x1a, 0x6f, 0xaf, 0xfb,
|
||||
0x7e, 0x4d, 0xbe, 0xa0, 0x56, 0xf7, 0x34, 0x56, 0x62, 0xe9, 0xb6, 0x21, 0x8b, 0xdc, 0xb4, 0x40,
|
||||
0x73, 0xf1, 0x0d, 0xb9, 0x04, 0x56, 0xcc, 0x4f, 0xa7, 0xbf, 0xe1, 0xda, 0x95, 0xd8, 0x03, 0xaa,
|
||||
0x44, 0x56, 0xb6, 0x44, 0x8f, 0xf5, 0x53, 0x8f, 0x59, 0x83, 0xc7, 0x65, 0xb3, 0xde, 0x1a, 0x31,
|
||||
0xe0, 0xdf, 0x13, 0xe2, 0xc3, 0xff, 0xbb, 0x62, 0xdf, 0xcb, 0x31, 0x1a, 0xb0, 0x42, 0x6c, 0xba,
|
||||
0xd1, 0x79, 0x6e, 0x18, 0x87, 0xd3, 0x73, 0xb6, 0xd3, 0x4e, 0xf2, 0xbc, 0xd3, 0x6e, 0x44, 0xa2,
|
||||
0x39, 0x4a, 0x42, 0x58, 0x20, 0x22, 0x8e, 0x89, 0x7a, 0xd1, 0x43, 0xac, 0x59, 0xdd, 0x32, 0xab,
|
||||
0x00, 0x41, 0x61, 0xa3, 0xf7, 0x95, 0x4a, 0x11, 0xb3, 0xde, 0x7a, 0xa4, 0xc0, 0x91, 0x76, 0x3b,
|
||||
0xed, 0x35, 0xbb, 0x79, 0xef, 0x4a, 0x78, 0x4f, 0x5e, 0x5c, 0x90, 0x11, 0x7d, 0xbf, 0x48, 0xdf,
|
||||
0x2b, 0xfd, 0x6e, 0x3c, 0xf3, 0x63, 0xeb, 0x50, 0x6d, 0x67, 0x5c, 0xcd, 0x2b, 0x44, 0x64, 0x73,
|
||||
0x7b, 0x7b, 0xfd, 0x07, 0x8b, 0x84, 0x8b, 0xee, 0xf2, 0xb6, 0xdb, 0x5e, 0xac, 0x10, 0x17, 0xc3,
|
||||
0xce, 0x99, 0xf2, 0x10, 0x95, 0xe9, 0x46, 0x18, 0x3a, 0x32, 0x1c, 0x53, 0xf0, 0xdc, 0x19, 0x78,
|
||||
0x3e, 0xb4, 0x7b, 0x03, 0xe4, 0x1d, 0x01, 0xf9, 0x68, 0x87, 0x51, 0x5e, 0xa0, 0xa7, 0x0f, 0xdf,
|
||||
0x4a, 0x66, 0xdf, 0x1e, 0x80, 0x7b, 0xbb, 0x4c, 0xa9, 0xb4, 0x07, 0xbd, 0x4c, 0x2f, 0x0b, 0xc5,
|
||||
0x94, 0x7c, 0x28, 0x86, 0xeb, 0x26, 0xe9, 0x80, 0xbc, 0x4b, 0x07, 0xec, 0x4e, 0x9b, 0x4c, 0x22,
|
||||
0xec, 0x32, 0x00, 0x76, 0xd9, 0x30, 0x87, 0x59, 0x2f, 0x9f, 0x27, 0x2e, 0xb7, 0x65, 0x92, 0x4a,
|
||||
0x4d, 0x1c, 0x15, 0xe3, 0x8c, 0x52, 0xc1, 0xcf, 0xde, 0xfe, 0x57, 0x8c, 0xfe, 0xa7, 0x9f, 0xe2,
|
||||
0x00, 0xd8, 0xc5, 0xda, 0x76, 0xe3, 0x13, 0x95, 0x44, 0xbf, 0x94, 0xa1, 0x3a, 0x16, 0x4e, 0x79,
|
||||
0x19, 0x16, 0xd1, 0x53, 0x4f, 0x08, 0x70, 0x1b, 0xc4, 0x3f, 0x14, 0x5e, 0xe1, 0x93, 0x62, 0x15,
|
||||
0x4d, 0xbd, 0x47, 0x8a, 0x97, 0x07, 0x8d, 0x28, 0xdd, 0x5e, 0xf5, 0x4d, 0xf0, 0xe6, 0x5a, 0x23,
|
||||
0xc6, 0x15, 0x79, 0x1e, 0x38, 0xa6, 0x09, 0xf9, 0xc2, 0xf4, 0x36, 0x06, 0x66, 0x90, 0xba, 0xa1,
|
||||
0x2e, 0xe0, 0xde, 0x92, 0x83, 0x79, 0x81, 0xd1, 0xdb, 0xc2, 0x2e, 0xdf, 0x1a, 0x39, 0x67, 0xe4,
|
||||
0xbb, 0xfd, 0x48, 0xe2, 0xf1, 0x91, 0x14, 0x35, 0x47, 0xc9, 0xcf, 0x82, 0x4a, 0xd6, 0x50, 0xaf,
|
||||
0x12, 0x8c, 0x38, 0x94, 0x91, 0x8d, 0xbe, 0x18, 0x6b, 0x99, 0x1d, 0x2a, 0x1a, 0xb2, 0xa6, 0x18,
|
||||
0xf3, 0x46, 0xf6, 0x01, 0xb3, 0x42, 0xf2, 0x83, 0x5d, 0x05, 0xd5, 0x36, 0xff, 0x17, 0x94, 0x8b,
|
||||
0x25, 0xef, 0xeb, 0xb5, 0x2b, 0xc3, 0x67, 0x47, 0x3c, 0x60, 0xda, 0x55, 0x4c, 0xd4, 0x6b, 0x29,
|
||||
0x37, 0xb5, 0x53, 0xaf, 0x62, 0xaa, 0x5f, 0x33, 0x05, 0xa8, 0x8b, 0x99, 0x7e, 0xcd, 0x14, 0x28,
|
||||
0xb9, 0xa9, 0x7e, 0xcd, 0xd4, 0x2f, 0xcf, 0xd4, 0x32, 0xcc, 0xd4, 0x37, 0xb8, 0xa9, 0x7e, 0xcd,
|
||||
0x94, 0x3f, 0xb8, 0x99, 0x7e, 0xcd, 0x14, 0x28, 0x17, 0x53, 0xfd, 0x2a, 0xee, 0xd5, 0xaf, 0x99,
|
||||
0x8e, 0x1c, 0x51, 0xa6, 0xfe, 0x50, 0x6d, 0x4c, 0xbf, 0xa6, 0xba, 0x79, 0x24, 0xdb, 0xdb, 0x1f,
|
||||
0xd1, 0xd7, 0x65, 0xfd, 0x6a, 0x72, 0xa2, 0x74, 0x0d, 0xfa, 0x35, 0x15, 0xa2, 0x91, 0x86, 0x8d,
|
||||
0xb7, 0xb6, 0xbc, 0xdb, 0x1e, 0x47, 0x9b, 0x6b, 0x53, 0x1c, 0xd7, 0xb0, 0xb9, 0x82, 0x0d, 0x2a,
|
||||
0x32, 0x2b, 0xbd, 0x71, 0xa3, 0x72, 0xa0, 0x7d, 0x59, 0xc2, 0xb8, 0xa4, 0x46, 0x35, 0x6c, 0x50,
|
||||
0xb0, 0x62, 0xae, 0x61, 0xa3, 0xa1, 0xc4, 0xe3, 0x43, 0x71, 0x23, 0x15, 0x73, 0x63, 0x15, 0x73,
|
||||
0x13, 0x15, 0x9b, 0xef, 0x63, 0x7b, 0x0d, 0x1b, 0xf3, 0x66, 0xd0, 0x2f, 0xf7, 0x55, 0xfa, 0x75,
|
||||
0x7b, 0xdd, 0xbd, 0xbb, 0x58, 0x83, 0x84, 0x24, 0xc4, 0x81, 0x4e, 0x8b, 0x1b, 0x8b, 0x46, 0x64,
|
||||
0x8c, 0x05, 0x11, 0x48, 0x06, 0xc4, 0x86, 0x59, 0x46, 0xcf, 0x0c, 0x51, 0xee, 0xf7, 0x4d, 0x67,
|
||||
0xff, 0xc2, 0xb7, 0xd3, 0x7f, 0xbb, 0xe1, 0xdf, 0xfb, 0xe6, 0x70, 0xc6, 0x67, 0xeb, 0x82, 0x25,
|
||||
0x41, 0x93, 0xa2, 0x94, 0x83, 0xc2, 0x9b, 0x7e, 0x5e, 0x6e, 0x73, 0x4f, 0x0d, 0xca, 0x41, 0xed,
|
||||
0x12, 0x3f, 0x8e, 0x49, 0x20, 0x56, 0x15, 0xc9, 0x28, 0xd6, 0x7c, 0x24, 0x96, 0xdb, 0x95, 0x0c,
|
||||
0x3f, 0x59, 0x3b, 0x81, 0x18, 0x8b, 0xbe, 0x44, 0x52, 0x5f, 0x02, 0x41, 0xa7, 0x04, 0x52, 0xfa,
|
||||
0x29, 0x51, 0x40, 0x8c, 0x1a, 0x79, 0x06, 0x89, 0xc1, 0xda, 0x48, 0x07, 0x4c, 0x3c, 0xcf, 0x26,
|
||||
0x33, 0x92, 0x0a, 0x48, 0x21, 0xd4, 0x99, 0x22, 0x02, 0x42, 0x55, 0xd0, 0x92, 0xbf, 0x80, 0xa2,
|
||||
0x44, 0x58, 0x98, 0xa1, 0xdd, 0x9c, 0x64, 0x40, 0x4c, 0xc8, 0xfc, 0xb4, 0xa8, 0xa9, 0x40, 0xb9,
|
||||
0x09, 0x40, 0x8e, 0x98, 0x92, 0xab, 0xa2, 0x96, 0x88, 0x34, 0x84, 0xa1, 0x86, 0x2f, 0x71, 0xac,
|
||||
0xbd, 0x38, 0x3e, 0x35, 0xcb, 0x34, 0x2b, 0x91, 0x18, 0x91, 0xd4, 0x56, 0xab, 0x40, 0x35, 0x95,
|
||||
0xd2, 0x30, 0xea, 0x2e, 0x80, 0x77, 0x78, 0xa4, 0xef, 0xc4, 0x2e, 0x64, 0x09, 0x0e, 0xab, 0xa0,
|
||||
0xb5, 0x38, 0xa8, 0x44, 0xc9, 0x94, 0xb2, 0x8c, 0x72, 0x40, 0xa6, 0x31, 0xc4, 0xf5, 0xf6, 0xf8,
|
||||
0x8d, 0x44, 0x81, 0x4c, 0x00, 0xe5, 0x0c, 0xf8, 0xfd, 0xf9, 0x69, 0xa8, 0x51, 0x24, 0x82, 0xc0,
|
||||
0x5d, 0xfa, 0x8b, 0x08, 0xb2, 0x23, 0xbe, 0x2d, 0xab, 0xdf, 0x6a, 0x9a, 0xb5, 0x2e, 0x44, 0x95,
|
||||
0x43, 0x0e, 0x28, 0x17, 0x09, 0x15, 0x53, 0xb7, 0x48, 0x7a, 0xd4, 0x12, 0x5e, 0x10, 0xf1, 0x0a,
|
||||
0x88, 0xfd, 0x4a, 0x8d, 0x20, 0x64, 0xc5, 0x23, 0xb3, 0x1e, 0x88, 0xf5, 0x1a, 0xe0, 0x8c, 0x55,
|
||||
0x64, 0x56, 0x14, 0x91, 0x1f, 0x00, 0x0a, 0x04, 0x34, 0xf0, 0xf0, 0xc1, 0x8c, 0x84, 0xf0, 0x41,
|
||||
0x62, 0x9d, 0x8a, 0xde, 0x6c, 0xac, 0xc1, 0xd2, 0xa2, 0x6a, 0x08, 0x60, 0x37, 0x25, 0xb1, 0xb7,
|
||||
0x94, 0x18, 0x39, 0x0a, 0x3b, 0x1a, 0x24, 0x0f, 0x6b, 0x2d, 0x04, 0x55, 0x34, 0x4d, 0x86, 0xde,
|
||||
0x60, 0x25, 0x2b, 0x9a, 0xf4, 0x93, 0x94, 0x83, 0x22, 0x21, 0xd2, 0x81, 0xac, 0x0a, 0x4c, 0x25,
|
||||
0x62, 0x86, 0x34, 0x7c, 0x21, 0xa9, 0x04, 0xfc, 0xa7, 0x84, 0x7a, 0x22, 0xeb, 0x83, 0xec, 0x10,
|
||||
0x1b, 0xcb, 0xf5, 0x7c, 0x48, 0x65, 0xa3, 0xde, 0xb4, 0x56, 0x63, 0x22, 0x73, 0x8d, 0x09, 0x4c,
|
||||
0x89, 0x80, 0x08, 0xa5, 0xd9, 0x4a, 0xc8, 0x2a, 0x43, 0x44, 0xa4, 0x9e, 0x03, 0x95, 0xb6, 0x4a,
|
||||
0x9a, 0xe5, 0x96, 0xd9, 0x10, 0x80, 0xcf, 0x84, 0xa1, 0x83, 0xc7, 0xa5, 0x59, 0x17, 0x2b, 0x33,
|
||||
0xbe, 0x64, 0xc4, 0x1c, 0xd4, 0x35, 0x2d, 0x59, 0x76, 0x1a, 0x10, 0x02, 0x23, 0x94, 0x67, 0x22,
|
||||
0x04, 0x85, 0xb9, 0x59, 0xa2, 0x43, 0x40, 0x6b, 0x72, 0x0c, 0x55, 0xa1, 0x05, 0xea, 0x42, 0x50,
|
||||
0x34, 0x5a, 0xb2, 0x36, 0x18, 0x89, 0x31, 0x44, 0xd5, 0xb2, 0x46, 0x28, 0x0a, 0x40, 0x08, 0xa6,
|
||||
0x25, 0xc1, 0x2c, 0xf7, 0x42, 0xe0, 0x9c, 0x6c, 0x3f, 0x03, 0x12, 0xc4, 0x8a, 0x97, 0x92, 0xc1,
|
||||
0x1b, 0x10, 0xb2, 0x44, 0x59, 0x06, 0x7e, 0x26, 0x26, 0x0e, 0x40, 0x98, 0xc3, 0x90, 0x5b, 0x08,
|
||||
0x56, 0x59, 0xa1, 0x2e, 0x86, 0x20, 0x13, 0xb2, 0x37, 0xd0, 0x22, 0xa6, 0x0d, 0x91, 0x8c, 0x47,
|
||||
0xb0, 0x85, 0x81, 0x66, 0x8f, 0xb0, 0x10, 0x80, 0x31, 0xf0, 0x7a, 0x56, 0x30, 0x30, 0xc9, 0xcb,
|
||||
0x59, 0xb6, 0x27, 0x4d, 0x84, 0x57, 0x0f, 0x48, 0x08, 0xc9, 0xc4, 0x36, 0x58, 0x43, 0xa6, 0xa4,
|
||||
0x38, 0x65, 0x65, 0x88, 0xba, 0x16, 0xdb, 0x96, 0x09, 0x7a, 0x87, 0xf0, 0xbb, 0x44, 0x88, 0x8f,
|
||||
0x42, 0x8e, 0x9a, 0xa0, 0xba, 0x57, 0x80, 0xa8, 0x25, 0x93, 0x6b, 0x44, 0xe2, 0x0d, 0x52, 0x93,
|
||||
0xb4, 0x1f, 0xc4, 0x4e, 0x6a, 0x24, 0x79, 0x1a, 0x4d, 0x4d, 0x06, 0x56, 0x40, 0xf9, 0xa8, 0x1a,
|
||||
0x29, 0x8a, 0x48, 0x4c, 0x2c, 0x31, 0x1c, 0xaf, 0x29, 0xef, 0x4e, 0x26, 0x0e, 0x68, 0x5e, 0x84,
|
||||
0x94, 0x29, 0x2d, 0x19, 0x9a, 0xc8, 0x3a, 0xb8, 0x83, 0x12, 0xdb, 0xc0, 0x14, 0xa2, 0x7d, 0xa1,
|
||||
0x2e, 0x4c, 0x02, 0x5a, 0x60, 0x84, 0xd5, 0x70, 0x4a, 0xd0, 0x2b, 0x58, 0x26, 0x5d, 0xb3, 0x78,
|
||||
0x0a, 0x09, 0x52, 0xec, 0x1a, 0x48, 0x7f, 0xb3, 0xac, 0x57, 0xbb, 0x0d, 0x36, 0x0a, 0xcf, 0x94,
|
||||
0x88, 0x96, 0x54, 0x34, 0x62, 0x42, 0x64, 0xf4, 0x29, 0x27, 0xcc, 0x85, 0x59, 0x80, 0x06, 0x59,
|
||||
0x00, 0x4c, 0xac, 0x42, 0x5a, 0x3c, 0x8b, 0x82, 0xf0, 0x13, 0xc2, 0x81, 0xe2, 0x2c, 0xe0, 0x24,
|
||||
0x28, 0x88, 0x93, 0x21, 0x5b, 0x0a, 0xa7, 0xc4, 0x0e, 0x13, 0x91, 0x31, 0xcd, 0x4c, 0x98, 0x36,
|
||||
0x0d, 0x33, 0x8f, 0x15, 0xcb, 0xa9, 0x1a, 0x74, 0xab, 0x2d, 0x85, 0x30, 0x4b, 0xa7, 0x0a, 0x22,
|
||||
0x8a, 0xd4, 0x70, 0x57, 0xaa, 0x59, 0xa5, 0xd0, 0x94, 0x44, 0x31, 0x91, 0x4d, 0x93, 0x21, 0xb6,
|
||||
0x2e, 0x13, 0xec, 0xa9, 0x01, 0x49, 0xef, 0x96, 0x7c, 0x10, 0x81, 0x3a, 0x11, 0xa1, 0xae, 0x1a,
|
||||
0xfa, 0x3b, 0xa2, 0xa7, 0x09, 0xd6, 0x32, 0x6a, 0xb6, 0xc3, 0x84, 0x49, 0x85, 0x8b, 0xf9, 0x3f,
|
||||
0x11, 0xf4, 0x3a, 0x02, 0x25, 0x07, 0xcc, 0x82, 0xca, 0x8f, 0xb6, 0x84, 0x68, 0x0e, 0x12, 0xaa,
|
||||
0x02, 0x5b, 0x69, 0xc4, 0x0e, 0x34, 0x0a, 0x55, 0xae, 0xb2, 0xbe, 0xc8, 0x9d, 0x4b, 0x6c, 0x06,
|
||||
0x88, 0x45, 0x65, 0x3e, 0x68, 0x5e, 0x34, 0xd5, 0x34, 0x0f, 0xb1, 0xe1, 0x6a, 0x01, 0xc7, 0x85,
|
||||
0x70, 0x00, 0x0f, 0x00, 0x98, 0xa2, 0xaa, 0x54, 0xed, 0x54, 0x4b, 0x14, 0x05, 0x63, 0x85, 0x21,
|
||||
0x4a, 0xb0, 0x55, 0x89, 0xf5, 0xee, 0x01, 0x94, 0x65, 0x7d, 0xac, 0x69, 0x3a, 0xfb, 0x51, 0x8b,
|
||||
0x6d, 0xb5, 0xc4, 0xf0, 0xa9, 0x8f, 0x2d, 0x83, 0x59, 0xb1, 0xf5, 0xb0, 0xac, 0x9d, 0x44, 0xfe,
|
||||
0xa8, 0x13, 0x83, 0x05, 0x52, 0x93, 0x95, 0x6b, 0x82, 0xa8, 0xf4, 0x01, 0xcb, 0x46, 0x51, 0x09,
|
||||
0x98, 0xc4, 0x8a, 0x89, 0xc6, 0x20, 0x93, 0x8f, 0x9a, 0xcb, 0x01, 0xa6, 0x0e, 0xfc, 0xc3, 0x7b,
|
||||
0x82, 0x7b, 0x31, 0xd1, 0x96, 0x7b, 0x61, 0x4a, 0x14, 0xb1, 0x89, 0x2d, 0xeb, 0xce, 0x2a, 0x45,
|
||||
0x6e, 0xc0, 0xbe, 0x44, 0x20, 0x2b, 0xcb, 0xfc, 0x51, 0x2b, 0x5e, 0x11, 0x6a, 0x4f, 0x0d, 0xb2,
|
||||
0xc5, 0x01, 0xc5, 0x57, 0x2e, 0x0b, 0x0b, 0x64, 0xbb, 0xe9, 0x64, 0x12, 0x8d, 0xb8, 0x7c, 0x58,
|
||||
0xa4, 0x08, 0x26, 0xd1, 0x11, 0xf1, 0xdc, 0x17, 0x71, 0x85, 0x57, 0x02, 0xa8, 0x1d, 0x90, 0xf1,
|
||||
0xe0, 0x96, 0x00, 0x96, 0xc6, 0x43, 0x33, 0x98, 0x02, 0xaf, 0x54, 0x15, 0x30, 0x0c, 0xec, 0xd4,
|
||||
0xc2, 0xe4, 0x96, 0x15, 0x45, 0x80, 0x94, 0x33, 0x0b, 0x81, 0x50, 0xc9, 0x58, 0x81, 0xc9, 0x28,
|
||||
0x16, 0x6e, 0x39, 0x3b, 0x00, 0xfa, 0x98, 0x6d, 0xe5, 0xe3, 0xe7, 0xa7, 0x4d, 0xc3, 0xe2, 0x2a,
|
||||
0x17, 0x31, 0x43, 0x00, 0x43, 0x80, 0x5f, 0xc5, 0x28, 0x8a, 0x3f, 0xde, 0x42, 0x07, 0x80, 0x29,
|
||||
0x52, 0x26, 0x22, 0xb7, 0x3f, 0x60, 0xca, 0x50, 0xb4, 0xa1, 0x5d, 0x92, 0xbf, 0xc8, 0x1a, 0xc9,
|
||||
0xfa, 0x7a, 0xe8, 0x77, 0x05, 0x7b, 0x85, 0xc2, 0x02, 0x16, 0x02, 0x12, 0xc2, 0x6e, 0xe0, 0x3a,
|
||||
0x54, 0x5c, 0x53, 0xd1, 0x65, 0x58, 0x73, 0x99, 0x4c, 0xf2, 0x19, 0x88, 0x2f, 0xd2, 0xcc, 0x91,
|
||||
0x59, 0x1a, 0x61, 0x0c, 0x3a, 0xe0, 0x27, 0x2a, 0x95, 0x70, 0xb6, 0x68, 0x85, 0xee, 0x2a, 0x38,
|
||||
0x81, 0x67, 0x73, 0x27, 0x68, 0x81, 0xee, 0xa3, 0xd8, 0x3f, 0x0e, 0xbd, 0x48, 0x9f, 0x8d, 0x90,
|
||||
0xda, 0xb7, 0x50, 0xbb, 0x55, 0x2a, 0xec, 0x89, 0x28, 0xdd, 0x04, 0x2c, 0x31, 0x5f, 0xac, 0x83,
|
||||
0x6f, 0x46, 0x93, 0x09, 0xcc, 0xa7, 0x7b, 0xec, 0x66, 0xd0, 0x4f, 0xb1, 0x06, 0x11, 0x05, 0x55,
|
||||
0x40, 0xf2, 0x51, 0x5f, 0x24, 0x3b, 0x46, 0x86, 0xa3, 0x5e, 0x06, 0xea, 0x77, 0x24, 0xae, 0xc9,
|
||||
0x8d, 0x55, 0x7c, 0x94, 0x1a, 0x9b, 0xb4, 0xec, 0xee, 0x0a, 0xc3, 0xe9, 0x39, 0xbb, 0x6b, 0xd6,
|
||||
0xa0, 0xd5, 0x9f, 0xae, 0xba, 0x2f, 0x78, 0x75, 0x72, 0x26, 0x9f, 0xcd, 0xa5, 0xe1, 0xad, 0x84,
|
||||
0x12, 0x34, 0xc9, 0x35, 0x98, 0xd9, 0x9a, 0xcb, 0xfd, 0x05, 0x44, 0x4a, 0x56, 0x3f, 0x57, 0x94,
|
||||
0x66, 0xf9, 0x42, 0x79, 0x1d, 0x92, 0x57, 0x25, 0x90, 0x53, 0x6e, 0x44, 0x2d, 0x6e, 0x33, 0x28,
|
||||
0x51, 0xd4, 0xc5, 0xdc, 0x80, 0x08, 0xac, 0x48, 0x91, 0xe8, 0x0e, 0x73, 0xf0, 0xb2, 0x15, 0xe9,
|
||||
0x97, 0xf8, 0x4d, 0xb9, 0xd4, 0x9c, 0x09, 0x53, 0x4d, 0x44, 0x5e, 0x40, 0x48, 0x5b, 0xd0, 0xdb,
|
||||
0xc0, 0xed, 0x14, 0x66, 0x58, 0x78, 0x02, 0xb3, 0x82, 0x8c, 0x79, 0x82, 0x8b, 0x08, 0xec, 0x31,
|
||||
0xb3, 0x82, 0x33, 0x69, 0x26, 0xca, 0xc2, 0xd1, 0x13, 0xbd, 0xeb, 0x04, 0x95, 0x6b, 0x30, 0x72,
|
||||
0x89, 0xb5, 0x24, 0xb1, 0x6d, 0xf4, 0x84, 0xec, 0xf4, 0xec, 0xe1, 0x0c, 0x9c, 0xad, 0xc7, 0x0b,
|
||||
0x3b, 0x1b, 0xc4, 0x31, 0x84, 0x06, 0xb0, 0x30, 0xef, 0x3c, 0xa1, 0x67, 0x80, 0x21, 0x24, 0xdc,
|
||||
0xe4, 0xc2, 0x64, 0xcc, 0xae, 0xed, 0x5b, 0x8d, 0xe8, 0x50, 0x80, 0x19, 0xb4, 0xac, 0x0c, 0x9b,
|
||||
0x23, 0x7d, 0x36, 0xad, 0x49, 0xad, 0x60, 0xcb, 0x7d, 0x4b, 0x96, 0x45, 0x99, 0xaa, 0x7e, 0xad,
|
||||
0x60, 0xf2, 0x04, 0x34, 0x3c, 0x16, 0x4c, 0xc4, 0xed, 0x38, 0x6b, 0xfa, 0x8d, 0x00, 0xd9, 0x76,
|
||||
0x94, 0x45, 0x5d, 0x02, 0xcb, 0xe2, 0x0e, 0x2c, 0x9b, 0xfb, 0x41, 0x26, 0x50, 0x41, 0x63, 0xf0,
|
||||
0xc4, 0xe2, 0x65, 0xb1, 0xa4, 0x4c, 0x97, 0xb2, 0xc6, 0x0f, 0xde, 0x31, 0x38, 0x5f, 0xc1, 0x9a,
|
||||
0xd8, 0x32, 0x21, 0x32, 0xd5, 0x95, 0x21, 0xe7, 0xe1, 0x6c, 0x54, 0x08, 0x08, 0xc8, 0x7a, 0xc8,
|
||||
0x06, 0x59, 0xef, 0x94, 0xd5, 0x28, 0xd4, 0xd5, 0x3c, 0xd8, 0xd0, 0x56, 0xd6, 0x13, 0xc0, 0x8b,
|
||||
0xda, 0x81, 0xb1, 0xbe, 0x30, 0xd6, 0x17, 0x64, 0x7d, 0xf0, 0x5b, 0x65, 0xb9, 0x33, 0xce, 0x8b,
|
||||
0xff, 0x38, 0x02, 0x28, 0xdb, 0x31, 0x40, 0xd9, 0x2e, 0x03, 0x94, 0xdd, 0x18, 0xf7, 0x1c, 0xaf,
|
||||
0xda, 0x08, 0x40, 0x1c, 0xb3, 0xf0, 0xcb, 0x90, 0xec, 0x76, 0x9c, 0x0d, 0x5f, 0x81, 0xae, 0xf6,
|
||||
0xd6, 0x6e, 0x07, 0xef, 0x51, 0xa9, 0x50, 0x05, 0x4d, 0x1f, 0x3b, 0xe8, 0xa1, 0x53, 0x3d, 0xe4,
|
||||
0x3e, 0xd7, 0xa2, 0x94, 0x80, 0x7a, 0x18, 0x9c, 0x29, 0xa2, 0x53, 0x45, 0xe4, 0x7d, 0x45, 0xac,
|
||||
0x34, 0x6f, 0x74, 0xab, 0xa5, 0x26, 0xd6, 0x4e, 0x75, 0xcf, 0xa9, 0x26, 0x86, 0xa1, 0x39, 0xa8,
|
||||
0xa2, 0x53, 0x55, 0x2c, 0x54, 0x13, 0x9d, 0x69, 0x62, 0x61, 0x9a, 0x48, 0xdd, 0xca, 0xba, 0xdc,
|
||||
0x1e, 0xba, 0x85, 0x7b, 0xa3, 0x74, 0xb9, 0x75, 0x85, 0xb9, 0xde, 0x6b, 0x62, 0x53, 0x3e, 0x63,
|
||||
0xe7, 0xfd, 0xe6, 0xf6, 0xdd, 0x7a, 0xe4, 0x47, 0xc1, 0x0d, 0x2b, 0xdb, 0x5f, 0x57, 0xc0, 0x5c,
|
||||
0xf7, 0xb3, 0xa2, 0xe5, 0x7a, 0x06, 0x0c, 0x25, 0x94, 0xee, 0x93, 0x56, 0x35, 0x20, 0x42, 0x53,
|
||||
0xf0, 0x72, 0x77, 0x62, 0xaf, 0x04, 0xaa, 0x39, 0x22, 0x34, 0xb4, 0xbb, 0xdd, 0x90, 0xdc, 0xfd,
|
||||
0x10, 0x6e, 0xbf, 0x0a, 0xc2, 0xad, 0xdd, 0x14, 0xe4, 0xd9, 0x1d, 0x1e, 0x00, 0x2f, 0xa7, 0x35,
|
||||
0xd9, 0x33, 0x22, 0x73, 0x3c, 0xeb, 0xf3, 0x9e, 0x6b, 0x10, 0xc1, 0xaf, 0x87, 0x4d, 0x17, 0x51,
|
||||
0xda, 0x45, 0x90, 0xf6, 0x58, 0x24, 0x05, 0xdf, 0xa3, 0xa9, 0x39, 0x94, 0xc4, 0x38, 0xa7, 0x3c,
|
||||
0x80, 0x1a, 0xf7, 0x09, 0x83, 0x71, 0x11, 0xcb, 0xd4, 0x9a, 0x1e, 0xd5, 0xce, 0x23, 0xa9, 0x8f,
|
||||
0x62, 0xa6, 0x49, 0x28, 0xac, 0xa1, 0xc1, 0xb4, 0xef, 0xca, 0xca, 0x19, 0xf4, 0x3b, 0x77, 0x87,
|
||||
0xba, 0x39, 0xa6, 0x30, 0xc5, 0x7a, 0xf3, 0x51, 0x84, 0x35, 0x6e, 0x69, 0x9b, 0xea, 0xe1, 0x56,
|
||||
0x2b, 0xcb, 0x97, 0x14, 0xa3, 0x7c, 0x49, 0x31, 0xce, 0x97, 0xac, 0x46, 0x49, 0xcf, 0xaf, 0xff,
|
||||
0xb8, 0xfa, 0xab, 0x20, 0x69, 0x92, 0x90, 0x13, 0x37, 0x02, 0xe6, 0x59, 0x0a, 0x62, 0x56, 0xc7,
|
||||
0x3f, 0x93, 0x9d, 0xdc, 0x17, 0x53, 0x4d, 0x98, 0xab, 0xcc, 0x92, 0x2a, 0xed, 0x55, 0xcd, 0xc0,
|
||||
0xd1, 0x09, 0xc4, 0x9a, 0x67, 0x10, 0x6b, 0x98, 0x41, 0xac, 0x61, 0x0a, 0xb1, 0xd6, 0x33, 0x88,
|
||||
0x35, 0xcc, 0x20, 0xd6, 0x74, 0xf0, 0xff, 0x29, 0xc4, 0xda, 0x4c, 0x21, 0xd6, 0x5d, 0xaa, 0x02,
|
||||
0xc9, 0x59, 0x91, 0x66, 0xa6, 0xf2, 0x44, 0xf7, 0x27, 0xb7, 0xb3, 0x1c, 0x02, 0xa1, 0xfd, 0x12,
|
||||
0xfe, 0xd9, 0x0d, 0x77, 0xc2, 0x2c, 0xe2, 0xa0, 0xfd, 0xa2, 0x7a, 0x1c, 0x2d, 0xe8, 0x2a, 0x6b,
|
||||
0x6e, 0x48, 0xb9, 0x62, 0x91, 0xd8, 0x41, 0x06, 0x42, 0xe5, 0x3a, 0x1e, 0x4f, 0x6c, 0x8d, 0xb4,
|
||||
0x62, 0x01, 0x41, 0x3d, 0x00, 0x32, 0x3f, 0xee, 0x00, 0xd2, 0xe1, 0x3e, 0xe8, 0x83, 0x3b, 0x25,
|
||||
0xf5, 0xd6, 0xc4, 0x11, 0x6c, 0x3a, 0xba, 0x41, 0xf1, 0xe3, 0x04, 0x20, 0xf5, 0x2c, 0x59, 0x22,
|
||||
0xfd, 0x35, 0x68, 0xee, 0x38, 0x07, 0x61, 0xc8, 0x28, 0x61, 0xd2, 0x62, 0x0c, 0x93, 0xf6, 0xb6,
|
||||
0x41, 0x57, 0xa6, 0x2b, 0xdc, 0x6f, 0x78, 0x44, 0x79, 0xe3, 0xf6, 0xbc, 0x81, 0x7b, 0xe1, 0x0c,
|
||||
0x1d, 0xf5, 0xd4, 0x43, 0x8f, 0xbb, 0x68, 0x8f, 0xaa, 0xd6, 0x0f, 0x7a, 0x13, 0xfa, 0x03, 0xde,
|
||||
0x92, 0xfe, 0xe0, 0xfc, 0xf2, 0x23, 0xb4, 0xec, 0xee, 0xd5, 0x23, 0xbb, 0x4d, 0x1e, 0x8f, 0x06,
|
||||
0xc2, 0xc3, 0xb4, 0xec, 0xce, 0x78, 0x1c, 0x7b, 0xf3, 0xca, 0x5d, 0x5f, 0x75, 0xdb, 0xcb, 0xee,
|
||||
0xdd, 0x4f, 0x7c, 0xec, 0xeb, 0xc3, 0x07, 0x1f, 0xfa, 0x0b, 0xf7, 0x27, 0x5e, 0x3d, 0xf6, 0x23,
|
||||
0x5f, 0x2a, 0xf6, 0xf7, 0xf9, 0xfd, 0xea, 0xd2, 0x9f, 0x9c, 0xf2, 0xf0, 0x81, 0xdd, 0xf6, 0x6e,
|
||||
0x84, 0xde, 0x9f, 0x8f, 0x09, 0xf1, 0x71, 0xa9, 0xc7, 0x49, 0xe1, 0x66, 0xdc, 0xe3, 0x24, 0x6e,
|
||||
0xfa, 0x3d, 0x89, 0xc7, 0xff, 0xf9, 0x2e, 0x2c, 0x10, 0x60, 0xfd, 0xdb, 0x71, 0x0a, 0xaf, 0xff,
|
||||
0x9c, 0x50, 0xa8, 0x16, 0x28, 0xa0, 0x1c, 0xe6, 0x38, 0x81, 0xab, 0xed, 0x84, 0x40, 0xbd, 0x40,
|
||||
0x00, 0x37, 0xe2, 0x2d, 0x10, 0xe8, 0xc7, 0x6c, 0x78, 0xb6, 0xc4, 0x04, 0x84, 0x38, 0xc7, 0x09,
|
||||
0xf4, 0x77, 0x63, 0x02, 0x67, 0x4b, 0x04, 0xba, 0xeb, 0x37, 0x93, 0xeb, 0x65, 0xe5, 0x2f, 0x3f,
|
||||
0xee, 0x56, 0xbc, 0x3b, 0x1f, 0x56, 0x7c, 0x78, 0x7c, 0xda, 0xc3, 0x07, 0x78, 0xe4, 0x0f, 0x79,
|
||||
0x24, 0xdf, 0xff, 0xeb, 0xf4, 0xd5, 0x73, 0x8f, 0x5f, 0x4b, 0xc7, 0xaf, 0x6e, 0x77, 0xd7, 0xf5,
|
||||
0xdb, 0x9f, 0xed, 0xba, 0x1e, 0xd2, 0xc4, 0xa7, 0x45, 0xb8, 0xfd, 0xd3, 0x22, 0x1c, 0xdf, 0x1e,
|
||||
0xf7, 0xd3, 0x23, 0xa6, 0xb4, 0xae, 0x2e, 0xfa, 0x7e, 0x38, 0xf9, 0xbc, 0x57, 0x7a, 0x67, 0x3f,
|
||||
0xdb, 0x33, 0xec, 0x4a, 0xf7, 0xfe, 0xf2, 0x0a, 0x9f, 0x9b, 0x3f, 0xf1, 0x50, 0x7e, 0xd7, 0xdf,
|
||||
0x5d, 0xdc, 0xfc, 0xe4, 0x31, 0x31, 0x7d, 0x8f, 0x16, 0x1e, 0x4b, 0x3f, 0x1b, 0x33, 0x9e, 0x7c,
|
||||
0x3e, 0x1a, 0xc8, 0xf3, 0x15, 0x03, 0xf9, 0xdb, 0xf3, 0x8b, 0x73, 0xc7, 0x37, 0x61, 0xfc, 0xed,
|
||||
0x60, 0x24, 0xcf, 0xbf, 0x61, 0x24, 0xdb, 0x5f, 0xd6, 0x74, 0xfe, 0x0b, 0x1e, 0xf0, 0xb5, 0xd4,
|
||||
0xfd, 0x2f, 0xdf, 0xd2, 0xfd, 0xa3, 0x35, 0xdd, 0x3f, 0x12, 0xf2, 0x4b, 0xbd, 0x3f, 0xfa, 0x8a,
|
||||
0xde, 0xa7, 0x63, 0x78, 0xdb, 0x8f, 0xc6, 0xf3, 0xeb, 0x8a, 0xf1, 0xfc, 0x2a, 0xa3, 0x99, 0x0f,
|
||||
0xe3, 0xd7, 0x23, 0xc3, 0xf0, 0x3a, 0x88, 0xf2, 0xa4, 0x0c, 0x71, 0x34, 0x10, 0x7b, 0xf9, 0xc3,
|
||||
0x01, 0x2b, 0xce, 0x56, 0x74, 0x7d, 0xb6, 0xb9, 0xfb, 0x70, 0xbb, 0xe1, 0x13, 0x14, 0xe7, 0x23,
|
||||
0x38, 0xfb, 0xea, 0x11, 0xcc, 0xc6, 0xf1, 0xfb, 0x9a, 0x25, 0xf9, 0x1d, 0xcf, 0x41, 0x5b, 0x5a,
|
||||
0x93, 0xdf, 0xbf, 0x5e, 0x22, 0xee, 0xb6, 0x2f, 0x47, 0x06, 0x5c, 0xec, 0xfb, 0xbf, 0xf8, 0x20,
|
||||
0x49, 0x77, 0xba, 0xb9, 0xba, 0xd8, 0x52, 0x7f, 0xe5, 0x6f, 0x6f, 0x04, 0xdf, 0xdf, 0xee, 0x2c,
|
||||
0x08, 0x1f, 0xb4, 0x5d, 0xb4, 0xed, 0x92, 0x15, 0x41, 0x85, 0xd0, 0x82, 0x29, 0xbd, 0x9e, 0x53,
|
||||
0xf1, 0x0b, 0x44, 0x0e, 0x6a, 0x48, 0x16, 0x08, 0xbe, 0x7f, 0x3d, 0x25, 0x78, 0x3f, 0xbd, 0x71,
|
||||
0xda, 0x7c, 0x69, 0x84, 0x33, 0x82, 0x8b, 0xd3, 0xd4, 0x44, 0xe1, 0xd4, 0x5e, 0xee, 0xb9, 0xc6,
|
||||
0xc7, 0x71, 0xe9, 0x22, 0xbd, 0x78, 0x39, 0x5a, 0x87, 0x97, 0x58, 0x07, 0x7b, 0xe0, 0xe6, 0xf8,
|
||||
0xd1, 0x32, 0xf6, 0x2f, 0x6c, 0xb2, 0xbc, 0x74, 0x4f, 0xeb, 0xec, 0xe2, 0xce, 0xf5, 0x17, 0xdd,
|
||||
0xf5, 0xd5, 0xf9, 0xe6, 0xf6, 0x93, 0xd3, 0x37, 0x7a, 0xde, 0x5d, 0x8b, 0x85, 0xe5, 0x13, 0xca,
|
||||
0x54, 0x60, 0xec, 0xf7, 0x6e, 0x93, 0x39, 0xfb, 0xae, 0xfc, 0xc7, 0x43, 0x0a, 0xce, 0x83, 0x1f,
|
||||
0xf4, 0xd8, 0xc3, 0x2f, 0x5d, 0x20, 0x8c, 0x7b, 0x84, 0x87, 0xd9, 0xad, 0xbe, 0x40, 0x76, 0xd2,
|
||||
0xe7, 0x7c, 0x0b, 0xe2, 0xea, 0x2b, 0x64, 0xe7, 0x3c, 0xbd, 0xbd, 0x94, 0xf8, 0xf5, 0xd3, 0xea,
|
||||
0x4b, 0x64, 0xaf, 0x3c, 0xfb, 0x63, 0x73, 0xe3, 0x4e, 0x7f, 0x38, 0xdb, 0x5f, 0x23, 0x0c, 0xf8,
|
||||
0xc2, 0x65, 0x51, 0x2e, 0x13, 0xb6, 0x59, 0x6f, 0x60, 0xd7, 0x6c, 0xa8, 0x83, 0x12, 0xbc, 0xbe,
|
||||
0x79, 0xa9, 0x9b, 0xd5, 0x93, 0x4d, 0x7f, 0x87, 0x37, 0x9a, 0x9e, 0xea, 0xb3, 0x55, 0x8f, 0xaf,
|
||||
0xe4, 0x93, 0xd3, 0xd1, 0x4a, 0x9e, 0xae, 0x5e, 0xc9, 0x99, 0xd6, 0xbf, 0x5c, 0xa3, 0xf5, 0xa6,
|
||||
0x8c, 0x67, 0x37, 0x17, 0x17, 0xe7, 0x87, 0x6a, 0xff, 0x72, 0xad, 0xda, 0xbf, 0x3c, 0x62, 0xfd,
|
||||
0x7e, 0xfb, 0x0b, 0xfd, 0xe3, 0xcd, 0x9b, 0x57, 0xfd, 0xe5, 0xdd, 0xa7, 0x83, 0x31, 0xfc, 0xf6,
|
||||
0x35, 0x63, 0x98, 0x19, 0xa0, 0xd3, 0xa9, 0x01, 0x7a, 0xb2, 0xf9, 0x78, 0x7d, 0x0b, 0x63, 0x77,
|
||||
0x7a, 0x7b, 0xd1, 0x5f, 0xdc, 0xf5, 0x07, 0x46, 0xe8, 0xa6, 0xdf, 0xee, 0x56, 0x99, 0x8f, 0x7b,
|
||||
0xe7, 0xb3, 0xcd, 0x97, 0xcc, 0xd0, 0x0c, 0x2c, 0x59, 0x72, 0x0f, 0x6f, 0x46, 0xfa, 0x6e, 0xcf,
|
||||
0xd4, 0xff, 0x56, 0xab, 0x74, 0xd3, 0x5f, 0x1d, 0x12, 0xfd, 0x56, 0xcb, 0x74, 0x23, 0x9e, 0xd1,
|
||||
0x64, 0xf2, 0x7c, 0x23, 0xd4, 0x7d, 0x34, 0x47, 0xe1, 0xef, 0x8c, 0x24, 0x18, 0xab, 0x2b, 0x4f,
|
||||
0xc2, 0xbf, 0x99, 0x78, 0x3f, 0x71, 0xa3, 0x47, 0xf4, 0xd9, 0xf2, 0x7a, 0x2e, 0xaf, 0xb7, 0xe5,
|
||||
0xb5, 0xd5, 0xdd, 0x5b, 0xa7, 0xc7, 0x18, 0x8f, 0xdb, 0xf1, 0x1a, 0xaa, 0xb6, 0xb9, 0xb9, 0xd9,
|
||||
0x7e, 0x9a, 0x48, 0x16, 0x0f, 0x8b, 0xbf, 0xe8, 0xec, 0x21, 0xd1, 0xe6, 0x27, 0x3e, 0x7e, 0xa8,
|
||||
0xe6, 0xec, 0xfb, 0x15, 0x27, 0x3f, 0x91, 0x93, 0xed, 0x49, 0xc7, 0x4e, 0x54, 0xf9, 0xf8, 0x15,
|
||||
0x3c, 0xf3, 0x91, 0x9c, 0xf9, 0x6a, 0xe7, 0x4c, 0x9e, 0xec, 0x47, 0xfa, 0x09, 0x30, 0xc0, 0xdd,
|
||||
0xdb, 0xdb, 0xeb, 0x0f, 0x6f, 0xde, 0xba, 0x1b, 0x15, 0x31, 0xb7, 0x67, 0x43, 0xf7, 0xc9, 0x2b,
|
||||
0x81, 0x53, 0xbf, 0x9a, 0x0d, 0x34, 0xc4, 0x23, 0x0a, 0xc1, 0x28, 0x84, 0x23, 0x14, 0xe2, 0x51,
|
||||
0x0a, 0xdf, 0xbb, 0x77, 0x17, 0x17, 0x37, 0xee, 0x62, 0xd3, 0xbd, 0x75, 0xd8, 0x1d, 0xc7, 0xd4,
|
||||
0x5e, 0x18, 0xb5, 0x17, 0xc7, 0xc6, 0x13, 0xa2, 0x2a, 0x5e, 0x54, 0xcd, 0x4b, 0x11, 0xc1, 0x9e,
|
||||
0x11, 0x7d, 0xdf, 0xff, 0x78, 0x0f, 0x83, 0x1e, 0xff, 0x77, 0x27, 0x47, 0x7c, 0xa0, 0xf7, 0x68,
|
||||
0xdb, 0xba, 0xc7, 0xaa, 0x3e, 0x97, 0x13, 0x7f, 0xe6, 0xca, 0xbe, 0xba, 0xbe, 0xbe, 0xc3, 0x3b,
|
||||
0xa5, 0x5f, 0x5f, 0xbe, 0xd9, 0xdb, 0x53, 0x90, 0x98, 0x69, 0xf7, 0xb3, 0xa9, 0x76, 0xe3, 0x0d,
|
||||
0xbc, 0xe7, 0xee, 0xdf, 0x58, 0x98, 0x03, 0xc5, 0xbe, 0x9a, 0xc4, 0x27, 0x78, 0x2f, 0xc0, 0x5f,
|
||||
0x8c, 0x18, 0x77, 0x14, 0x7f, 0xb9, 0xdd, 0x9c, 0x7f, 0xd8, 0x6c, 0x65, 0x98, 0xe7, 0x97, 0xef,
|
||||
0x1d, 0x34, 0x60, 0x85, 0x70, 0x3d, 0x7b, 0xac, 0x17, 0xfb, 0x5e, 0xb6, 0x5a, 0x3e, 0x63, 0xd1,
|
||||
0x51, 0x38, 0xce, 0x07, 0x0f, 0xf0, 0x3b, 0x84, 0xf8, 0x51, 0xd8, 0xfd, 0x8f, 0xef, 0x5d, 0x10,
|
||||
0xe9, 0xe3, 0x51, 0x89, 0xf7, 0xde, 0xc8, 0x26, 0x33, 0x96, 0xb5, 0x9d, 0x8d, 0x7d, 0xb6, 0xc2,
|
||||
0xc6, 0xfe, 0x73, 0xc9, 0xbf, 0x7c, 0x66, 0x6b, 0x9c, 0xca, 0x89, 0xc8, 0xec, 0x95, 0x6f, 0x66,
|
||||
0xd0, 0x5f, 0xac, 0x31, 0xe8, 0x2f, 0x74, 0xb4, 0xfb, 0x30, 0xeb, 0x70, 0x57, 0x79, 0x71, 0xaf,
|
||||
0x45, 0x9f, 0xd8, 0x70, 0x35, 0x21, 0x3f, 0x20, 0xec, 0xdb, 0xfd, 0x47, 0x1f, 0x4a, 0xab, 0xe1,
|
||||
0xe6, 0x6b, 0x87, 0x17, 0x56, 0x6c, 0x5e, 0x5d, 0x7f, 0xb8, 0xfb, 0xf1, 0xd5, 0x76, 0x73, 0xf5,
|
||||
0x4e, 0xce, 0xd2, 0xe3, 0xf2, 0x03, 0x4f, 0xe5, 0xc3, 0x23, 0xfa, 0xf0, 0x32, 0xf3, 0xff, 0x03,
|
||||
0x5d, 0x2f, 0xbc, 0xe7, 0xe2, 0x7c, 0x00, 0x00,
|
||||
};
|
||||
1230
wled00/html_mobile.h
1230
wled00/html_mobile.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,40 +1,34 @@
|
||||
/*
|
||||
* Settings html
|
||||
* Settings html
|
||||
*/
|
||||
|
||||
//common CSS of settings pages
|
||||
const char PAGE_settingsCss[] PROGMEM = R"=====(body{font-family:var(--cFn),sans-serif;text-align:center;background:var(--cCol);color:var(--tCol);line-height:200%;margin:0;background-attachment:fixed}hr{border-color:var(--dCol);filter:drop-shadow(-5px -5px 5px var(--sCol))}button{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:20px;margin:8px;margin-top:12px}.helpB{text-align:left;position:absolute;width:60px}input{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.5ch solid var(--bCol);filter:drop-shadow(-5px -5px 5px var(--sCol))}input[type=number]{width:4em}select{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:0.5ch solid var(--bCol);filter:drop-shadow( -5px -5px 5px var(--sCol) );}td{padding:2px;}</style>)=====";
|
||||
|
||||
//common CSS of settings pages
|
||||
const char PAGE_settingsCss[] PROGMEM = R"=====(<style>body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}hr{border-color:#666}button{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}.helpB{text-align:left;position:absolute;width:60px}input{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}input[type=number]{width:4em}select{background:#333;color:#fff;font-family:Verdana,sans-serif;border:0.5ch solid #333}td{padding:2px;}.d5{width:4.5em !important;}</style>)=====";
|
||||
|
||||
//settings menu
|
||||
const char PAGE_settings0[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><title>WLED Settings</title>)=====";
|
||||
|
||||
const char PAGE_settings1[] PROGMEM = R"=====(body{text-align:center;background:var(--cCol);height:100%;margin:0;background-attachment:fixed}html{--h:11.55vh}button{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),Helvetica,sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:8vmin;height:var(--h);width:95%;margin-top:2.4vh}</style>
|
||||
<script>function BB(){if(window.frameElement){document.getElementById("b").style.display="none";document.documentElement.style.setProperty("--h","13.86vh")}};</script>
|
||||
</head>
|
||||
const char PAGE_settings[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><title>WLED Settings</title><style>body{text-align:center;background:#222;height:100%%;margin:0}html{--h:11.55vh}button{background:#333;color:#fff;font-family:Verdana,Helvetica,sans-serif;border:.3ch solid #333;display:inline-block;font-size:8vmin;height:var(--h);width:95%%;margin-top:2.4vh}</style>
|
||||
<script>function BB(){if(window.frameElement){document.getElementById("b").style.display="none";document.documentElement.style.setProperty("--h","13.86vh")}};</script></head>
|
||||
<body onload=BB()>
|
||||
<form action=/><button type=submit id=b>Back</button></form>
|
||||
<form action=/settings/wifi><button type=submit>WiFi Setup</button></form>
|
||||
<form action=/settings/leds><button type=submit>LED Preferences</button></form>
|
||||
<form action=/settings/ui><button type=submit>User Interface</button></form>
|
||||
<form action=/settings/ui><button type=submit>User Interface</button></form>%DMXMENU%
|
||||
<form action=/settings/sync><button type=submit>Sync Interfaces</button></form>
|
||||
<form action=/settings/time><button type=submit>Time & Macros</button></form>
|
||||
<form action=/settings/sec><button type=submit>Security & Updates</button></form>
|
||||
</body>
|
||||
</html>)=====";
|
||||
|
||||
</body></html>)=====";
|
||||
|
||||
|
||||
//wifi settings
|
||||
const char PAGE_settings_wifi0[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500">
|
||||
<title>WiFi Settings</title><script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#wifi-settings");}function B(){window.history.back();}function GetV(){var d = document;)=====";
|
||||
|
||||
const char PAGE_settings_wifi1[] PROGMEM = R"=====(</head>
|
||||
<body onload="GetV()">
|
||||
const char PAGE_settings_wifi[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8">
|
||||
<title>WiFi Settings</title><script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#wifi-settings");}function B(){window.history.back();}function GetV(){var d=document;
|
||||
%CSS%%SCSS%</head><body onload="GetV()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button><hr>
|
||||
<h2>WiFi setup</h2>
|
||||
<h3>Connect to existing network</h3>
|
||||
Network name (SSID, empty to not connect): <br><input name="CS" maxlength="32"><br>
|
||||
@@ -56,243 +50,323 @@ Static subnet mask:<br>
|
||||
<input name="S3" type="number" min="0" max="255" required><br>
|
||||
mDNS address (leave empty for no mDNS):<br/>
|
||||
http:// <input name="CM" maxlength="32"> .local<br>
|
||||
Try connecting before opening AP for: <input name="AT" type="number" min="0" max="255" required> s <br>
|
||||
Client IP: <span class="sip"> Not connected </span><br>
|
||||
<h3>Configure Access Point</h3>
|
||||
AP SSID (leave empty for no AP):<br> <input name="AS" maxlength="32"><br>
|
||||
AP name (SSID):<br><input name="AS" maxlength="32"><br>
|
||||
Hide AP name: <input type="checkbox" name="AH"><br>
|
||||
AP password (leave empty for open):<br> <input type="password" name="AP" maxlength="63"> <br>
|
||||
AP password (leave empty for open):<br> <input type="password" name="AP" maxlength="63"><br>
|
||||
Access Point WiFi channel: <input name="AC" type="number" min="1" max="13" required><br>
|
||||
AP IP: <span class="sip"> Not active </span><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
|
||||
AP opens:
|
||||
<select name="AB">
|
||||
<option value="0">No connection after boot</option>
|
||||
<option value="1">Disconnected</option>
|
||||
<option value="2">Always</option>
|
||||
<option value="3">Never (not recommended)</option></select><br>
|
||||
AP IP: <span class="sip"> Not active </span><br>
|
||||
<h3>Experimental</h3>
|
||||
Disable WiFi sleep: <input type="checkbox" name="WS"><br>
|
||||
<i>Can help with connectivity issues.<br>
|
||||
Do not enable if WiFi is working correctly, increases power consumption.</i>
|
||||
<hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>)=====";
|
||||
|
||||
|
||||
//LED settings
|
||||
const char PAGE_settings_leds0[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500">
|
||||
<title>LED Settings</title><script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings");}function B(){window.history.back();}function S(){GetV();UI();}function UI(){
|
||||
var myC=document.querySelectorAll('.wc'),l=myC.length;
|
||||
for (i = 0; i < l; i++){myC[i].style.display=(document.getElementById('rgbw').checked)?'inline':'none';}
|
||||
var val=Math.ceil((100+document.Sf.LC.value*55)/500)/2;
|
||||
val=(val>5)?Math.ceil(val):val;var s="";
|
||||
if (val<1.1){s="ESP 5V pin with 1A USB supply";}else{s="External 5V ";s+=val;s+="A supply connected to LEDs";}
|
||||
document.getElementById('psu').innerHTML=s;document.getElementById('ps2').innerHTML=val+"A = "+val*1000;
|
||||
}function GetV(){var d = document;)=====";
|
||||
const char PAGE_settings_leds[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset=utf-8>
|
||||
<meta name=viewport content="width=500">
|
||||
<title>LED Settings</title>
|
||||
<script>var d=document,laprev=55;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings")}function B(){window.open("/settings","_self")}function S(){GetV();setABL()}
|
||||
function enABL(){var a=d.getElementById("able").checked;d.Sf.LA.value=(a)?laprev:0;d.getElementById("abl").style.display=(a)?"inline":"none";d.getElementById("psu2").style.display=(a)?"inline":"none";if(d.Sf.LA.value>0){setABL()}}function enLA(){var a=d.Sf.LAsel.value;d.Sf.LA.value=a;d.getElementById("LAdis").style.display=(a==50)?"inline":"none";UI()}function setABL(){d.getElementById("able").checked=true;d.Sf.LAsel.value=50;switch(parseInt(d.Sf.LA.value)){case 0:d.getElementById("able").checked=false;enABL();break;case 30:d.Sf.LAsel.value=30;break;case 35:d.Sf.LAsel.value=35;break;case 55:d.Sf.LAsel.value=55;break;case 255:d.Sf.LAsel.value=255;break;default:d.getElementById("LAdis").style.display="inline"}UI()}function UI(){var b=d.querySelectorAll(".wc"),a=b.length;for(i=0;i<a;i++){b[i].style.display=(d.getElementById("rgbw").checked)?"inline":"none"}d.getElementById("ledwarning").style.display=(d.Sf.LC.value>1000)?"inline":"none";d.getElementById("ampwarning").style.display=(d.Sf.MA.value>7200)?"inline":"none";if(d.Sf.LA.value==255){laprev=12} else if(d.Sf.LA.value>0){laprev=d.Sf.LA.value}var j=Math.ceil((100+d.Sf.LC.value*laprev)/500)/2;j=(j>5)?Math.ceil(j):j;var g="";var e=(d.Sf.LAsel.value==30);var i=(d.Sf.LAsel.value==255);if(j<1.02&&!e&&!i){g="ESP 5V pin with 1A USB supply"}else{g+=e?"12V ":i?"WS2815 12V ":"5V ";g+=j;g+="A supply connected to LEDs"}var h=Math.ceil((100+d.Sf.LC.value*laprev)/1500)/2;h=(h>5)?Math.ceil(h):h;var c="(for most effects, ~";c+=h;c+="A is enough)<br>";d.getElementById("psu").innerHTML=g;d.getElementById("psu2").innerHTML=i?"":c}function GetV(){var d=document;
|
||||
%CSS%%SCSS%</head><body onload=S()>
|
||||
<form id=form_s name=Sf method=post>
|
||||
<div class=helpB><button type=button onclick=H()>?</button></div>
|
||||
<button type=button onclick=B()>Back</button><button type=submit>Save</button><hr>
|
||||
<h2>LED setup</h2>
|
||||
LED count: <input name=LC type=number min=1 max=1500 oninput=UI() required><br>
|
||||
<div id=ledwarning style=color:orange;display:none>
|
||||
⚠ You might run into stability or lag issues.<br>
|
||||
Use less than 1000 LEDs per ESP for the best experience!<br>
|
||||
</div>
|
||||
<i>Recommended power supply for brightest white:</i><br>
|
||||
<b><span id=psu>?</span></b><br>
|
||||
<span id=psu2><br></span>
|
||||
<br>
|
||||
Enable automatic brightness limiter: <input type=checkbox name=ABen onchange=enABL() id=able><br>
|
||||
<div id=abl>
|
||||
Maximum Current: <input name=MA type=number min=250 max=65000 oninput=UI() required> mA<br>
|
||||
<div id=ampwarning style=color:orange;display:none>
|
||||
⚠ Your power supply provides high current.<br>
|
||||
To improve the safety of your setup,<br>
|
||||
please use thick cables,<br>
|
||||
multiple power injection points and a fuse!<br>
|
||||
</div>
|
||||
<i>Automatically limits brightness to stay close to the limit.<br>
|
||||
Keep at <1A if powering LEDs directly from the ESP 5V pin!<br>
|
||||
If you are using an external power supply, enter its rating.<br>
|
||||
(Current estimated usage: <span class=pow>unknown</span>)</i><br><br>
|
||||
LED voltage (Max. current for a single LED):<br>
|
||||
<select name=LAsel onchange=enLA()>
|
||||
<option value=55 selected>5V default (55mA)</option>
|
||||
<option value=35>5V efficient (35mA)</option>
|
||||
<option value=30>12V (30mA)</option>
|
||||
<option value=255>WS2815 (12mA)</option>
|
||||
<option value=50>Custom</option>
|
||||
</select><br>
|
||||
<span id=LAdis style=display:none>Custom max. current per LED: <input name=LA type=number min=0 max=255 id=la oninput=UI() required> mA<br></span>
|
||||
<i>Keep at default if you are unsure about your type of LEDs.</i><br>
|
||||
</div>
|
||||
<br>
|
||||
LEDs are 4-channel type (RGBW): <input type=checkbox name=EW onchange=UI() id=rgbw><br>
|
||||
<span class=wc>
|
||||
Auto-calculate white channel from RGB:<br>
|
||||
<select name=AW>
|
||||
<option value=0>None</option>
|
||||
<option value=1>Brighter</option>
|
||||
<option value=2>Accurate</option>
|
||||
<option value=3>Dual</option>
|
||||
<option value=4>Legacy</option>
|
||||
</select>
|
||||
<br></span>
|
||||
Color order:
|
||||
<select name=CO>
|
||||
<option value=0>GRB</option>
|
||||
<option value=1>RGB</option>
|
||||
<option value=2>BRG</option>
|
||||
<option value=3>RBG</option>
|
||||
<option value=4>BGR</option>
|
||||
<option value=5>GBR</option>
|
||||
</select>
|
||||
<h3>Defaults</h3>
|
||||
Turn LEDs on after power up/reset: <input type=checkbox name=BO><br>
|
||||
Default brightness: <input name=CA type=number min=0 max=255 required> (0-255)<br><br>
|
||||
Apply preset <input name=BP type=number min=0 max=16 required> at boot (0 uses defaults)
|
||||
<br>- <i>or</i> -<br>
|
||||
Set current preset cycle setting as boot default: <input type=checkbox name=PC><br><br>
|
||||
Use Gamma correction for color: <input type=checkbox name=GC> (strongly recommended)<br>
|
||||
Use Gamma correction for brightness: <input type=checkbox name=GB> (not recommended)<br><br>
|
||||
Brightness factor: <input name=BF type=number min=1 max=255 required> %
|
||||
<h3>Transitions</h3>
|
||||
Crossfade: <input type=checkbox name=TF><br>
|
||||
Transition Time: <input name=TD maxlength=5 size=2> ms<br>
|
||||
Enable Palette transitions: <input type=checkbox name=PF>
|
||||
<h3>Timed light</h3>
|
||||
Default Duration: <input name=TL type=number min=1 max=255 required> min<br>
|
||||
Default Target brightness: <input name=TB type=number min=0 max=255 required><br>
|
||||
Fade down: <input type=checkbox name=TW><br>
|
||||
<h3>Advanced</h3>
|
||||
Palette blending:
|
||||
<select name=PB>
|
||||
<option value=0>Linear (wrap if moving)</option>
|
||||
<option value=1>Linear (always wrap)</option>
|
||||
<option value=2>Linear (never wrap)</option>
|
||||
<option value=3>None (not recommended)</option>
|
||||
</select><br>
|
||||
Reverse LED order (rotate 180): <input type=checkbox name=RV><br>
|
||||
Skip first LED: <input type=checkbox name=SL><hr>
|
||||
<button type=button onclick=B()>Back</button><button type=submit>Save</button>
|
||||
</form></body></html>)=====";
|
||||
|
||||
const char PAGE_settings_leds1[] PROGMEM = R"=====(</head>
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
//DMX Output settings
|
||||
const char PAGE_settings_dmx[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>DMX Settings</title><script>
|
||||
function GCH(num) {
|
||||
d=document;
|
||||
|
||||
d.getElementById('dmxchannels').innerHTML += "";
|
||||
for (i=0;i<num;i++) {
|
||||
d.getElementById('dmxchannels').innerHTML += "<span id=CH" + (i+1) + "s >Channel " + (i+1) + ": <select name=CH" + (i+1) + " id=\"CH" + (i+1) + "\"><option value=0>Set to 0</option><option value=1>Red</option><option value=2>Green</option><option value=3>Blue</option><option value=4>White</option><option value=5>Shutter (Brightness)</option><option value=6>Set to 255</option></select></span><br />\n";
|
||||
}
|
||||
}
|
||||
function mMap(){
|
||||
d=document;
|
||||
numCh=document.Sf.CN.value;
|
||||
numGap=document.Sf.CG.value;
|
||||
if (parseInt(numCh)>parseInt(numGap)) {
|
||||
d.getElementById("gapwarning").style.display="block";
|
||||
} else {
|
||||
d.getElementById("gapwarning").style.display="none";
|
||||
}
|
||||
for (i=0;i<15;i++) {
|
||||
if (i>=numCh) {
|
||||
d.getElementById("CH"+(i+1) + "s").style.opacity = "0.5";
|
||||
d.getElementById("CH"+(i+1)).disabled = true;
|
||||
|
||||
} else {
|
||||
d.getElementById("CH"+(i+1) + "s").style.opacity = "1";
|
||||
d.getElementById("CH"+(i+1)).disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
function S(){GCH(15);GetV();mMap();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}function B(){window.history.back();}function GetV(){var d=document;
|
||||
%CSS%%SCSS%</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
<h2>LED setup</h2>
|
||||
LED count: <input name="LC" type="number" min="1" max="1200" oninput=UI() required><br>
|
||||
<i>Recommended power supply for brightest white:</i><br>
|
||||
<b><span id="psu">?</span></b><br><br>
|
||||
Maximum Current: <input name="MA" type="number" min="250" max="65000" required> mA<br>
|
||||
<i>Automatically limits brightness to stay close to the limit.<br>
|
||||
Keep at <1A if powering LEDs directly from the ESP 5V pin!<br>
|
||||
If you are using an external 5V supply, enter its rating.<br>
|
||||
"65000" completely diasbles the power calculation.<br>
|
||||
(Current estimated usage: <span class="pow">unknown</span>)</i><br><br>
|
||||
LEDs are 4-channel type (RGBW): <input type="checkbox" name="EW" onchange=UI() id="rgbw"><br>
|
||||
Color order:
|
||||
<select name="CO">
|
||||
<option value="0">GRB</option>
|
||||
<option value="1">RGB</option>
|
||||
<option value="2">BRG</option>
|
||||
<option value="3">RBG</option></select>
|
||||
<h3>Defaults</h3>
|
||||
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br><br>
|
||||
Default RGB color:
|
||||
<input name="CR" type="number" min="0" max="255" required>
|
||||
<input name="CG" type="number" min="0" max="255" required>
|
||||
<input name="CB" type="number" min="0" max="255" required><br>
|
||||
<span class="wc">Default white value: <input name="CW" type="number" min="0" max="255" required><br>
|
||||
Auto-calculate white from RGB instead: <input type="checkbox" name="AW"><br></span>
|
||||
Default brightness: <input name="CA" type="number" min="0" max="255" required> (0-255)<br>
|
||||
Default effect ID: <input name="FX" type="number" min="0" max="57" required><br>
|
||||
Default effect speed: <input name="SX" type="number" min="0" max="255" required><br>
|
||||
Default effect intensity: <input name="IX" type="number" min="0" max="255" required><br>
|
||||
Default effect palette: <input name="FP" type="number" min="0" max="255" required><br>
|
||||
Default secondary RGB<span class="wc">W</span>:<br>
|
||||
<input name="SR" type="number" min="0" max="255" required>
|
||||
<input name="SG" type="number" min="0" max="255" required>
|
||||
<input name="SB" type="number" min="0" max="255" required>
|
||||
<span class="wc"><input name="SW" type="number" min="0" max="255" required></span><br>
|
||||
Ignore and use current color, brightness and effects: <input type="checkbox" name="IS"><br><br>
|
||||
Apply preset <input name="BP" type="number" min="0" max="25" required> at boot (0 uses defaults)<br>
|
||||
Save current preset cycle configuration as boot default: <input type="checkbox" name="PC"><br><br>
|
||||
Use Gamma correction for color: <input type="checkbox" name="GC"> (strongly recommended)<br>
|
||||
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br><br>
|
||||
Brightness factor: <input name="BF" type="number" min="0" max="255" required> %
|
||||
<h3>Transitions</h3>
|
||||
Crossfade: <input type="checkbox" name="TF"><br>
|
||||
Transition Time: <input name="TD" maxlength="5" size="2"> ms<br>
|
||||
Enable transition for secondary color: <input type="checkbox" name="T2"><br>
|
||||
Enable Palette transitions: <input type="checkbox" name="PF">
|
||||
<h3>Timed light</h3>
|
||||
Default Duration: <input name="TL" type="number" min="1" max="255" required> min<br>
|
||||
Default Target brightness: <input name="TB" type="number" min="0" max="255" required><br>
|
||||
Fade down: <input type="checkbox" name="TW"><br>
|
||||
<h3>Advanced</h3>
|
||||
Palette blending:
|
||||
<select name="PB">
|
||||
<option value="0">Linear (wrap if moving)</option>
|
||||
<option value="1">Linear (always wrap)</option>
|
||||
<option value="2">Linear (never wrap)</option>
|
||||
<option value="3">None (not recommended)</option>
|
||||
</select><br>
|
||||
Reverse LED order (rotate 180): <input type="checkbox" name="RV"><br>
|
||||
Skip first LED: <input type="checkbox" name="SL"><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
<h2>Imma firin ma lazer (if it has DMX support)</h2><!-- TODO: Change to something less-meme-related //-->
|
||||
|
||||
<i>Number of fixtures is taken from LED config page</i><br>
|
||||
|
||||
Channels per fixture (15 max): <input type="number" min="1" max="15" name="CN" maxlength="2" onchange="mMap();"><br />
|
||||
Start channel: <input type="number" min="1" max="512" name="CS" maxlength="2"><br />
|
||||
Spacing between start channels: <input type="number" min="1" max="512" name="CG" maxlength="2" onchange="mMap();"> [ <a href="javascript:alert('if set to 10, first fixture will start at 10,\nsecond will start at 20 etc.\nRegardless of the channel count.\nMakes memorizing channel numbers easier.');">info</a> ]<br>
|
||||
<div id="gapwarning" style="color: orange; display: none;">WARNING: Channel gap is lower than channels per fixture.<br />This will cause overlap.</div>
|
||||
<button type="button" onclick="location.href='/dmxmap';">DMX Map</button><br>
|
||||
DMX fixtures start LED: <input type="number" min="0" max="1500" name="SL">
|
||||
<h3>channel functions</h3>
|
||||
<div id="dmxchannels"></div>
|
||||
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>)=====";
|
||||
|
||||
#else
|
||||
const char PAGE_settings_dmx[] PROGMEM = R"=====()=====";
|
||||
#endif
|
||||
|
||||
//User Interface settings
|
||||
const char PAGE_settings_ui0[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500">
|
||||
<title>UI Settings</title><script>
|
||||
function gId(s){return document.getElementById(s);}function S(){GetV();Ct();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#user-interface-settings");}function B(){window.history.back();}function Ct(){if (gId("co").selected){gId("cth").style.display="block";}else{gId("cth").style.display="none";}}function GetV(){var d = document;)=====";
|
||||
|
||||
const char PAGE_settings_ui1[] PROGMEM = R"=====(</head>
|
||||
const char PAGE_settings_ui[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>UI Settings</title><script>
|
||||
function gId(s){return document.getElementById(s);}function S(){GetV();Ct();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#user-interface-settings");}function B(){window.history.back();}function Ct(){if (gId("co").selected){gId("cth").style.display="block";}else{gId("cth").style.display="none";}}function GetV(){var d=document;
|
||||
%CSS%%SCSS%</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
<h2>Web Setup</h2>
|
||||
User Interface Mode:
|
||||
<select name="UI">
|
||||
<option value="0" selected>Auto</option>
|
||||
<option value="1">Classic</option>
|
||||
<option value="2">Mobile</option>
|
||||
</select><br>
|
||||
Server description: <input name="DS" maxlength="32"><br><br>
|
||||
<i>The following options are for the classic UI!</i><br>
|
||||
Use HSB sliders instead of RGB by default: <input type="checkbox" name="MD"><br>
|
||||
Color Theme:
|
||||
<select name="TH" onchange="Ct()">
|
||||
<option value="0" selected>Night</option>
|
||||
<option value="1">Modern</option>
|
||||
<option value="2">Bright</option>
|
||||
<option value="3">Wine</option>
|
||||
<option value="4">Electric</option>
|
||||
<option value="5">Mint</option>
|
||||
<option value="6">Amber</option>
|
||||
<option value="7">Dark</option>
|
||||
<option value="8">Air</option>
|
||||
<option value="9">Nixie</option>
|
||||
<option value="10">Terminal</option>
|
||||
<option value="11">C64</option>
|
||||
<option value="12">Easter</option>
|
||||
<option value="13">Christmas</option>
|
||||
<option value="14">The End</option>
|
||||
<option value="15" id="co">Custom</option>
|
||||
</select><br>
|
||||
<div id="cth">
|
||||
Please specify your custom hex colors (e.g. FF0000 for red)<br>
|
||||
Custom accent color: <input maxlength=9 name="C0"><br>
|
||||
Custom background: <input maxlength=9 name="C1"><br>
|
||||
Custom panel color: <input maxlength=9 name="C2"><br>
|
||||
Custom icon color: <input maxlength=9 name="C3"><br>
|
||||
Custom shadow: <input maxlength=9 name="C4"><br>
|
||||
Custom text color: <input maxlength=9 name="C5"><br></div>
|
||||
Use font: <input maxlength=32 name="CF"><br>
|
||||
Make sure the font you use is installed on your system!<br>
|
||||
Server description: <input name="DS" maxlength="32"><br>
|
||||
Sync button toggles both send and receive: <input type="checkbox" name="ST"><br><br>
|
||||
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>)=====";
|
||||
|
||||
|
||||
//sync settings
|
||||
const char PAGE_settings_sync0[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500"><title>Sync Settings</title>
|
||||
<script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings");}function B(){window.open("/settings","_self");}function GetV(){var d = document;)=====";
|
||||
|
||||
const char PAGE_settings_sync1[] PROGMEM = R"=====(</head>
|
||||
<body onload="GetV()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
//sync settings
|
||||
const char PAGE_settings_sync[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name=viewport content="width=500"><meta charset=utf-8><title>Sync Settings</title>
|
||||
<script>var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings")}function B(){window.open("/settings","_self")}function adj(){if(d.Sf.DI.value==6454){if(d.Sf.DA.value==1){d.Sf.DA.value=0}if(d.Sf.EU.value==1){d.Sf.EU.value=0}}else{if(d.Sf.DI.value==5568){if(d.Sf.DA.value==0){d.Sf.DA.value=1}if(d.Sf.EU.value==0){d.Sf.EU.value=1}}}}function SP(){var a=d.Sf.DI.value;d.getElementById("xp").style.display=(a>0)?"none":"block";if(a>0){d.Sf.EP.value=a}}function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568:d.Sf.DI.value=5568;break;case 6454:d.Sf.DI.value=6454;break}SP()}function S(){GetV();SetVal()};function GetV(){
|
||||
%CSS%%SCSS%</head>
|
||||
<body onload=S()>
|
||||
<form id=form_s name=Sf method=post>
|
||||
<div class=helpB><button type=button onclick=H()>?</button></div>
|
||||
<button type=button onclick=B()>Back</button><button type=submit>Save</button><hr>
|
||||
<h2>Sync setup</h2>
|
||||
<h3>Button setup</h3>
|
||||
On/Off button enabled: <input type="checkbox" name="BT"><br>
|
||||
Infrared receiver enabled: <input type="checkbox" name="IR"><br>
|
||||
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a>
|
||||
On/Off button enabled: <input type=checkbox name=BT><br>
|
||||
Infrared remote:
|
||||
<select name=IR>
|
||||
<option value=0>Disabled</option>
|
||||
<option value=1>24-key RGB</option>
|
||||
<option value=2>24-key with CT</option>
|
||||
<option value=3>40-key blue</option>
|
||||
<option value=4>44-key RGB</option>
|
||||
<option value=5>21-key RGB</option>
|
||||
<option value=6>6-key black</option>
|
||||
</select><br>
|
||||
<a href=https://github.com/Aircoookie/WLED/wiki/Infrared-Control target=_blank>IR info</a>
|
||||
<h3>WLED Broadcast</h3>
|
||||
UDP Port: <input name="UP" maxlength="5" size="4"><br>
|
||||
Receive <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br>
|
||||
Send notifications on direct change: <input type="checkbox" name="SD"><br>
|
||||
Send notifications on button press: <input type="checkbox" name="SB"><br>
|
||||
Send Alexa notifications: <input type="checkbox" name="SA"><br>
|
||||
Send Philips Hue change notifications: <input type="checkbox" name="SH"><br>
|
||||
Send notifications twice: <input type="checkbox" name="S2"><br>
|
||||
UDP Port: <input name=UP type=number min=1 max=65535 class=d5 required><br>
|
||||
Receive <input type=checkbox name=RB>Brightness, <input type=checkbox name=RC>Color, and <input type=checkbox name=RX>Effects<br>
|
||||
Send notifications on direct change: <input type=checkbox name=SD><br>
|
||||
Send notifications on button press: <input type=checkbox name=SB><br>
|
||||
Send Alexa notifications: <input type=checkbox name=SA><br>
|
||||
Send Philips Hue change notifications: <input type=checkbox name=SH><br>
|
||||
Send Macro notifications: <input type=checkbox name=SM><br>
|
||||
Send notifications twice: <input type=checkbox name=S2>
|
||||
<h3>Realtime</h3>
|
||||
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
|
||||
<i>E1.31 (sACN)</i><br>
|
||||
Use E1.31 multicast: <input type="checkbox" name="EM"><br>
|
||||
E1.31 start universe: <input name="EU" type="number" min="1" max="63999" required><br>
|
||||
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx" target="_blank">LedFx</a>!<br><br>
|
||||
Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
|
||||
Force max brightness: <input type="checkbox" name="FB"><br>
|
||||
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
|
||||
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required><br>
|
||||
Enable UI access during realtime: <input type="checkbox" name="RU"> (can cause issues)
|
||||
Receive UDP realtime: <input type=checkbox name=RD><br><br>
|
||||
<i>Network DMX input</i><br>
|
||||
Type:
|
||||
<select name=DI onchange=SP();adj()>
|
||||
<option value=5568>E1.31 (sACN)</option>
|
||||
<option value=6454>Art-Net</option>
|
||||
<option value=0 selected>Custom port</option>
|
||||
</select><br>
|
||||
<div id=xp>Port: <input name=EP type=number min=1 max=65535 value=5568 class=d5 required><br></div>
|
||||
Multicast: <input type=checkbox name=EM><br>
|
||||
Start universe: <input name=EU type=number min=0 max=63999 required><br>
|
||||
<i>Reboot required.</i> Check out <a href=https://github.com/ahodges9/LedFx target=_blank>LedFx</a>!<br>
|
||||
Skip out-of-sequence packets: <input type=checkbox name=ES><br>
|
||||
DMX start address: <input name=DA type=number min=0 max=510 required><br>
|
||||
DMX mode:
|
||||
<select name=DM>
|
||||
<option value=0>Disabled</option>
|
||||
<option value=1>Single RGB</option>
|
||||
<option value=2>Single DRGB</option>
|
||||
<option value=3>Effect</option>
|
||||
<option value=4>Multi RGB</option>
|
||||
<option value=5>Multi DRGB</option>
|
||||
</select><br>
|
||||
<a href=https://github.com/Aircoookie/WLED/wiki/E1.31-DMX target=_blank>E1.31 info</a><br>
|
||||
Timeout: <input name=ET type=number min=1 max=65000 required> ms<br>
|
||||
Force max brightness: <input type=checkbox name=FB><br>
|
||||
Disable realtime gamma correction: <input type=checkbox name=RG><br>
|
||||
Realtime LED offset: <input name=WO type=number min=-255 max=255 required>
|
||||
<h3>Alexa Voice Assistant</h3>
|
||||
Emulate Alexa device: <input type="checkbox" name="AL"><br>
|
||||
Alexa invocation name: <input name="AI" maxlength="32">
|
||||
Emulate Alexa device: <input type=checkbox name=AL><br>
|
||||
Alexa invocation name: <input name=AI maxlength=32>
|
||||
<h3>Blynk</h3>
|
||||
<b>Blynk, MQTT and Hue sync all connect to external hosts!<br>
|
||||
This impacts the responsiveness of the ESP8266.</b><br>
|
||||
This may impact the responsiveness of the ESP8266.</b><br>
|
||||
For best results, only use one of these services at a time.<br>
|
||||
(alternatively, connect a second ESP to them and use the UDP sync)<br><br>
|
||||
Device Auth token: <input name="BK" maxlength="33"><br>
|
||||
<i>Clear the token field to disable. </i><a href="https://github.com/Aircoookie/WLED/wiki/Blynk" target="_blank">Setup info</a>
|
||||
Device Auth token: <input name=BK maxlength=33><br>
|
||||
<i>Clear the token field to disable. </i><a href=https://github.com/Aircoookie/WLED/wiki/Blynk target=_blank>Setup info</a>
|
||||
<h3>MQTT</h3>
|
||||
Broker: <input name="MS" maxlength="32"><br>
|
||||
Device Topic: <input name="MD" maxlength="32"><br>
|
||||
Group Topic: <input name="MG" maxlength="32"><br>
|
||||
<i>Reboot required to apply changes. </i><a href="https://github.com/Aircoookie/WLED/wiki/MQTT" target="_blank">MQTT info</a>
|
||||
Enable MQTT: <input type=checkbox name=MQ><br>
|
||||
Broker: <input name=MS maxlength=32>
|
||||
Port: <input name=MQPORT type=number min=1 max=65535 class=d5><br>
|
||||
<b>The MQTT credentials are sent over an unsecured connection.<br>
|
||||
Never use the MQTT password for another service!</b><br>
|
||||
Username: <input name=MQUSER maxlength=40><br>
|
||||
Password: <input type=password input name=MQPASS maxlength=40><br>
|
||||
Client ID: <input name=MQCID maxlength=40><br>
|
||||
Device Topic: <input name=MD maxlength=32><br>
|
||||
Group Topic: <input name=MG maxlength=32><br>
|
||||
<i>Reboot required to apply changes. </i><a href=https://github.com/Aircoookie/WLED/wiki/MQTT target=_blank>MQTT info</a>
|
||||
<h3>Philips Hue</h3>
|
||||
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
|
||||
Poll Hue light <input name="HL" type="number" min="1" max="99" required> every <input name="HI" type="number" min="100" max="65000" required> ms: <input type="checkbox" name="HP"><br>
|
||||
Then, receive <input type="checkbox" name="HO"> On/Off, <input type="checkbox" name="HB"> Brightness, and <input type="checkbox" name="HC"> Color<br>
|
||||
Poll Hue light <input name=HL type=number min=1 max=99> every <input name=HI type=number min=100 max=65000> ms: <input type=checkbox name=HP><br>
|
||||
Then, receive <input type=checkbox name=HO> On/Off, <input type=checkbox name=HB> Brightness, and <input type=checkbox name=HC> Color<br>
|
||||
Hue Bridge IP:<br>
|
||||
<input name="H0" type="number" min="0" max="255" required> .
|
||||
<input name="H1" type="number" min="0" max="255" required> .
|
||||
<input name="H2" type="number" min="0" max="255" required> .
|
||||
<input name="H3" type="number" min="0" max="255" required><br>
|
||||
<input name=H0 type=number min=0 max=255> .
|
||||
<input name=H1 type=number min=0 max=255> .
|
||||
<input name=H2 type=number min=0 max=255> .
|
||||
<input name=H3 type=number min=0 max=255><br>
|
||||
<b>Press the pushlink button on the bridge, after that save this page!</b><br>
|
||||
(when first connecting)<br>
|
||||
Hue status: <span class="hms"> Internal ESP Error! </span><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
Hue status: <span class=sip> Disabled in this build </span><hr>
|
||||
<button type=button onclick=B()>Back</button><button type=submit>Save</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>)=====";
|
||||
</body></html>)=====";
|
||||
|
||||
|
||||
//time and macro settings
|
||||
const char PAGE_settings_time0[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500"><title>Time Settings</title>
|
||||
const char PAGE_settings_time[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>Time Settings</title>
|
||||
<script>var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings");}function B(){window.open("/settings","_self");}function S(){BTa();GetV();Cs();FC();}function gId(s){return d.getElementById(s);}function Cs(){gId("cac").style.display="none";gId("coc").style.display="block";gId("ccc").style.display="none";if (gId("ca").selected){gId("cac").style.display="block";}if (gId("cc").selected){gId("coc").style.display="none";gId("ccc").style.display="block";}if (gId("cn").selected){gId("coc").style.display="none";}}
|
||||
function BTa(){var ih="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Macro</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";for (i=0;i<8;i++){ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" type=\"number\" min=\"0\" max=\"16\"></td>";for (j=1;j<8;j++) ih+="<td><input id=\"W"+i+j+"\" type=\"checkbox\"></td>";}gId("TMT").innerHTML=ih;}
|
||||
function FC(){for(j=0;j<8;j++){for(i=0;i<8;i++)gId("W"+i+j).checked=gId("W"+i).value>>j&1;}}
|
||||
function Wd(){a=[0,0,0,0,0,0,0,0];for(i=0;i<8;i++){m=1;for(j=0;j<8;j++){a[i]+=gId("W"+i+j).checked*m;m*=2;}gId("W"+i).value=a[i];}}function GetV(){)=====";
|
||||
|
||||
const char PAGE_settings_time1[] PROGMEM = R"=====(</head>
|
||||
function Wd(){a=[0,0,0,0,0,0,0,0];for(i=0;i<8;i++){m=1;for(j=0;j<8;j++){a[i]+=gId("W"+i+j).checked*m;m*=2;}gId("W"+i).value=a[i];}}function GetV(){
|
||||
%CSS%%SCSS%</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post" onsubmit="Wd()">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
<h2>Time setup</h2>
|
||||
Get time from NTP server: <input type="checkbox" name="NT"><br>
|
||||
<input name="NS" maxlength="32"><br>
|
||||
Use 24h format: <input type="checkbox" name="CF"><br>
|
||||
Time zone:
|
||||
Time zone:
|
||||
<select name="TZ">
|
||||
<option value="0" selected>GMT(UTC)</option>
|
||||
<option value="1">GMT/BST</option>
|
||||
@@ -308,6 +382,10 @@ Time zone:
|
||||
<option value="11">AEST/AEDT</option>
|
||||
<option value="12">NZST/NZDT</option>
|
||||
<option value="13">North Korea</option>
|
||||
<option value="14">IST (India)</option>
|
||||
<option value="15">CA-Saskatchewan</option>
|
||||
<option value="16">ACST</option>
|
||||
<option value="17">ACST/ACDT</option>
|
||||
</select><br>
|
||||
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
|
||||
Current local time is <span class="times">unknown</span>.
|
||||
@@ -316,7 +394,7 @@ Clock Overlay:
|
||||
<select name="OL" onchange="Cs()">
|
||||
<option value="0" id="cn" selected>None</option>
|
||||
<option value="1" id="ca">Analog Clock</option>
|
||||
<option value="2">Single Digit Clock</option>
|
||||
<option value="2" disabled>-</option>
|
||||
<option value="3" id="cc">Cronixie Clock</option>
|
||||
</select><br>
|
||||
<div id="coc">
|
||||
@@ -353,12 +431,13 @@ Define API macros here:<br>
|
||||
15: <input name="M15" maxlength="64"><br>
|
||||
16: <input name="M16" maxlength="64"><br><br>
|
||||
<i>Use 0 for the default action instead of a macro</i><br>
|
||||
Boot Macro: <input name="MB" type="number" min="0" max="16" required><br>
|
||||
Alexa On/Off Macros: <input name="A0" type="number" min="0" max="16" required> <input name="A1" type="number" min="0" max="16" required><br>
|
||||
Button Macro: <input name="MP" type="number" min="0" max="16" required> Long Press: <input name="ML" type="number" min="0" max="16" required><br>
|
||||
Countdown-Over Macro: <input name="MC" type="number" min="0" max="16" required><br>
|
||||
Timed-Light-Over Macro: <input name="MN" type="number" min="0" max="16" required><br>
|
||||
Time-Controlled Macros:<br>
|
||||
Boot macro: <input name="MB" type="number" min="0" max="16" required><br>
|
||||
Alexa On/Off macros: <input name="A0" type="number" min="0" max="16" required> <input name="A1" type="number" min="0" max="16" required><br>
|
||||
Button short press macro: <input name="MP" type="number" min="0" max="16" required><br>
|
||||
Long press: <input name="ML" type="number" min="0" max="16" required> Double press: <input name="MD" type="number" min="0" max="16" required><br>
|
||||
Countdown-Over macro: <input name="MC" type="number" min="0" max="16" required><br>
|
||||
Timed-Light-Over macro: <input name="MN" type="number" min="0" max="16" required><br>
|
||||
Time-Controlled macros:<br>
|
||||
<div style="display: inline-block">
|
||||
<table id="TMT">
|
||||
</table></div><hr>
|
||||
@@ -369,12 +448,11 @@ Time-Controlled Macros:<br>
|
||||
|
||||
|
||||
//security settings and about
|
||||
const char PAGE_settings_sec0[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500">
|
||||
const char PAGE_settings_sec[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8">
|
||||
<title>Misc Settings</title>
|
||||
<script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#security-settings");}function B(){window.open("/settings","_self");}function U(){window.open("/update","_self");}function GetV(){var d = document;)=====";
|
||||
|
||||
const char PAGE_settings_sec1[] PROGMEM = R"=====(</head>
|
||||
<script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#security-settings");}function B(){window.open("/settings","_self");}function U(){window.open("/update","_self");}function GetV(){var d=document;
|
||||
%CSS%%SCSS%</head>
|
||||
<body onload="GetV()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
@@ -387,9 +465,6 @@ The password should be changed when OTA is enabled.<br>
|
||||
<b>Disable OTA when not in use, otherwise an attacker can reflash device software!</b><br>
|
||||
<i>Settings on this page are only changable if OTA lock is disabled!</i><br>
|
||||
Deny access to WiFi settings if locked: <input type="checkbox" name="OW"><br><br>
|
||||
Disable recovery AP: <input type="checkbox" name="NA"><br>
|
||||
In case of an error there will be no wireless recovery possible!<br>
|
||||
Completely disables all Access Point functions.<br><br>
|
||||
Factory reset: <input type="checkbox" name="RS"><br>
|
||||
All EEPROM content (settings) will be erased.<br><br>
|
||||
HTTP traffic is unencrypted. An attacker in the same network can intercept form data!
|
||||
@@ -397,12 +472,12 @@ HTTP traffic is unencrypted. An attacker in the same network can intercept form
|
||||
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
||||
Enable ArduinoOTA: <input type="checkbox" name="AO"><br>
|
||||
<h3>About</h3>
|
||||
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.8.3<br><br>
|
||||
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.10.0<br><br>
|
||||
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-&-About" target="_blank">Contributors, dependencies and special thanks</a><br>
|
||||
A huge thank you to everyone who helped me create WLED!<br><br>
|
||||
(c) 2016-2019 Christian Schwinne <br>
|
||||
(c) 2016-2020 Christian Schwinne <br>
|
||||
<i>Licensed under the MIT license</i><br><br>
|
||||
Server message: <span class="msg"> Response error! </span><hr>
|
||||
Server message: <span class="sip"> Response error! </span><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
1697
wled00/html_ui.h
Normal file
1697
wled00/html_ui.h
Normal file
File diff suppressed because it is too large
Load Diff
207
wled00/hue.cpp
Normal file
207
wled00/hue.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Sync to Philips hue lights
|
||||
*/
|
||||
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
|
||||
void handleHue()
|
||||
{
|
||||
if (hueReceived)
|
||||
{
|
||||
colorUpdated(NOTIFIER_CALL_MODE_HUE); hueReceived = false;
|
||||
if (hueStoreAllowed && hueNewKey)
|
||||
{
|
||||
saveSettingsToEEPROM(); //save api key
|
||||
hueStoreAllowed = false;
|
||||
hueNewKey = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!WLED_CONNECTED || hueClient == nullptr || millis() - hueLastRequestSent < huePollIntervalMs) return;
|
||||
|
||||
hueLastRequestSent = millis();
|
||||
if (huePollingEnabled)
|
||||
{
|
||||
reconnectHue();
|
||||
} else {
|
||||
hueClient->close();
|
||||
if (hueError == HUE_ERROR_ACTIVE) hueError = HUE_ERROR_INACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
void reconnectHue()
|
||||
{
|
||||
if (!WLED_CONNECTED || !huePollingEnabled) return;
|
||||
DEBUG_PRINTLN("Hue reconnect");
|
||||
if (hueClient == nullptr) {
|
||||
hueClient = new AsyncClient();
|
||||
hueClient->onConnect(&onHueConnect, hueClient);
|
||||
hueClient->onData(&onHueData, hueClient);
|
||||
hueClient->onError(&onHueError, hueClient);
|
||||
hueAuthRequired = (strlen(hueApiKey)<20);
|
||||
}
|
||||
hueClient->connect(hueIP, 80);
|
||||
}
|
||||
|
||||
void onHueError(void* arg, AsyncClient* client, int8_t error)
|
||||
{
|
||||
DEBUG_PRINTLN("Hue err");
|
||||
hueError = HUE_ERROR_TIMEOUT;
|
||||
}
|
||||
|
||||
void onHueConnect(void* arg, AsyncClient* client)
|
||||
{
|
||||
DEBUG_PRINTLN("Hue connect");
|
||||
sendHuePoll();
|
||||
}
|
||||
|
||||
void sendHuePoll()
|
||||
{
|
||||
if (hueClient == nullptr || !hueClient->connected()) return;
|
||||
String req = "";
|
||||
if (hueAuthRequired)
|
||||
{
|
||||
req += F("POST /api HTTP/1.1\r\nHost: ");
|
||||
req += hueIP.toString();
|
||||
req += F("\r\nContent-Length: 25\r\n\r\n{\"devicetype\":\"wled#esp\"}");
|
||||
} else
|
||||
{
|
||||
req += "GET /api/";
|
||||
req += hueApiKey;
|
||||
req += "/lights/" + String(huePollLightId);
|
||||
req += F(" HTTP/1.1\r\nHost: ");
|
||||
req += hueIP.toString();
|
||||
req += "\r\n\r\n";
|
||||
}
|
||||
hueClient->add(req.c_str(), req.length());
|
||||
hueClient->send();
|
||||
hueLastRequestSent = millis();
|
||||
}
|
||||
|
||||
void onHueData(void* arg, AsyncClient* client, void *data, size_t len)
|
||||
{
|
||||
if (!len) return;
|
||||
char* str = (char*)data;
|
||||
DEBUG_PRINTLN(hueApiKey);
|
||||
DEBUG_PRINTLN(str);
|
||||
//only get response body
|
||||
str = strstr(str,"\r\n\r\n");
|
||||
if (str == nullptr) return;
|
||||
str += 4;
|
||||
|
||||
StaticJsonDocument<512> root;
|
||||
if (str[0] == '[') //is JSON array
|
||||
{
|
||||
auto error = deserializeJson(root, str);
|
||||
if (error)
|
||||
{
|
||||
hueError = HUE_ERROR_JSON_PARSING; return;
|
||||
}
|
||||
|
||||
int hueErrorCode = root[0]["error"]["type"];
|
||||
if (hueErrorCode)//hue bridge returned error
|
||||
{
|
||||
hueError = hueErrorCode;
|
||||
switch (hueErrorCode)
|
||||
{
|
||||
case 1: hueAuthRequired = true; break; //Unauthorized user
|
||||
case 3: huePollingEnabled = false; break; //Invalid light ID
|
||||
case 101: hueAuthRequired = true; break; //link button not presset
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (hueAuthRequired)
|
||||
{
|
||||
const char* apikey = root[0]["success"]["username"];
|
||||
if (apikey != nullptr && strlen(apikey) < sizeof(hueApiKey))
|
||||
{
|
||||
strcpy(hueApiKey, apikey);
|
||||
hueAuthRequired = false;
|
||||
hueNewKey = true;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//else, assume it is JSON object, look for state and only parse that
|
||||
str = strstr(str,"state");
|
||||
if (str == nullptr) return;
|
||||
str = strstr(str,"{");
|
||||
|
||||
auto error = deserializeJson(root, str);
|
||||
if (error)
|
||||
{
|
||||
hueError = HUE_ERROR_JSON_PARSING; return;
|
||||
}
|
||||
|
||||
float hueX=0, hueY=0;
|
||||
uint16_t hueHue=0, hueCt=0;
|
||||
byte hueBri=0, hueSat=0, hueColormode=0;
|
||||
|
||||
if (root["on"]) {
|
||||
if (root.containsKey("bri")) //Dimmable device
|
||||
{
|
||||
hueBri = root["bri"];
|
||||
hueBri++;
|
||||
const char* cm =root["colormode"];
|
||||
if (cm != nullptr) //Color device
|
||||
{
|
||||
if (strstr(cm,"ct") != nullptr) //ct mode
|
||||
{
|
||||
hueCt = root["ct"];
|
||||
hueColormode = 3;
|
||||
} else if (strstr(cm,"xy") != nullptr) //xy mode
|
||||
{
|
||||
hueX = root["xy"][0]; // 0.5051
|
||||
hueY = root["xy"][1]; // 0.4151
|
||||
hueColormode = 1;
|
||||
} else //hs mode
|
||||
{
|
||||
hueHue = root["hue"];
|
||||
hueSat = root["sat"];
|
||||
hueColormode = 2;
|
||||
}
|
||||
}
|
||||
} else //On/Off device
|
||||
{
|
||||
hueBri = briLast;
|
||||
}
|
||||
} else
|
||||
{
|
||||
hueBri = 0;
|
||||
}
|
||||
|
||||
hueError = HUE_ERROR_ACTIVE;
|
||||
|
||||
//apply vals
|
||||
if (hueBri != hueBriLast)
|
||||
{
|
||||
if (hueApplyOnOff)
|
||||
{
|
||||
if (hueBri==0) {bri = 0;}
|
||||
else if (bri==0 && hueBri>0) bri = briLast;
|
||||
}
|
||||
if (hueApplyBri)
|
||||
{
|
||||
if (hueBri>0) bri = hueBri;
|
||||
}
|
||||
hueBriLast = hueBri;
|
||||
}
|
||||
if (hueApplyColor)
|
||||
{
|
||||
switch(hueColormode)
|
||||
{
|
||||
case 1: if (hueX != hueXLast || hueY != hueYLast) colorXYtoRGB(hueX,hueY,col); hueXLast = hueX; hueYLast = hueY; break;
|
||||
case 2: if (hueHue != hueHueLast || hueSat != hueSatLast) colorHStoRGB(hueHue,hueSat,col); hueHueLast = hueHue; hueSatLast = hueSat; break;
|
||||
case 3: if (hueCt != hueCtLast) colorCTtoRGB(hueCt,col); hueCtLast = hueCt; break;
|
||||
}
|
||||
}
|
||||
hueReceived = true;
|
||||
}
|
||||
#else
|
||||
void handleHue(){}
|
||||
void reconnectHue(){}
|
||||
#endif
|
||||
466
wled00/ir.cpp
Normal file
466
wled00/ir.cpp
Normal file
@@ -0,0 +1,466 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Infrared sensor support for generic 24/40/44 key RGB remotes
|
||||
*/
|
||||
|
||||
#if defined(WLED_DISABLE_INFRARED)
|
||||
void handleIR(){}
|
||||
#else
|
||||
|
||||
IRrecv* irrecv;
|
||||
//change pin in NpbWrapper.h
|
||||
|
||||
decode_results results;
|
||||
|
||||
unsigned long irCheckedTime = 0;
|
||||
uint32_t lastValidCode = 0;
|
||||
uint16_t irTimesRepeated = 0;
|
||||
uint8_t lastIR6ColourIdx = 0;
|
||||
|
||||
|
||||
//Add what your custom IR codes should trigger here. Guide: https://github.com/Aircoookie/WLED/wiki/Infrared-Control
|
||||
//IR codes themselves can be defined directly after "case" or in "ir_codes.h"
|
||||
bool decodeIRCustom(uint32_t code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
//just examples, feel free to modify or remove
|
||||
case IRCUSTOM_ONOFF : toggleOnOff(); break;
|
||||
case IRCUSTOM_MACRO1 : applyMacro(1); break;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
if (code != IRCUSTOM_MACRO1) colorUpdated(NOTIFIER_CALL_MODE_BUTTON); //don't update color again if we apply macro, it already does it
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//relatively change brightness, minumum A=5
|
||||
void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte higherBoundary)
|
||||
{
|
||||
int16_t new_val = (int16_t) *property + amount;
|
||||
if (new_val > higherBoundary) new_val = higherBoundary;
|
||||
else if (new_val < lowerBoundary) new_val = lowerBoundary;
|
||||
*property = (byte)constrain(new_val,0.1,255.1);
|
||||
}
|
||||
|
||||
void changeEffectSpeed(int8_t amount)
|
||||
{
|
||||
if (effectCurrent != 0) {
|
||||
int16_t new_val = (int16_t) effectSpeed + amount;
|
||||
effectSpeed = (byte)constrain(new_val,0.1,255.1);
|
||||
} else { // if Effect == "solid Color", change the hue of the primary color
|
||||
CRGB fastled_col;
|
||||
fastled_col.red = col[0];
|
||||
fastled_col.green = col[1];
|
||||
fastled_col.blue = col[2];
|
||||
CHSV prim_hsv = rgb2hsv_approximate(fastled_col);
|
||||
int16_t new_val = (int16_t) prim_hsv.h + amount;
|
||||
if (new_val > 255) new_val -= 255; // roll-over if bigger than 255
|
||||
if (new_val < 0) new_val += 255; // roll-over if smaller than 0
|
||||
prim_hsv.h = (byte)new_val;
|
||||
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
||||
col[0] = fastled_col.red;
|
||||
col[1] = fastled_col.green;
|
||||
col[2] = fastled_col.blue;
|
||||
}
|
||||
}
|
||||
|
||||
void changeEffectIntensity(int8_t amount)
|
||||
{
|
||||
if (effectCurrent != 0) {
|
||||
int16_t new_val = (int16_t) effectIntensity + amount;
|
||||
effectIntensity = (byte)constrain(new_val,0.1,255.1);
|
||||
} else { // if Effect == "solid Color", change the saturation of the primary color
|
||||
CRGB fastled_col;
|
||||
fastled_col.red = col[0];
|
||||
fastled_col.green = col[1];
|
||||
fastled_col.blue = col[2];
|
||||
CHSV prim_hsv = rgb2hsv_approximate(fastled_col);
|
||||
int16_t new_val = (int16_t) prim_hsv.s + amount;
|
||||
prim_hsv.s = (byte)constrain(new_val,0.1,255.1); // constrain to 0-255
|
||||
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
||||
col[0] = fastled_col.red;
|
||||
col[1] = fastled_col.green;
|
||||
col[2] = fastled_col.blue;
|
||||
}
|
||||
}
|
||||
|
||||
void decodeIR(uint32_t code)
|
||||
{
|
||||
if (code == 0xFFFFFFFF) //repeated code, continue brightness up/down
|
||||
{
|
||||
irTimesRepeated++;
|
||||
if (lastValidCode == IR24_BRIGHTER || lastValidCode == IR40_BPLUS )
|
||||
{
|
||||
relativeChange(&bri, 10); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
else if (lastValidCode == IR24_DARKER || lastValidCode == IR40_BMINUS )
|
||||
{
|
||||
relativeChange(&bri, -10, 5); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
if (lastValidCode == IR40_WPLUS)
|
||||
{
|
||||
relativeChangeWhite(10); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
else if (lastValidCode == IR40_WMINUS)
|
||||
{
|
||||
relativeChangeWhite(-10, 5); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
else if ((lastValidCode == IR24_ON || lastValidCode == IR40_ON) && irTimesRepeated > 7 )
|
||||
{
|
||||
nightlightActive = true;
|
||||
nightlightStartTime = millis();
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
return;
|
||||
}
|
||||
lastValidCode = 0; irTimesRepeated = 0;
|
||||
|
||||
if (decodeIRCustom(code)) return;
|
||||
if (code > 0xFFFFFF) return; //invalid code
|
||||
else if (code > 0xF70000 && code < 0xF80000) decodeIR24(code); //is in 24-key remote range
|
||||
else if (code > 0xFF0000) {
|
||||
switch (irEnabled) {
|
||||
case 1: decodeIR24OLD(code); break; // white 24-key remote (old) - it sends 0xFF0000 values
|
||||
case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys
|
||||
case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys
|
||||
case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys
|
||||
case 5: decodeIR21(code); break; // white 21-key remote
|
||||
case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness,
|
||||
// "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE"
|
||||
// sets bright plain white
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
if (nightlightActive && bri == 0) nightlightActive = false;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); //for notifier, IR is considered a button input
|
||||
//code <= 0xF70000 also invalid
|
||||
}
|
||||
|
||||
|
||||
void decodeIR24(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR24_BRIGHTER : relativeChange(&bri, 10); break;
|
||||
case IR24_DARKER : relativeChange(&bri, -10, 5); break;
|
||||
case IR24_OFF : briLast = bri; bri = 0; break;
|
||||
case IR24_ON : bri = briLast; break;
|
||||
case IR24_RED : colorFromUint32(COLOR_RED); break;
|
||||
case IR24_REDDISH : colorFromUint32(COLOR_REDDISH); break;
|
||||
case IR24_ORANGE : colorFromUint32(COLOR_ORANGE); break;
|
||||
case IR24_YELLOWISH : colorFromUint32(COLOR_YELLOWISH); break;
|
||||
case IR24_YELLOW : colorFromUint32(COLOR_YELLOW); break;
|
||||
case IR24_GREEN : colorFromUint32(COLOR_GREEN); break;
|
||||
case IR24_GREENISH : colorFromUint32(COLOR_GREENISH); break;
|
||||
case IR24_TURQUOISE : colorFromUint32(COLOR_TURQUOISE); break;
|
||||
case IR24_CYAN : colorFromUint32(COLOR_CYAN); break;
|
||||
case IR24_AQUA : colorFromUint32(COLOR_AQUA); break;
|
||||
case IR24_BLUE : colorFromUint32(COLOR_BLUE); break;
|
||||
case IR24_DEEPBLUE : colorFromUint32(COLOR_DEEPBLUE); break;
|
||||
case IR24_PURPLE : colorFromUint32(COLOR_PURPLE); break;
|
||||
case IR24_MAGENTA : colorFromUint32(COLOR_MAGENTA); break;
|
||||
case IR24_PINK : colorFromUint32(COLOR_PINK); break;
|
||||
case IR24_WHITE : colorFromUint32(COLOR_WHITE); effectCurrent = 0; break;
|
||||
case IR24_FLASH : if (!applyPreset(1)) effectCurrent = FX_MODE_COLORTWINKLE; break;
|
||||
case IR24_STROBE : if (!applyPreset(2)) effectCurrent = FX_MODE_RAINBOW_CYCLE; break;
|
||||
case IR24_FADE : if (!applyPreset(3)) effectCurrent = FX_MODE_BREATH; break;
|
||||
case IR24_SMOOTH : if (!applyPreset(4)) effectCurrent = FX_MODE_RAINBOW; break;
|
||||
default: return;
|
||||
}
|
||||
lastValidCode = code;
|
||||
}
|
||||
|
||||
void decodeIR24OLD(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR24_OLD_BRIGHTER : relativeChange(&bri, 10); break;
|
||||
case IR24_OLD_DARKER : relativeChange(&bri, -10, 5); break;
|
||||
case IR24_OLD_OFF : briLast = bri; bri = 0; break;
|
||||
case IR24_OLD_ON : bri = briLast; break;
|
||||
case IR24_OLD_RED : colorFromUint32(COLOR_RED); break;
|
||||
case IR24_OLD_REDDISH : colorFromUint32(COLOR_REDDISH); break;
|
||||
case IR24_OLD_ORANGE : colorFromUint32(COLOR_ORANGE); break;
|
||||
case IR24_OLD_YELLOWISH : colorFromUint32(COLOR_YELLOWISH); break;
|
||||
case IR24_OLD_YELLOW : colorFromUint32(COLOR_YELLOW); break;
|
||||
case IR24_OLD_GREEN : colorFromUint32(COLOR_GREEN); break;
|
||||
case IR24_OLD_GREENISH : colorFromUint32(COLOR_GREENISH); break;
|
||||
case IR24_OLD_TURQUOISE : colorFromUint32(COLOR_TURQUOISE); break;
|
||||
case IR24_OLD_CYAN : colorFromUint32(COLOR_CYAN); break;
|
||||
case IR24_OLD_AQUA : colorFromUint32(COLOR_AQUA); break;
|
||||
case IR24_OLD_BLUE : colorFromUint32(COLOR_BLUE); break;
|
||||
case IR24_OLD_DEEPBLUE : colorFromUint32(COLOR_DEEPBLUE); break;
|
||||
case IR24_OLD_PURPLE : colorFromUint32(COLOR_PURPLE); break;
|
||||
case IR24_OLD_MAGENTA : colorFromUint32(COLOR_MAGENTA); break;
|
||||
case IR24_OLD_PINK : colorFromUint32(COLOR_PINK); break;
|
||||
case IR24_OLD_WHITE : colorFromUint32(COLOR_WHITE); effectCurrent = 0; break;
|
||||
case IR24_OLD_FLASH : if (!applyPreset(1)) { effectCurrent = FX_MODE_COLORTWINKLE; effectPalette = 0; } break;
|
||||
case IR24_OLD_STROBE : if (!applyPreset(2)) { effectCurrent = FX_MODE_RAINBOW_CYCLE; effectPalette = 0; } break;
|
||||
case IR24_OLD_FADE : if (!applyPreset(3)) { effectCurrent = FX_MODE_BREATH; effectPalette = 0; } break;
|
||||
case IR24_OLD_SMOOTH : if (!applyPreset(4)) { effectCurrent = FX_MODE_RAINBOW; effectPalette = 0; } break;
|
||||
default: return;
|
||||
}
|
||||
lastValidCode = code;
|
||||
}
|
||||
|
||||
|
||||
void decodeIR24CT(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR24_CT_BRIGHTER : relativeChange(&bri, 10); break;
|
||||
case IR24_CT_DARKER : relativeChange(&bri, -10, 5); break;
|
||||
case IR24_CT_OFF : briLast = bri; bri = 0; break;
|
||||
case IR24_CT_ON : bri = briLast; break;
|
||||
case IR24_CT_RED : colorFromUint32(COLOR_RED); break;
|
||||
case IR24_CT_REDDISH : colorFromUint32(COLOR_REDDISH); break;
|
||||
case IR24_CT_ORANGE : colorFromUint32(COLOR_ORANGE); break;
|
||||
case IR24_CT_YELLOWISH : colorFromUint32(COLOR_YELLOWISH); break;
|
||||
case IR24_CT_YELLOW : colorFromUint32(COLOR_YELLOW); break;
|
||||
case IR24_CT_GREEN : colorFromUint32(COLOR_GREEN); break;
|
||||
case IR24_CT_GREENISH : colorFromUint32(COLOR_GREENISH); break;
|
||||
case IR24_CT_TURQUOISE : colorFromUint32(COLOR_TURQUOISE); break;
|
||||
case IR24_CT_CYAN : colorFromUint32(COLOR_CYAN); break;
|
||||
case IR24_CT_AQUA : colorFromUint32(COLOR_AQUA); break;
|
||||
case IR24_CT_BLUE : colorFromUint32(COLOR_BLUE); break;
|
||||
case IR24_CT_DEEPBLUE : colorFromUint32(COLOR_DEEPBLUE); break;
|
||||
case IR24_CT_PURPLE : colorFromUint32(COLOR_PURPLE); break;
|
||||
case IR24_CT_MAGENTA : colorFromUint32(COLOR_MAGENTA); break;
|
||||
case IR24_CT_PINK : colorFromUint32(COLOR_PINK); break;
|
||||
case IR24_CT_COLDWHITE : colorFromUint32(COLOR2_COLDWHITE); effectCurrent = 0; break;
|
||||
case IR24_CT_WARMWHITE : colorFromUint32(COLOR2_WARMWHITE); effectCurrent = 0; break;
|
||||
case IR24_CT_CTPLUS : colorFromUint32(COLOR2_COLDWHITE2); effectCurrent = 0; break;
|
||||
case IR24_CT_CTMINUS : colorFromUint32(COLOR2_WARMWHITE2); effectCurrent = 0; break;
|
||||
case IR24_CT_MEMORY : {
|
||||
if (col[3] > 0) col[3] = 0;
|
||||
else colorFromUint32(COLOR2_NEUTRALWHITE); effectCurrent = 0; } break;
|
||||
default: return;
|
||||
}
|
||||
lastValidCode = code;
|
||||
}
|
||||
|
||||
|
||||
void decodeIR40(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR40_BPLUS : relativeChange(&bri, 10); break;
|
||||
case IR40_BMINUS : relativeChange(&bri, -10, 5); break;
|
||||
case IR40_OFF : briLast = bri; bri = 0; break;
|
||||
case IR40_ON : bri = briLast; break;
|
||||
case IR40_RED : colorFromUint24(COLOR_RED); break;
|
||||
case IR40_REDDISH : colorFromUint24(COLOR_REDDISH); break;
|
||||
case IR40_ORANGE : colorFromUint24(COLOR_ORANGE); break;
|
||||
case IR40_YELLOWISH : colorFromUint24(COLOR_YELLOWISH); break;
|
||||
case IR40_YELLOW : colorFromUint24(COLOR_YELLOW); break;
|
||||
case IR40_GREEN : colorFromUint24(COLOR_GREEN); break;
|
||||
case IR40_GREENISH : colorFromUint24(COLOR_GREENISH); break;
|
||||
case IR40_TURQUOISE : colorFromUint24(COLOR_TURQUOISE); break;
|
||||
case IR40_CYAN : colorFromUint24(COLOR_CYAN); break;
|
||||
case IR40_AQUA : colorFromUint24(COLOR_AQUA); break;
|
||||
case IR40_BLUE : colorFromUint24(COLOR_BLUE); break;
|
||||
case IR40_DEEPBLUE : colorFromUint24(COLOR_DEEPBLUE); break;
|
||||
case IR40_PURPLE : colorFromUint24(COLOR_PURPLE); break;
|
||||
case IR40_MAGENTA : colorFromUint24(COLOR_MAGENTA); break;
|
||||
case IR40_PINK : colorFromUint24(COLOR_PINK); break;
|
||||
case IR40_WARMWHITE2 : {
|
||||
if (useRGBW) { colorFromUint32(COLOR2_WARMWHITE2); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_WARMWHITE2); } break;
|
||||
case IR40_WARMWHITE : {
|
||||
if (useRGBW) { colorFromUint32(COLOR2_WARMWHITE); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_WARMWHITE); } break;
|
||||
case IR40_WHITE : {
|
||||
if (useRGBW) { colorFromUint32(COLOR2_NEUTRALWHITE); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_NEUTRALWHITE); } break;
|
||||
case IR40_COLDWHITE : {
|
||||
if (useRGBW) { colorFromUint32(COLOR2_COLDWHITE); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_COLDWHITE); } break;
|
||||
case IR40_COLDWHITE2 : {
|
||||
if (useRGBW) { colorFromUint32(COLOR2_COLDWHITE2); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_COLDWHITE2); } break;
|
||||
case IR40_WPLUS : relativeChangeWhite(10); break;
|
||||
case IR40_WMINUS : relativeChangeWhite(-10, 5); break;
|
||||
case IR40_WOFF : whiteLast = col[3]; col[3] = 0; break;
|
||||
case IR40_WON : col[3] = whiteLast; break;
|
||||
case IR40_W25 : bri = 63; break;
|
||||
case IR40_W50 : bri = 127; break;
|
||||
case IR40_W75 : bri = 191; break;
|
||||
case IR40_W100 : bri = 255; break;
|
||||
case IR40_QUICK : changeEffectSpeed( 16); break;
|
||||
case IR40_SLOW : changeEffectSpeed(-16); break;
|
||||
case IR40_JUMP7 : changeEffectIntensity( 16); break;
|
||||
case IR40_AUTO : changeEffectIntensity(-16); break;
|
||||
case IR40_JUMP3 : if (!applyPreset(1)) { effectCurrent = FX_MODE_STATIC; effectPalette = 0; } break;
|
||||
case IR40_FADE3 : if (!applyPreset(2)) { effectCurrent = FX_MODE_BREATH; effectPalette = 0; } break;
|
||||
case IR40_FADE7 : if (!applyPreset(3)) { effectCurrent = FX_MODE_FIRE_FLICKER; effectPalette = 0; } break;
|
||||
case IR40_FLASH : if (!applyPreset(4)) { effectCurrent = FX_MODE_RAINBOW; effectPalette = 0; } break;
|
||||
}
|
||||
lastValidCode = code;
|
||||
}
|
||||
|
||||
void decodeIR44(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR44_BPLUS : relativeChange(&bri, 10); break;
|
||||
case IR44_BMINUS : relativeChange(&bri, -10, 5); break;
|
||||
case IR44_OFF : briLast = bri; bri = 0; break;
|
||||
case IR44_ON : bri = briLast; break;
|
||||
case IR44_RED : colorFromUint24(COLOR_RED); break;
|
||||
case IR44_REDDISH : colorFromUint24(COLOR_REDDISH); break;
|
||||
case IR44_ORANGE : colorFromUint24(COLOR_ORANGE); break;
|
||||
case IR44_YELLOWISH : colorFromUint24(COLOR_YELLOWISH); break;
|
||||
case IR44_YELLOW : colorFromUint24(COLOR_YELLOW); break;
|
||||
case IR44_GREEN : colorFromUint24(COLOR_GREEN); break;
|
||||
case IR44_GREENISH : colorFromUint24(COLOR_GREENISH); break;
|
||||
case IR44_TURQUOISE : colorFromUint24(COLOR_TURQUOISE); break;
|
||||
case IR44_CYAN : colorFromUint24(COLOR_CYAN); break;
|
||||
case IR44_AQUA : colorFromUint24(COLOR_AQUA); break;
|
||||
case IR44_BLUE : colorFromUint24(COLOR_BLUE); break;
|
||||
case IR44_DEEPBLUE : colorFromUint24(COLOR_DEEPBLUE); break;
|
||||
case IR44_PURPLE : colorFromUint24(COLOR_PURPLE); break;
|
||||
case IR44_MAGENTA : colorFromUint24(COLOR_MAGENTA); break;
|
||||
case IR44_PINK : colorFromUint24(COLOR_PINK); break;
|
||||
case IR44_WHITE : {
|
||||
if (useRGBW) {
|
||||
if (col[3] > 0) col[3] = 0;
|
||||
else { colorFromUint32(COLOR2_NEUTRALWHITE); effectCurrent = 0; }
|
||||
} else colorFromUint24(COLOR_NEUTRALWHITE); } break;
|
||||
case IR44_WARMWHITE2 : {
|
||||
if (useRGBW) { colorFromUint32(COLOR2_WARMWHITE2); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_WARMWHITE2); } break;
|
||||
case IR44_WARMWHITE : {
|
||||
if (useRGBW) { colorFromUint32(COLOR2_WARMWHITE); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_WARMWHITE); } break;
|
||||
case IR44_COLDWHITE : {
|
||||
if (useRGBW) { colorFromUint32(COLOR2_COLDWHITE); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_COLDWHITE); } break;
|
||||
case IR44_COLDWHITE2 : {
|
||||
if (useRGBW) { colorFromUint32(COLOR2_COLDWHITE2); effectCurrent = 0; }
|
||||
else colorFromUint24(COLOR_COLDWHITE2); } break;
|
||||
case IR44_REDPLUS : relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break;
|
||||
case IR44_REDMINUS : relativeChange(&effectCurrent, -1, 0); break;
|
||||
case IR44_GREENPLUS : relativeChange(&effectPalette, 1, 0, strip.getPaletteCount() -1); break;
|
||||
case IR44_GREENMINUS : relativeChange(&effectPalette, -1, 0); break;
|
||||
case IR44_BLUEPLUS : changeEffectIntensity( 16); break;
|
||||
case IR44_BLUEMINUS : changeEffectIntensity(-16); break;
|
||||
case IR44_QUICK : changeEffectSpeed( 16); break;
|
||||
case IR44_SLOW : changeEffectSpeed(-16); break;
|
||||
case IR44_DIY1 : if (!applyPreset(1)) { effectCurrent = FX_MODE_STATIC; effectPalette = 0; } break;
|
||||
case IR44_DIY2 : if (!applyPreset(2)) { effectCurrent = FX_MODE_BREATH; effectPalette = 0; } break;
|
||||
case IR44_DIY3 : if (!applyPreset(3)) { effectCurrent = FX_MODE_FIRE_FLICKER; effectPalette = 0; } break;
|
||||
case IR44_DIY4 : if (!applyPreset(4)) { effectCurrent = FX_MODE_RAINBOW; effectPalette = 0; } break;
|
||||
case IR44_DIY5 : if (!applyPreset(5)) { effectCurrent = FX_MODE_METEOR_SMOOTH; effectPalette = 0; } break;
|
||||
case IR44_DIY6 : if (!applyPreset(6)) { effectCurrent = FX_MODE_RAIN; effectPalette = 0; } break;
|
||||
case IR44_AUTO : effectCurrent = FX_MODE_STATIC; break;
|
||||
case IR44_FLASH : effectCurrent = FX_MODE_PALETTE; break;
|
||||
case IR44_JUMP3 : bri = 63; break;
|
||||
case IR44_JUMP7 : bri = 127; break;
|
||||
case IR44_FADE3 : bri = 191; break;
|
||||
case IR44_FADE7 : bri = 255; break;
|
||||
}
|
||||
lastValidCode = code;
|
||||
}
|
||||
|
||||
void decodeIR21(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR21_BRIGHTER: relativeChange(&bri, 10); break;
|
||||
case IR21_DARKER: relativeChange(&bri, -10, 5); break;
|
||||
case IR21_OFF: briLast = bri; bri = 0; break;
|
||||
case IR21_ON: bri = briLast; break;
|
||||
case IR21_RED: colorFromUint32(COLOR_RED); break;
|
||||
case IR21_REDDISH: colorFromUint32(COLOR_REDDISH); break;
|
||||
case IR21_ORANGE: colorFromUint32(COLOR_ORANGE); break;
|
||||
case IR21_YELLOWISH: colorFromUint32(COLOR_YELLOWISH); break;
|
||||
case IR21_GREEN: colorFromUint32(COLOR_GREEN); break;
|
||||
case IR21_GREENISH: colorFromUint32(COLOR_GREENISH); break;
|
||||
case IR21_TURQUOISE: colorFromUint32(COLOR_TURQUOISE); break;
|
||||
case IR21_CYAN: colorFromUint32(COLOR_CYAN); break;
|
||||
case IR21_BLUE: colorFromUint32(COLOR_BLUE); break;
|
||||
case IR21_DEEPBLUE: colorFromUint32(COLOR_DEEPBLUE); break;
|
||||
case IR21_PURPLE: colorFromUint32(COLOR_PURPLE); break;
|
||||
case IR21_PINK: colorFromUint32(COLOR_PINK); break;
|
||||
case IR21_WHITE: colorFromUint32(COLOR_WHITE); effectCurrent = 0; break;
|
||||
case IR21_FLASH: if (!applyPreset(1)) { effectCurrent = FX_MODE_COLORTWINKLE; effectPalette = 0; } break;
|
||||
case IR21_STROBE: if (!applyPreset(2)) { effectCurrent = FX_MODE_RAINBOW_CYCLE; effectPalette = 0; } break;
|
||||
case IR21_FADE: if (!applyPreset(3)) { effectCurrent = FX_MODE_BREATH; effectPalette = 0; } break;
|
||||
case IR21_SMOOTH: if (!applyPreset(4)) { effectCurrent = FX_MODE_RAINBOW; effectPalette = 0; } break;
|
||||
default: return;
|
||||
}
|
||||
lastValidCode = code;
|
||||
}
|
||||
|
||||
void decodeIR6(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR6_POWER: toggleOnOff(); break;
|
||||
case IR6_CHANNEL_UP: relativeChange(&bri, 10); break;
|
||||
case IR6_CHANNEL_DOWN: relativeChange(&bri, -10, 5); break;
|
||||
case IR6_VOLUME_UP: relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break; // next effect
|
||||
case IR6_VOLUME_DOWN: // next palette
|
||||
relativeChange(&effectPalette, 1, 0, strip.getPaletteCount() -1);
|
||||
switch(lastIR6ColourIdx) {
|
||||
case 0: colorFromUint32(COLOR_RED); break;
|
||||
case 1: colorFromUint32(COLOR_REDDISH); break;
|
||||
case 2: colorFromUint32(COLOR_ORANGE); break;
|
||||
case 3: colorFromUint32(COLOR_YELLOWISH); break;
|
||||
case 4: colorFromUint32(COLOR_GREEN); break;
|
||||
case 5: colorFromUint32(COLOR_GREENISH); break;
|
||||
case 6: colorFromUint32(COLOR_TURQUOISE); break;
|
||||
case 7: colorFromUint32(COLOR_CYAN); break;
|
||||
case 8: colorFromUint32(COLOR_BLUE); break;
|
||||
case 9: colorFromUint32(COLOR_DEEPBLUE); break;
|
||||
case 10:colorFromUint32(COLOR_PURPLE); break;
|
||||
case 11:colorFromUint32(COLOR_PINK); break;
|
||||
case 12:colorFromUint32(COLOR_WHITE); break;
|
||||
default: break;
|
||||
}
|
||||
lastIR6ColourIdx++;
|
||||
if(lastIR6ColourIdx > 12) lastIR6ColourIdx = 0; break;
|
||||
case IR6_MUTE: effectCurrent = 0; effectPalette = 0; colorFromUint32(COLOR_WHITE); bri=255; break;
|
||||
}
|
||||
lastValidCode = code;
|
||||
}
|
||||
|
||||
|
||||
void initIR()
|
||||
{
|
||||
if (irEnabled > 0)
|
||||
{
|
||||
irrecv = new IRrecv(IR_PIN);
|
||||
irrecv->enableIRIn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handleIR()
|
||||
{
|
||||
if (irEnabled > 0 && millis() - irCheckedTime > 120)
|
||||
{
|
||||
irCheckedTime = millis();
|
||||
if (irEnabled > 0)
|
||||
{
|
||||
if (irrecv == NULL)
|
||||
{
|
||||
initIR(); return;
|
||||
}
|
||||
|
||||
if (irrecv->decode(&results))
|
||||
{
|
||||
if (results.value != 0) // only print results if anything is received ( != 0 )
|
||||
{
|
||||
Serial.print("IR recv\r\n0x");
|
||||
Serial.println((uint32_t)results.value, HEX);
|
||||
Serial.println();
|
||||
}
|
||||
decodeIR(results.value);
|
||||
irrecv->resume();
|
||||
}
|
||||
} else if (irrecv != NULL)
|
||||
{
|
||||
irrecv->disableIRIn();
|
||||
delete irrecv; irrecv = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -4,6 +4,16 @@
|
||||
#define IRCUSTOM_ONOFF 0xA55AEA15 //Pioneer RC-975R "+FAV" button (example)
|
||||
#define IRCUSTOM_MACRO1 0xFFFFFFFF //placeholder, will never be checked for
|
||||
|
||||
// Default IR codes for 6-key learning remote https://www.aliexpress.com/item/4000307837886.html
|
||||
// This cheap remote has the advantage of being more powerful (longer range) than cheap credit-card remotes
|
||||
#define IR6_POWER 0xFF0FF0
|
||||
#define IR6_CHANNEL_UP 0xFF8F70
|
||||
#define IR6_CHANNEL_DOWN 0xFF4FB0
|
||||
#define IR6_VOLUME_UP 0xFFCF30
|
||||
#define IR6_VOLUME_DOWN 0xFF2FD0
|
||||
#define IR6_MUTE 0xFFAF50
|
||||
|
||||
|
||||
//Infrared codes for 24-key remote from http://woodsgood.ca/projects/2015/02/13/rgb-led-strip-controllers-ir-codes/
|
||||
#define IR24_BRIGHTER 0xF700FF
|
||||
#define IR24_DARKER 0xF7807F
|
||||
@@ -30,52 +40,168 @@
|
||||
#define IR24_FADE 0xF7C837
|
||||
#define IR24_SMOOTH 0xF7E817
|
||||
|
||||
/* 44-key defs, to be done later
|
||||
#define IR44_BPlus 0xFF3AC5 //
|
||||
#define IR44_BMinus 0xFFBA45 //
|
||||
#define IR44_ON 0xFF827D //
|
||||
#define IR44_OFF 0xFF02FD //
|
||||
#define IR44_R 0xFF1AE5 //
|
||||
#define IR44_G 0xFF9A65 //
|
||||
#define IR44_B 0xFFA25D //
|
||||
#define IR44_W 0xFF22DD //
|
||||
#define IR44_B1 0xFF2AD5 //
|
||||
#define IR44_B2 0xFFAA55 //
|
||||
#define IR44_B3 0xFF926D //
|
||||
#define IR44_B4 0xFF12ED //
|
||||
#define IR44_B5 0xFF0AF5 //
|
||||
#define IR44_B6 0xFF8A75 //
|
||||
#define IR44_B7 0xFFB24D //
|
||||
#define IR44_B8 0xFF32CD //
|
||||
#define IR44_B9 0xFF38C7 //
|
||||
#define IR44_B10 0xFFB847 //
|
||||
#define IR44_B11 0xFF7887 //
|
||||
#define IR44_B12 0xFFF807 //
|
||||
#define IR44_B13 0xFF18E7 //
|
||||
#define IR44_B14 0xFF9867 //
|
||||
#define IR44_B15 0xFF58A7 //
|
||||
#define IR44_B16 0xFFD827 //
|
||||
#define IR44_UPR 0xFF28D7 //
|
||||
#define IR44_UPG 0xFFA857 //
|
||||
#define IR44_UPB 0xFF6897 //
|
||||
#define IR44_QUICK 0xFFE817 //
|
||||
#define IR44_DOWNR 0xFF08F7 //
|
||||
#define IR44_DOWNG 0xFF8877 //
|
||||
#define IR44_DOWNB 0xFF48B7 //
|
||||
#define IR44_SLOW 0xFFC837 //
|
||||
#define IR44_DIY1 0xFF30CF //
|
||||
#define IR44_DIY2 0xFFB04F //
|
||||
#define IR44_DIY3 0xFF708F //
|
||||
#define IR44_AUTO 0xFFF00F //
|
||||
#define IR44_DIY4 0xFF10EF //
|
||||
#define IR44_DIY5 0xFF906F //
|
||||
#define IR44_DIY6 0xFF50AF //
|
||||
#define IR44_FLASH 0xFFD02F //
|
||||
#define IR44_JUMP3 0xFF20DF //
|
||||
#define IR44_JUMP7 0xFFA05F //
|
||||
#define IR44_FADE3 0xFF609F //
|
||||
#define IR44_FADE7 0xFFE01F //
|
||||
*/
|
||||
// 24-key defs for white remote control with CW / WW / CT+ and CT- keys (from ALDI LED pillar lamp)
|
||||
#define IR24_CT_BRIGHTER 0xF700FF // BRI +
|
||||
#define IR24_CT_DARKER 0xF7807F // BRI -
|
||||
#define IR24_CT_OFF 0xF740BF // OFF
|
||||
#define IR24_CT_ON 0xF7C03F // ON
|
||||
#define IR24_CT_RED 0xF720DF // RED
|
||||
#define IR24_CT_REDDISH 0xF710EF // REDDISH
|
||||
#define IR24_CT_ORANGE 0xF730CF // ORANGE
|
||||
#define IR24_CT_YELLOWISH 0xF708F7 // YELLOWISH
|
||||
#define IR24_CT_YELLOW 0xF728D7 // YELLOW
|
||||
#define IR24_CT_GREEN 0xF7A05F // GREEN
|
||||
#define IR24_CT_GREENISH 0xF7906F // GREENISH
|
||||
#define IR24_CT_TURQUOISE 0xF7B04F // TURQUOISE
|
||||
#define IR24_CT_CYAN 0xF78877 // CYAN
|
||||
#define IR24_CT_AQUA 0xF7A857 // AQUA
|
||||
#define IR24_CT_BLUE 0xF7609F // BLUE
|
||||
#define IR24_CT_DEEPBLUE 0xF750AF // DEEPBLUE
|
||||
#define IR24_CT_PURPLE 0xF7708F // PURPLE
|
||||
#define IR24_CT_MAGENTA 0xF748B7 // MAGENTA
|
||||
#define IR24_CT_PINK 0xF76897 // PINK
|
||||
#define IR24_CT_COLDWHITE 0xF7E01F // CW
|
||||
#define IR24_CT_WARMWHITE 0xF7D02F // WW
|
||||
#define IR24_CT_CTPLUS 0xF7F00F // CT+
|
||||
#define IR24_CT_CTMINUS 0xF7C837 // CT-
|
||||
#define IR24_CT_MEMORY 0xF7E817 // MEMORY
|
||||
|
||||
// 24-key defs for old remote control
|
||||
#define IR24_OLD_BRIGHTER 0xFF906F // Brightness Up
|
||||
#define IR24_OLD_DARKER 0xFFB847 // Brightness Down
|
||||
#define IR24_OLD_OFF 0xFFF807 // Power OFF
|
||||
#define IR24_OLD_ON 0xFFB04F // Power On
|
||||
#define IR24_OLD_RED 0xFF9867 // RED
|
||||
#define IR24_OLD_REDDISH 0xFFE817 // Light RED
|
||||
#define IR24_OLD_ORANGE 0xFF02FD // Orange
|
||||
#define IR24_OLD_YELLOWISH 0xFF50AF // Light Orange
|
||||
#define IR24_OLD_YELLOW 0xFF38C7 // YELLOW
|
||||
#define IR24_OLD_GREEN 0xFFD827 // GREEN
|
||||
#define IR24_OLD_GREENISH 0xFF48B7 // Light GREEN
|
||||
#define IR24_OLD_TURQUOISE 0xFF32CD // TURQUOISE
|
||||
#define IR24_OLD_CYAN 0xFF7887 // CYAN
|
||||
#define IR24_OLD_AQUA 0xFF28D7 // AQUA
|
||||
#define IR24_OLD_BLUE 0xFF8877 // BLUE
|
||||
#define IR24_OLD_DEEPBLUE 0xFF6897 // Dark BLUE
|
||||
#define IR24_OLD_PURPLE 0xFF20DF // PURPLE
|
||||
#define IR24_OLD_MAGENTA 0xFF708F // MAGENTA
|
||||
#define IR24_OLD_PINK 0xFFF00F // PINK
|
||||
#define IR24_OLD_WHITE 0xFFA857 // WHITE
|
||||
#define IR24_OLD_FLASH 0xFFB24D // FLASH Mode
|
||||
#define IR24_OLD_STROBE 0xFF00FF // STROBE Mode
|
||||
#define IR24_OLD_FADE 0xFF58A7 // FADE Mode
|
||||
#define IR24_OLD_SMOOTH 0xFF30CF // SMOOTH Mode
|
||||
|
||||
// 40-key defs for blue remote control
|
||||
#define IR40_BPLUS 0xFF3AC5 //
|
||||
#define IR40_BMINUS 0xFFBA45 //
|
||||
#define IR40_OFF 0xFF827D //
|
||||
#define IR40_ON 0xFF02FD //
|
||||
#define IR40_RED 0xFF1AE5 //
|
||||
#define IR40_GREEN 0xFF9A65 //
|
||||
#define IR40_BLUE 0xFFA25D //
|
||||
#define IR40_WHITE 0xFF22DD // natural white
|
||||
#define IR40_REDDISH 0xFF2AD5 //
|
||||
#define IR40_GREENISH 0xFFAA55 //
|
||||
#define IR40_DEEPBLUE 0xFF926D //
|
||||
#define IR40_WARMWHITE2 0xFF12ED // warmest white
|
||||
#define IR40_ORANGE 0xFF0AF5 //
|
||||
#define IR40_TURQUOISE 0xFF8A75 //
|
||||
#define IR40_PURPLE 0xFFB24D //
|
||||
#define IR40_WARMWHITE 0xFF32CD // warm white
|
||||
#define IR40_YELLOWISH 0xFF38C7 //
|
||||
#define IR40_CYAN 0xFFB847 //
|
||||
#define IR40_MAGENTA 0xFF7887 //
|
||||
#define IR40_COLDWHITE 0xFFF807 // cold white
|
||||
#define IR40_YELLOW 0xFF18E7 //
|
||||
#define IR40_AQUA 0xFF9867 //
|
||||
#define IR40_PINK 0xFF58A7 //
|
||||
#define IR40_COLDWHITE2 0xFFD827 // coldest white
|
||||
#define IR40_WPLUS 0xFF28D7 // white chanel bright plus
|
||||
#define IR40_WMINUS 0xFFA857 // white chanel bright minus
|
||||
#define IR40_WOFF 0xFF6897 // white chanel on
|
||||
#define IR40_WON 0xFFE817 // white chanel off
|
||||
#define IR40_W25 0xFF08F7 // white chanel 25%
|
||||
#define IR40_W50 0xFF8877 // white chanel 50%
|
||||
#define IR40_W75 0xFF48B7 // white chanel 75%
|
||||
#define IR40_W100 0xFFC837 // white chanel 100%
|
||||
#define IR40_JUMP3 0xFF30CF // JUMP3
|
||||
#define IR40_FADE3 0xFFB04F // FADE3
|
||||
#define IR40_JUMP7 0xFF708F // JUMP7
|
||||
#define IR40_QUICK 0xFFF00F // QUICK
|
||||
#define IR40_FADE7 0xFF10EF // FADE7
|
||||
#define IR40_FLASH 0xFF906F // FLASH
|
||||
#define IR40_AUTO 0xFF50AF // AUTO
|
||||
#define IR40_SLOW 0xFFD02F // SLOW
|
||||
|
||||
// 44-key defs, to be done later
|
||||
#define IR44_BPLUS 0xFF3AC5 //
|
||||
#define IR44_BMINUS 0xFFBA45 //
|
||||
#define IR44_OFF 0xFF827D //
|
||||
#define IR44_ON 0xFF02FD //
|
||||
#define IR44_RED 0xFF1AE5 //
|
||||
#define IR44_GREEN 0xFF9A65 //
|
||||
#define IR44_BLUE 0xFFA25D //
|
||||
#define IR44_WHITE 0xFF22DD // natural white
|
||||
#define IR44_REDDISH 0xFF2AD5 //
|
||||
#define IR44_GREENISH 0xFFAA55 //
|
||||
#define IR44_DEEPBLUE 0xFF926D //
|
||||
#define IR44_WARMWHITE2 0xFF12ED // warmest white
|
||||
#define IR44_ORANGE 0xFF0AF5 //
|
||||
#define IR44_TURQUOISE 0xFF8A75 //
|
||||
#define IR44_PURPLE 0xFFB24D //
|
||||
#define IR44_WARMWHITE 0xFF32CD // warm white
|
||||
#define IR44_YELLOWISH 0xFF38C7 //
|
||||
#define IR44_CYAN 0xFFB847 //
|
||||
#define IR44_MAGENTA 0xFF7887 //
|
||||
#define IR44_COLDWHITE 0xFFF807 // cold white
|
||||
#define IR44_YELLOW 0xFF18E7 //
|
||||
#define IR44_AQUA 0xFF9867 //
|
||||
#define IR44_PINK 0xFF58A7 //
|
||||
#define IR44_COLDWHITE2 0xFFD827 // coldest white
|
||||
#define IR44_REDPLUS 0xFF28D7 //
|
||||
#define IR44_GREENPLUS 0xFFA857 //
|
||||
#define IR44_BLUEPLUS 0xFF6897 //
|
||||
#define IR44_QUICK 0xFFE817 //
|
||||
#define IR44_REDMINUS 0xFF08F7 //
|
||||
#define IR44_GREENMINUS 0xFF8877 //
|
||||
#define IR44_BLUEMINUS 0xFF48B7 //
|
||||
#define IR44_SLOW 0xFFC837 //
|
||||
#define IR44_DIY1 0xFF30CF //
|
||||
#define IR44_DIY2 0xFFB04F //
|
||||
#define IR44_DIY3 0xFF708F //
|
||||
#define IR44_AUTO 0xFFF00F //
|
||||
#define IR44_DIY4 0xFF10EF //
|
||||
#define IR44_DIY5 0xFF906F //
|
||||
#define IR44_DIY6 0xFF50AF //
|
||||
#define IR44_FLASH 0xFFD02F //
|
||||
#define IR44_JUMP3 0xFF20DF //
|
||||
#define IR44_JUMP7 0xFFA05F //
|
||||
#define IR44_FADE3 0xFF609F //
|
||||
#define IR44_FADE7 0xFFE01F //
|
||||
|
||||
//Infrared codes for 21-key remote https://images-na.ssl-images-amazon.com/images/I/51NMA0XucnL.jpg
|
||||
#define IR21_BRIGHTER 0xFFE01F
|
||||
#define IR21_DARKER 0xFFA857
|
||||
#define IR21_OFF 0xFF629D
|
||||
#define IR21_ON 0xFFA25D
|
||||
#define IR21_RED 0xFF6897
|
||||
#define IR21_REDDISH 0xFF30CF
|
||||
#define IR21_ORANGE 0xFF10EF
|
||||
#define IR21_YELLOWISH 0xFF42BD
|
||||
#define IR21_GREEN 0xFF9867
|
||||
#define IR21_GREENISH 0xFF18E7
|
||||
#define IR21_TURQUOISE 0xFF38C7
|
||||
#define IR21_CYAN 0xFF4AB5
|
||||
#define IR21_BLUE 0xFFB04F
|
||||
#define IR21_DEEPBLUE 0xFF7A85
|
||||
#define IR21_PURPLE 0xFF5AA5
|
||||
#define IR21_PINK 0xFF52AD
|
||||
#define IR21_WHITE 0xFF906F
|
||||
#define IR21_FLASH 0xFFE21D
|
||||
#define IR21_STROBE 0xFF22DD
|
||||
#define IR21_FADE 0xFF02FD
|
||||
#define IR21_SMOOTH 0xFFC23D
|
||||
|
||||
#define COLOR_RED 0xFF0000
|
||||
#define COLOR_REDDISH 0xFF7800
|
||||
@@ -93,3 +219,13 @@
|
||||
#define COLOR_MAGENTA 0xFF00DC
|
||||
#define COLOR_PINK 0xFF00A0
|
||||
#define COLOR_WHITE 0xFFFFDC
|
||||
#define COLOR_WARMWHITE2 0xFFAA69
|
||||
#define COLOR_WARMWHITE 0xFFBF8E
|
||||
#define COLOR_NEUTRALWHITE 0xFFD4B4
|
||||
#define COLOR_COLDWHITE 0xFFE9D9
|
||||
#define COLOR_COLDWHITE2 0xFFFFFF
|
||||
#define COLOR2_WARMWHITE2 0xFFFF9900
|
||||
#define COLOR2_WARMWHITE 0xFF825A00
|
||||
#define COLOR2_NEUTRALWHITE 0xFF000000
|
||||
#define COLOR2_COLDWHITE 0xFF7F7F7F
|
||||
#define COLOR2_COLDWHITE2 0xFFFFFFFF
|
||||
|
||||
469
wled00/json.cpp
Normal file
469
wled00/json.cpp
Normal file
@@ -0,0 +1,469 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* JSON API (De)serialization
|
||||
*/
|
||||
|
||||
void deserializeSegment(JsonObject elem, byte it)
|
||||
{
|
||||
byte id = elem["id"] | it;
|
||||
if (id < strip.getMaxSegments())
|
||||
{
|
||||
WS2812FX::Segment& seg = strip.getSegment(id);
|
||||
uint16_t start = elem["start"] | seg.start;
|
||||
int stop = elem["stop"] | -1;
|
||||
|
||||
if (stop < 0) {
|
||||
uint16_t len = elem["len"];
|
||||
stop = (len > 0) ? start + len : seg.stop;
|
||||
}
|
||||
uint16_t grp = elem["grp"] | seg.grouping;
|
||||
uint16_t spc = elem["spc"] | seg.spacing;
|
||||
strip.setSegment(id, start, stop, grp, spc);
|
||||
|
||||
int segbri = elem["bri"] | -1;
|
||||
if (segbri == 0) {
|
||||
seg.setOption(SEG_OPTION_ON, 0);
|
||||
} else if (segbri > 0) {
|
||||
seg.opacity = segbri;
|
||||
seg.setOption(SEG_OPTION_ON, 1);
|
||||
}
|
||||
|
||||
seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON));
|
||||
|
||||
JsonArray colarr = elem["col"];
|
||||
if (!colarr.isNull())
|
||||
{
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
{
|
||||
JsonArray colX = colarr[i];
|
||||
if (colX.isNull()) break;
|
||||
byte sz = colX.size();
|
||||
if (sz > 0 && sz < 5)
|
||||
{
|
||||
int rgbw[] = {0,0,0,0};
|
||||
byte cp = copyArray(colX, rgbw);
|
||||
|
||||
if (cp == 1 && rgbw[0] == 0) seg.colors[i] = 0;
|
||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||
{
|
||||
if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
|
||||
if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
|
||||
} else {
|
||||
seg.colors[i] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
|
||||
seg.setOption(SEG_OPTION_SELECTED, elem["sel"] | seg.getOption(SEG_OPTION_SELECTED));
|
||||
seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
|
||||
|
||||
//temporary, strip object gets updated via colorUpdated()
|
||||
if (id == strip.getMainSegmentId()) {
|
||||
effectCurrent = elem["fx"] | effectCurrent;
|
||||
effectSpeed = elem["sx"] | effectSpeed;
|
||||
effectIntensity = elem["ix"] | effectIntensity;
|
||||
effectPalette = elem["pal"] | effectPalette;
|
||||
} else { //permanent
|
||||
byte fx = elem["fx"] | seg.mode;
|
||||
if (fx != seg.mode && fx < strip.getModeCount()) strip.setMode(id, fx);
|
||||
seg.speed = elem["sx"] | seg.speed;
|
||||
seg.intensity = elem["ix"] | seg.intensity;
|
||||
seg.palette = elem["pal"] | seg.palette;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool deserializeState(JsonObject root)
|
||||
{
|
||||
strip.applyToAllSelected = false;
|
||||
bool stateResponse = root["v"] | false;
|
||||
|
||||
int ps = root["ps"] | -1;
|
||||
if (ps >= 0) applyPreset(ps);
|
||||
|
||||
bri = root["bri"] | bri;
|
||||
|
||||
bool on = root["on"] | (bri > 0);
|
||||
if (!on != !bri) toggleOnOff();
|
||||
|
||||
int tr = root["transition"] | -1;
|
||||
if (tr >= 0)
|
||||
{
|
||||
transitionDelay = tr;
|
||||
transitionDelay *= 100;
|
||||
}
|
||||
|
||||
tr = root["tt"] | -1;
|
||||
if (tr >= 0)
|
||||
{
|
||||
transitionDelayTemp = tr;
|
||||
transitionDelayTemp *= 100;
|
||||
jsonTransitionOnce = true;
|
||||
}
|
||||
|
||||
int cy = root["pl"] | -2;
|
||||
if (cy > -2) presetCyclingEnabled = (cy >= 0);
|
||||
JsonObject ccnf = root["ccnf"];
|
||||
presetCycleMin = ccnf["min"] | presetCycleMin;
|
||||
presetCycleMax = ccnf["max"] | presetCycleMax;
|
||||
tr = ccnf["time"] | -1;
|
||||
if (tr >= 2)
|
||||
{
|
||||
presetCycleTime = tr;
|
||||
presetCycleTime *= 100;
|
||||
}
|
||||
|
||||
JsonObject nl = root["nl"];
|
||||
nightlightActive = nl["on"] | nightlightActive;
|
||||
nightlightDelayMins = nl["dur"] | nightlightDelayMins;
|
||||
nightlightFade = nl["fade"] | nightlightFade;
|
||||
nightlightTargetBri = nl["tbri"] | nightlightTargetBri;
|
||||
|
||||
JsonObject udpn = root["udpn"];
|
||||
notifyDirect = udpn["send"] | notifyDirect;
|
||||
receiveNotifications = udpn["recv"] | receiveNotifications;
|
||||
bool noNotification = udpn["nn"]; //send no notification just for this request
|
||||
|
||||
int timein = root["time"] | -1;
|
||||
if (timein != -1) setTime(timein);
|
||||
doReboot = root["rb"] | doReboot;
|
||||
|
||||
realtimeOverride = root["lor"] | realtimeOverride;
|
||||
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
|
||||
|
||||
byte prevMain = strip.getMainSegmentId();
|
||||
strip.mainSegment = root["mainseg"] | prevMain;
|
||||
if (strip.getMainSegmentId() != prevMain) setValuesFromMainSeg();
|
||||
|
||||
int it = 0;
|
||||
JsonVariant segVar = root["seg"];
|
||||
if (segVar.is<JsonObject>())
|
||||
{
|
||||
int id = segVar["id"] | -1;
|
||||
|
||||
if (id < 0) { //set all selected segments
|
||||
bool didSet = false;
|
||||
byte lowestActive = 99;
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
||||
{
|
||||
WS2812FX::Segment sg = strip.getSegment(s);
|
||||
if (sg.isActive())
|
||||
{
|
||||
if (lowestActive == 99) lowestActive = s;
|
||||
if (sg.isSelected()) {
|
||||
deserializeSegment(segVar, s);
|
||||
didSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!didSet && lowestActive < strip.getMaxSegments()) deserializeSegment(segVar, lowestActive);
|
||||
} else { //set only the segment with the specified ID
|
||||
deserializeSegment(segVar, it);
|
||||
}
|
||||
} else {
|
||||
JsonArray segs = segVar.as<JsonArray>();
|
||||
for (JsonObject elem : segs)
|
||||
{
|
||||
deserializeSegment(elem, it);
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
colorUpdated(noNotification ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
|
||||
//write presets to flash directly?
|
||||
bool persistSaves = !(root["np"] | false);
|
||||
|
||||
ps = root["psave"] | -1;
|
||||
if (ps >= 0) savePreset(ps, persistSaves);
|
||||
|
||||
return stateResponse;
|
||||
}
|
||||
|
||||
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id)
|
||||
{
|
||||
root["id"] = id;
|
||||
root["start"] = seg.start;
|
||||
root["stop"] = seg.stop;
|
||||
root["len"] = seg.stop - seg.start;
|
||||
root["grp"] = seg.grouping;
|
||||
root["spc"] = seg.spacing;
|
||||
root["on"] = seg.getOption(SEG_OPTION_ON);
|
||||
byte segbri = seg.opacity;
|
||||
root["bri"] = (segbri) ? segbri : 255;
|
||||
|
||||
JsonArray colarr = root.createNestedArray("col");
|
||||
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
{
|
||||
JsonArray colX = colarr.createNestedArray();
|
||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||
{
|
||||
if (i == 0) {
|
||||
colX.add(col[0]); colX.add(col[1]); colX.add(col[2]); if (useRGBW) colX.add(col[3]);
|
||||
} else {
|
||||
colX.add(colSec[0]); colX.add(colSec[1]); colX.add(colSec[2]); if (useRGBW) colX.add(colSec[3]);
|
||||
}
|
||||
} else {
|
||||
colX.add((seg.colors[i] >> 16) & 0xFF);
|
||||
colX.add((seg.colors[i] >> 8) & 0xFF);
|
||||
colX.add((seg.colors[i]) & 0xFF);
|
||||
if (useRGBW)
|
||||
colX.add((seg.colors[i] >> 24) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
root["fx"] = seg.mode;
|
||||
root["sx"] = seg.speed;
|
||||
root["ix"] = seg.intensity;
|
||||
root["pal"] = seg.palette;
|
||||
root["sel"] = seg.isSelected();
|
||||
root["rev"] = seg.getOption(SEG_OPTION_REVERSED);
|
||||
}
|
||||
|
||||
|
||||
void serializeState(JsonObject root)
|
||||
{
|
||||
if (errorFlag) root["error"] = errorFlag;
|
||||
|
||||
root["on"] = (bri > 0);
|
||||
root["bri"] = briLast;
|
||||
root["transition"] = transitionDelay/100; //in 100ms
|
||||
|
||||
root["ps"] = currentPreset;
|
||||
root["pss"] = savedPresets;
|
||||
root["pl"] = (presetCyclingEnabled) ? 0: -1;
|
||||
|
||||
//temporary for preser cycle
|
||||
JsonObject ccnf = root.createNestedObject("ccnf");
|
||||
ccnf["min"] = presetCycleMin;
|
||||
ccnf["max"] = presetCycleMax;
|
||||
ccnf["time"] = presetCycleTime/100;
|
||||
|
||||
JsonObject nl = root.createNestedObject("nl");
|
||||
nl["on"] = nightlightActive;
|
||||
nl["dur"] = nightlightDelayMins;
|
||||
nl["fade"] = nightlightFade;
|
||||
nl["tbri"] = nightlightTargetBri;
|
||||
|
||||
JsonObject udpn = root.createNestedObject("udpn");
|
||||
udpn["send"] = notifyDirect;
|
||||
udpn["recv"] = receiveNotifications;
|
||||
|
||||
root["lor"] = realtimeOverride;
|
||||
|
||||
root["mainseg"] = strip.getMainSegmentId();
|
||||
|
||||
JsonArray seg = root.createNestedArray("seg");
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
||||
{
|
||||
WS2812FX::Segment sg = strip.getSegment(s);
|
||||
if (sg.isActive())
|
||||
{
|
||||
JsonObject seg0 = seg.createNestedObject();
|
||||
serializeSegment(seg0, sg, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//by https://github.com/tzapu/WiFiManager/blob/master/WiFiManager.cpp
|
||||
int getSignalQuality(int rssi)
|
||||
{
|
||||
int quality = 0;
|
||||
|
||||
if (rssi <= -100)
|
||||
{
|
||||
quality = 0;
|
||||
}
|
||||
else if (rssi >= -50)
|
||||
{
|
||||
quality = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
quality = 2 * (rssi + 100);
|
||||
}
|
||||
return quality;
|
||||
}
|
||||
|
||||
void serializeInfo(JsonObject root)
|
||||
{
|
||||
root["ver"] = versionString;
|
||||
root["vid"] = VERSION;
|
||||
//root["cn"] = WLED_CODENAME;
|
||||
|
||||
JsonObject leds = root.createNestedObject("leds");
|
||||
leds["count"] = ledCount;
|
||||
leds["rgbw"] = useRGBW;
|
||||
leds["wv"] = useRGBW && (strip.rgbwMode == RGBW_MODE_MANUAL_ONLY || strip.rgbwMode == RGBW_MODE_DUAL); //should a white channel slider be displayed?
|
||||
JsonArray leds_pin = leds.createNestedArray("pin");
|
||||
leds_pin.add(LEDPIN);
|
||||
|
||||
leds["pwr"] = strip.currentMilliamps;
|
||||
leds["maxpwr"] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
|
||||
leds["maxseg"] = strip.getMaxSegments();
|
||||
leds["seglock"] = false; //will be used in the future to prevent modifications to segment config
|
||||
|
||||
root["str"] = syncToggleReceive;
|
||||
|
||||
root["name"] = serverDescription;
|
||||
root["udpport"] = udpPort;
|
||||
root["live"] = (bool)realtimeMode;
|
||||
|
||||
switch (realtimeMode) {
|
||||
case REALTIME_MODE_INACTIVE: root["lm"] = ""; break;
|
||||
case REALTIME_MODE_GENERIC: root["lm"] = ""; break;
|
||||
case REALTIME_MODE_UDP: root["lm"] = "UDP"; break;
|
||||
case REALTIME_MODE_HYPERION: root["lm"] = "Hyperion"; break;
|
||||
case REALTIME_MODE_E131: root["lm"] = "E1.31"; break;
|
||||
case REALTIME_MODE_ADALIGHT: root["lm"] = F("USB Adalight");
|
||||
case REALTIME_MODE_ARTNET: root["lm"] = "Art-Net"; break;
|
||||
}
|
||||
|
||||
if (realtimeIP[0] == 0)
|
||||
{
|
||||
root["lip"] = "";
|
||||
} else {
|
||||
root["lip"] = realtimeIP.toString();
|
||||
}
|
||||
|
||||
root["fxcount"] = strip.getModeCount();
|
||||
root["palcount"] = strip.getPaletteCount();
|
||||
|
||||
JsonObject wifi_info = root.createNestedObject("wifi");
|
||||
wifi_info["bssid"] = WiFi.BSSIDstr();
|
||||
int qrssi = WiFi.RSSI();
|
||||
wifi_info["rssi"] = qrssi;
|
||||
wifi_info["signal"] = getSignalQuality(qrssi);
|
||||
wifi_info["channel"] = WiFi.channel();
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#ifdef WLED_DEBUG
|
||||
wifi_info["txPower"] = (int) WiFi.getTxPower();
|
||||
wifi_info["sleep"] = (bool) WiFi.getSleep();
|
||||
#endif
|
||||
root["arch"] = "esp32";
|
||||
root["core"] = ESP.getSdkVersion();
|
||||
//root["maxalloc"] = ESP.getMaxAllocHeap();
|
||||
#ifdef WLED_DEBUG
|
||||
root["resetReason0"] = (int)rtc_get_reset_reason(0);
|
||||
root["resetReason1"] = (int)rtc_get_reset_reason(1);
|
||||
#endif
|
||||
root["lwip"] = 0;
|
||||
#else
|
||||
root["arch"] = "esp8266";
|
||||
root["core"] = ESP.getCoreVersion();
|
||||
//root["maxalloc"] = ESP.getMaxFreeBlockSize();
|
||||
#ifdef WLED_DEBUG
|
||||
root["resetReason"] = (int)ESP.getResetInfoPtr()->reason;
|
||||
#endif
|
||||
root["lwip"] = LWIP_VERSION_MAJOR;
|
||||
#endif
|
||||
|
||||
root["freeheap"] = ESP.getFreeHeap();
|
||||
root["uptime"] = millis()/1000 + rolloverMillis*4294967;
|
||||
|
||||
byte os = 0;
|
||||
#ifdef WLED_DEBUG
|
||||
os = 0x80;
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
os += 0x40;
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_BLYNK
|
||||
os += 0x20;
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
os += 0x10;
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_FILESYSTEM
|
||||
os += 0x08;
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
os += 0x04;
|
||||
#endif
|
||||
#ifdef WLED_ENABLE_ADALIGHT
|
||||
os += 0x02;
|
||||
#endif
|
||||
#ifndef WLED_DISABLE_OTA
|
||||
os += 0x01;
|
||||
#endif
|
||||
root["opt"] = os;
|
||||
|
||||
root["brand"] = "WLED";
|
||||
root["product"] = "FOSS";
|
||||
root["mac"] = escapedMac;
|
||||
}
|
||||
|
||||
void serveJson(AsyncWebServerRequest* request)
|
||||
{
|
||||
byte subJson = 0;
|
||||
const String& url = request->url();
|
||||
if (url.indexOf("state") > 0) subJson = 1;
|
||||
else if (url.indexOf("info") > 0) subJson = 2;
|
||||
else if (url.indexOf("si") > 0) subJson = 3;
|
||||
else if (url.indexOf("live") > 0) {
|
||||
serveLiveLeds(request);
|
||||
return;
|
||||
}
|
||||
else if (url.indexOf("eff") > 0) {
|
||||
request->send_P(200, "application/json", JSON_mode_names);
|
||||
return;
|
||||
}
|
||||
else if (url.indexOf("pal") > 0) {
|
||||
request->send_P(200, "application/json", JSON_palette_names);
|
||||
return;
|
||||
}
|
||||
else if (url.length() > 6) { //not just /json
|
||||
request->send( 501, "application/json", F("{\"error\":\"Not implemented\"}"));
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
||||
JsonObject doc = response->getRoot();
|
||||
|
||||
switch (subJson)
|
||||
{
|
||||
case 1: //state
|
||||
serializeState(doc); break;
|
||||
case 2: //info
|
||||
serializeInfo(doc); break;
|
||||
default: //all
|
||||
JsonObject state = doc.createNestedObject("state");
|
||||
serializeState(state);
|
||||
JsonObject info = doc.createNestedObject("info");
|
||||
serializeInfo(info);
|
||||
if (subJson != 3)
|
||||
{
|
||||
doc["effects"] = serialized((const __FlashStringHelper*)JSON_mode_names);
|
||||
doc["palettes"] = serialized((const __FlashStringHelper*)JSON_palette_names);
|
||||
}
|
||||
}
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
#define MAX_LIVE_LEDS 180
|
||||
|
||||
void serveLiveLeds(AsyncWebServerRequest* request)
|
||||
{
|
||||
uint16_t used = ledCount;
|
||||
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
|
||||
char buffer[2000] = "{\"leds\":[";
|
||||
olen = 9;
|
||||
obuf = buffer;
|
||||
|
||||
for (uint16_t i= 0; i < used; i += n)
|
||||
{
|
||||
olen += sprintf(buffer + olen, "\"%06X\",", strip.getPixelColor(i));
|
||||
}
|
||||
olen -= 1;
|
||||
oappend("],\"n\":");
|
||||
oappendi(n);
|
||||
oappend("}");
|
||||
request->send(200, "application/json", buffer);
|
||||
}
|
||||
@@ -1,7 +1,27 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* LED methods
|
||||
*/
|
||||
|
||||
void setValuesFromMainSeg()
|
||||
{
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
colorFromUint32(seg.colors[0]);
|
||||
colorFromUint32(seg.colors[1], true);
|
||||
effectCurrent = seg.mode;
|
||||
effectSpeed = seg.speed;
|
||||
effectIntensity = seg.intensity;
|
||||
effectPalette = seg.palette;
|
||||
}
|
||||
|
||||
|
||||
void resetTimebase()
|
||||
{
|
||||
strip.timebase = 0 - millis();
|
||||
}
|
||||
|
||||
|
||||
void toggleOnOff()
|
||||
{
|
||||
if (bri == 0)
|
||||
@@ -16,43 +36,24 @@ void toggleOnOff()
|
||||
|
||||
|
||||
void setAllLeds() {
|
||||
if (!realtimeActive || !arlsForceMaxBri)
|
||||
if (!realtimeMode || !arlsForceMaxBri)
|
||||
{
|
||||
double d = briT*briMultiplier;
|
||||
int val = d/100;
|
||||
if (val > 255) val = 255;
|
||||
if (useGammaCorrectionBri)
|
||||
{
|
||||
strip.setBrightness(gamma8[val]);
|
||||
} else {
|
||||
strip.setBrightness(val);
|
||||
}
|
||||
strip.setBrightness(val);
|
||||
}
|
||||
if (!enableSecTransition)
|
||||
{
|
||||
for (byte i = 0; i<3; i++)
|
||||
{
|
||||
colSecT[i] = colSec[i];
|
||||
}
|
||||
colSecT[3] = colSec[3];
|
||||
}
|
||||
if (useRGBW && autoRGBtoRGBW)
|
||||
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY)
|
||||
{
|
||||
colorRGBtoRGBW(colT);
|
||||
colorRGBtoRGBW(colSecT);
|
||||
}
|
||||
if (useGammaCorrectionRGB)
|
||||
{
|
||||
strip.setColor(gamma8[colT[0]], gamma8[colT[1]], gamma8[colT[2]], gamma8[colT[3]]);
|
||||
strip.setSecondaryColor(gamma8[colSecT[0]], gamma8[colSecT[1]], gamma8[colSecT[2]], gamma8[colSecT[3]]);
|
||||
} else {
|
||||
strip.setColor(colT[0], colT[1], colT[2], colT[3]);
|
||||
strip.setSecondaryColor(colSecT[0], colSecT[1], colSecT[2], colSecT[3]);
|
||||
}
|
||||
strip.setColor(0, colT[0], colT[1], colT[2], colT[3]);
|
||||
strip.setColor(1, colSecT[0], colSecT[1], colSecT[2], colSecT[3]);
|
||||
}
|
||||
|
||||
|
||||
void setLedsStandard()
|
||||
void setLedsStandard(bool justColors)
|
||||
{
|
||||
for (byte i=0; i<4; i++)
|
||||
{
|
||||
@@ -61,6 +62,7 @@ void setLedsStandard()
|
||||
colSecOld[i] = colSec[i];
|
||||
colSecT[i] = colSec[i];
|
||||
}
|
||||
if (justColors) return;
|
||||
briOld = bri;
|
||||
briT = bri;
|
||||
setAllLeds();
|
||||
@@ -83,17 +85,36 @@ void colorUpdated(int callMode)
|
||||
{
|
||||
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
||||
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
|
||||
if (callMode != NOTIFIER_CALL_MODE_INIT &&
|
||||
callMode != NOTIFIER_CALL_MODE_DIRECT_CHANGE &&
|
||||
callMode != NOTIFIER_CALL_MODE_NO_NOTIFY) strip.applyToAllSelected = true; //if not from JSON api, which directly sets segments
|
||||
|
||||
bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette);
|
||||
if (!colorChanged())
|
||||
bool colChanged = colorChanged();
|
||||
|
||||
if (fxChanged || colChanged)
|
||||
{
|
||||
if (nightlightActive && !nightlightActiveOld && callMode != 3 && callMode != 5)
|
||||
if (realtimeTimeout == UINT32_MAX) realtimeTimeout = 0;
|
||||
if (isPreset) {isPreset = false;}
|
||||
else {currentPreset = -1;}
|
||||
|
||||
notify(callMode);
|
||||
|
||||
//set flag to update blynk and mqtt
|
||||
if (callMode != NOTIFIER_CALL_MODE_PRESET_CYCLE) interfaceUpdateCallMode = callMode;
|
||||
} else {
|
||||
if (nightlightActive && !nightlightActiveOld &&
|
||||
callMode != NOTIFIER_CALL_MODE_NOTIFICATION &&
|
||||
callMode != NOTIFIER_CALL_MODE_NO_NOTIFY)
|
||||
{
|
||||
notify(4); return;
|
||||
notify(NOTIFIER_CALL_MODE_NIGHTLIGHT);
|
||||
interfaceUpdateCallMode = NOTIFIER_CALL_MODE_NIGHTLIGHT;
|
||||
}
|
||||
else if (fxChanged) notify(6);
|
||||
return; //no change
|
||||
}
|
||||
if (callMode != 5 && nightlightActive && nightlightFade)
|
||||
|
||||
if (!colChanged) return; //following code is for e.g. initiating transitions
|
||||
|
||||
if (callMode != NOTIFIER_CALL_MODE_NO_NOTIFY && nightlightActive && nightlightFade)
|
||||
{
|
||||
briNlT = bri;
|
||||
nightlightDelayMs -= (millis() - nightlightStartTime);
|
||||
@@ -104,15 +125,20 @@ void colorUpdated(int callMode)
|
||||
colIT[i] = col[i];
|
||||
colSecIT[i] = colSec[i];
|
||||
}
|
||||
if (briT == 0)
|
||||
{
|
||||
setLedsStandard(true); //do not color transition if starting from off
|
||||
if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning
|
||||
}
|
||||
|
||||
briIT = bri;
|
||||
if (bri > 0) briLast = bri;
|
||||
|
||||
notify(callMode);
|
||||
|
||||
if (fadeTransition)
|
||||
{
|
||||
//set correct delay if not using notification delay
|
||||
if (callMode != 3) transitionDelayTemp = transitionDelay;
|
||||
if (callMode != NOTIFIER_CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay;
|
||||
jsonTransitionOnce = false;
|
||||
if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;}
|
||||
|
||||
if (transitionActive)
|
||||
@@ -133,25 +159,20 @@ void colorUpdated(int callMode)
|
||||
setLedsStandard();
|
||||
strip.trigger();
|
||||
}
|
||||
|
||||
if (callMode == 8) return;
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
if (espalexaDevice != nullptr) espalexaDevice->setValue(bri);
|
||||
#endif
|
||||
//only update Blynk and mqtt every 2 seconds to reduce lag
|
||||
if (millis() - lastInterfaceUpdate <= 2000)
|
||||
{
|
||||
interfaceUpdateCallMode = callMode;
|
||||
return;
|
||||
}
|
||||
updateInterfaces(callMode);
|
||||
}
|
||||
|
||||
|
||||
void updateInterfaces(uint8_t callMode)
|
||||
{
|
||||
if (callMode != 9 && callMode != 5) updateBlynk();
|
||||
publishMQTT();
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
if (espalexaDevice != nullptr && callMode != NOTIFIER_CALL_MODE_ALEXA) {
|
||||
espalexaDevice->setValue(bri);
|
||||
espalexaDevice->setColor(col[0], col[1], col[2]);
|
||||
}
|
||||
#endif
|
||||
if (callMode != NOTIFIER_CALL_MODE_BLYNK &&
|
||||
callMode != NOTIFIER_CALL_MODE_NO_NOTIFY) updateBlynk();
|
||||
doPublishMqtt = true;
|
||||
lastInterfaceUpdate = millis();
|
||||
}
|
||||
|
||||
@@ -164,6 +185,7 @@ void handleTransitions()
|
||||
updateInterfaces(interfaceUpdateCallMode);
|
||||
interfaceUpdateCallMode = 0; //disable
|
||||
}
|
||||
if (doPublishMqtt) publishMqtt();
|
||||
|
||||
if (transitionActive && transitionDelayTemp > 0)
|
||||
{
|
||||
@@ -200,12 +222,17 @@ void handleNightlight()
|
||||
nightlightDelayMs = (int)(nightlightDelayMins*60000);
|
||||
nightlightActiveOld = true;
|
||||
briNlT = bri;
|
||||
for (byte i=0; i<4; i++) colNlT[i] = col[i]; // remember starting color
|
||||
}
|
||||
float nper = (millis() - nightlightStartTime)/((float)nightlightDelayMs);
|
||||
if (nightlightFade)
|
||||
{
|
||||
bri = briNlT + ((nightlightTargetBri - briNlT)*nper);
|
||||
colorUpdated(5);
|
||||
if (nightlightColorFade) // color fading only is enabled with "NF=2"
|
||||
{
|
||||
for (byte i=0; i<4; i++) col[i] = colNlT[i]+ ((colSec[i] - colNlT[i])*nper); // fading from actual color to secondary color
|
||||
}
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY);
|
||||
}
|
||||
if (nper >= 1)
|
||||
{
|
||||
@@ -213,7 +240,7 @@ void handleNightlight()
|
||||
if (!nightlightFade)
|
||||
{
|
||||
bri = nightlightTargetBri;
|
||||
colorUpdated(5);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY);
|
||||
}
|
||||
updateBlynk();
|
||||
if (bri == 0) briLast = briNlT;
|
||||
@@ -226,10 +253,10 @@ void handleNightlight()
|
||||
//also handle preset cycle here
|
||||
if (presetCyclingEnabled && (millis() - presetCycledTime > presetCycleTime))
|
||||
{
|
||||
applyPreset(presetCycCurr,presetApplyBri,presetApplyCol,presetApplyFx);
|
||||
applyPreset(presetCycCurr,presetApplyBri);
|
||||
presetCycCurr++; if (presetCycCurr > presetCycleMax) presetCycCurr = presetCycleMin;
|
||||
if (presetCycCurr > 25) presetCycCurr = 1;
|
||||
colorUpdated(8);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_PRESET_CYCLE);
|
||||
presetCycledTime = millis();
|
||||
}
|
||||
}
|
||||
143
wled00/mqtt.cpp
Normal file
143
wled00/mqtt.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* MQTT communication protocol for home automation
|
||||
*/
|
||||
|
||||
#ifdef WLED_ENABLE_MQTT
|
||||
#define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds
|
||||
|
||||
void parseMQTTBriPayload(char* payload)
|
||||
{
|
||||
if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; colorUpdated(1);}
|
||||
else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); colorUpdated(1);}
|
||||
else {
|
||||
uint8_t in = strtoul(payload, NULL, 10);
|
||||
if (in == 0 && bri > 0) briLast = bri;
|
||||
bri = in;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void onMqttConnect(bool sessionPresent)
|
||||
{
|
||||
//(re)subscribe to required topics
|
||||
char subuf[38];
|
||||
|
||||
if (mqttDeviceTopic[0] != 0)
|
||||
{
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
mqtt->subscribe(subuf, 0);
|
||||
strcat(subuf, "/col");
|
||||
mqtt->subscribe(subuf, 0);
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, "/api");
|
||||
mqtt->subscribe(subuf, 0);
|
||||
}
|
||||
|
||||
if (mqttGroupTopic[0] != 0)
|
||||
{
|
||||
strcpy(subuf, mqttGroupTopic);
|
||||
mqtt->subscribe(subuf, 0);
|
||||
strcat(subuf, "/col");
|
||||
mqtt->subscribe(subuf, 0);
|
||||
strcpy(subuf, mqttGroupTopic);
|
||||
strcat(subuf, "/api");
|
||||
mqtt->subscribe(subuf, 0);
|
||||
}
|
||||
|
||||
doPublishMqtt = true;
|
||||
DEBUG_PRINTLN("MQTT ready");
|
||||
}
|
||||
|
||||
|
||||
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
||||
|
||||
DEBUG_PRINT("MQTT msg: ");
|
||||
DEBUG_PRINTLN(topic);
|
||||
DEBUG_PRINTLN(payload);
|
||||
|
||||
//no need to check the topic because we only get topics we are subscribed to
|
||||
|
||||
if (strstr(topic, "/col"))
|
||||
{
|
||||
colorFromDecOrHexString(col, (char*)payload);
|
||||
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
} else if (strstr(topic, "/api"))
|
||||
{
|
||||
String apireq = "win&";
|
||||
apireq += (char*)payload;
|
||||
handleSet(nullptr, apireq);
|
||||
} else parseMQTTBriPayload(payload);
|
||||
}
|
||||
|
||||
|
||||
void publishMqtt()
|
||||
{
|
||||
doPublishMqtt = false;
|
||||
if (mqtt == nullptr || !mqtt->connected()) return;
|
||||
DEBUG_PRINTLN("Publish MQTT");
|
||||
|
||||
char s[10];
|
||||
char subuf[38];
|
||||
|
||||
sprintf(s, "%ld", bri);
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, "/g");
|
||||
mqtt->publish(subuf, 0, true, s);
|
||||
|
||||
sprintf(s, "#%06X", (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2]));
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, "/c");
|
||||
mqtt->publish(subuf, 0, true, s);
|
||||
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, "/status");
|
||||
mqtt->publish(subuf, 0, true, "online");
|
||||
|
||||
char apires[1024];
|
||||
XML_response(nullptr, apires);
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, "/v");
|
||||
mqtt->publish(subuf, 0, true, apires);
|
||||
}
|
||||
|
||||
|
||||
//HA autodiscovery was removed in favor of the native integration in HA v0.102.0
|
||||
|
||||
bool initMqtt()
|
||||
{
|
||||
lastMqttReconnectAttempt = millis();
|
||||
if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false;
|
||||
|
||||
if (mqtt == nullptr) {
|
||||
mqtt = new AsyncMqttClient();
|
||||
mqtt->onMessage(onMqttMessage);
|
||||
mqtt->onConnect(onMqttConnect);
|
||||
}
|
||||
if (mqtt->connected()) return true;
|
||||
|
||||
DEBUG_PRINTLN("Reconnecting MQTT");
|
||||
IPAddress mqttIP;
|
||||
if (mqttIP.fromString(mqttServer)) //see if server is IP or domain
|
||||
{
|
||||
mqtt->setServer(mqttIP, mqttPort);
|
||||
} else {
|
||||
mqtt->setServer(mqttServer, mqttPort);
|
||||
}
|
||||
mqtt->setClientId(mqttClientID);
|
||||
if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass);
|
||||
|
||||
strcpy(mqttStatusTopic, mqttDeviceTopic);
|
||||
strcat(mqttStatusTopic, "/status");
|
||||
mqtt->setWill(mqttStatusTopic, 0, true, "offline");
|
||||
mqtt->setKeepAlive(MQTT_KEEP_ALIVE_TIME);
|
||||
mqtt->connect();
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
bool initMqtt(){return false;}
|
||||
void publishMqtt(){}
|
||||
#endif
|
||||
@@ -1,3 +1,6 @@
|
||||
#include "src/dependencies/timezone/Timezone.h"
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Acquires time from NTP server
|
||||
*/
|
||||
@@ -25,6 +28,8 @@ TimeChangeRule CDT = {Second, Sun, Mar, 2, -300 }; //Daylight time = UTC - 5
|
||||
TimeChangeRule CST = {First, Sun, Nov, 2, -360 }; //Standard time = UTC - 6 hours
|
||||
Timezone tzUSCentral(CDT, CST);
|
||||
|
||||
Timezone tzCASaskatchewan(CST, CST); //Central without DST
|
||||
|
||||
TimeChangeRule MDT = {Second, Sun, Mar, 2, -360 }; //Daylight time = UTC - 6 hours
|
||||
TimeChangeRule MST = {First, Sun, Nov, 2, -420 }; //Standard time = UTC - 7 hours
|
||||
Timezone tzUSMountain(MDT, MST);
|
||||
@@ -52,11 +57,20 @@ Timezone tzNZ(NZDT, NZST);
|
||||
TimeChangeRule NKST = {Last, Sun, Mar, 1, 510}; //Pyongyang Time = UTC + 8.5 hours
|
||||
Timezone tzNK(NKST, NKST);
|
||||
|
||||
Timezone* timezones[] = {&tzUTC, &tzUK, &tzEUCentral, &tzEUEastern, &tzUSEastern, &tzUSCentral, &tzUSMountain, &tzUSArizona, &tzUSPacific, &tzChina, &tzJapan, &tzAUEastern, &tzNZ, &tzNK};
|
||||
TimeChangeRule IST = {Last, Sun, Mar, 1, 330}; // India Standard Time = UTC + 5.5 hours
|
||||
Timezone tzIndia(IST, IST);
|
||||
|
||||
TimeChangeRule ACST = {First, Sun, Apr, 3, 570}; //Australian Central Standard = UTC + 9.5 hours
|
||||
TimeChangeRule ACDT = {First, Sun, Oct, 2, 630}; //Australian Central Daylight = UTC + 10.5 hours
|
||||
Timezone tzAUNorthern(ACST, ACST);
|
||||
Timezone tzAUSouthern(ACDT, ACST);
|
||||
|
||||
// Pick your timezone from here.
|
||||
Timezone* timezones[] = {&tzUTC, &tzUK, &tzEUCentral, &tzEUEastern, &tzUSEastern, &tzUSCentral, &tzUSMountain, &tzUSArizona, &tzUSPacific, &tzChina, &tzJapan, &tzAUEastern, &tzNZ, &tzNK, &tzIndia, &tzCASaskatchewan, &tzAUNorthern, &tzAUSouthern};
|
||||
|
||||
void handleNetworkTime()
|
||||
{
|
||||
if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > 50000000L && WiFi.status() == WL_CONNECTED)
|
||||
if (ntpEnabled && ntpConnected && millis() - ntpLastSyncTime > 50000000L && WLED_CONNECTED)
|
||||
{
|
||||
if (millis() - ntpPacketSentTime > 10000)
|
||||
{
|
||||
@@ -72,23 +86,31 @@ void handleNetworkTime()
|
||||
|
||||
void sendNTPPacket()
|
||||
{
|
||||
WiFi.hostByName(ntpServerName, ntpServerIP);
|
||||
DEBUG_PRINTLN("send NTP packet");
|
||||
if (!ntpServerIP.fromString(ntpServerName)) //see if server is IP or domain
|
||||
{
|
||||
#ifdef ESP8266
|
||||
WiFi.hostByName(ntpServerName, ntpServerIP, 750);
|
||||
#else
|
||||
WiFi.hostByName(ntpServerName, ntpServerIP);
|
||||
#endif
|
||||
}
|
||||
|
||||
memset(obuf, 0, NTP_PACKET_SIZE);
|
||||
DEBUG_PRINTLN("send NTP");
|
||||
byte pbuf[NTP_PACKET_SIZE];
|
||||
memset(pbuf, 0, NTP_PACKET_SIZE);
|
||||
|
||||
obuf[0] = 0b11100011; // LI, Version, Mode
|
||||
obuf[1] = 0; // Stratum, or type of clock
|
||||
obuf[2] = 6; // Polling Interval
|
||||
obuf[3] = 0xEC; // Peer Clock Precision
|
||||
pbuf[0] = 0b11100011; // LI, Version, Mode
|
||||
pbuf[1] = 0; // Stratum, or type of clock
|
||||
pbuf[2] = 6; // Polling Interval
|
||||
pbuf[3] = 0xEC; // Peer Clock Precision
|
||||
// 8 bytes of zero for Root Delay & Root Dispersion
|
||||
obuf[12] = 49;
|
||||
obuf[13] = 0x4E;
|
||||
obuf[14] = 49;
|
||||
obuf[15] = 52;
|
||||
pbuf[12] = 49;
|
||||
pbuf[13] = 0x4E;
|
||||
pbuf[14] = 49;
|
||||
pbuf[15] = 52;
|
||||
|
||||
ntpUdp.beginPacket(ntpServerIP, 123); //NTP requests are to port 123
|
||||
ntpUdp.write((byte*)obuf, NTP_PACKET_SIZE);
|
||||
ntpUdp.write(pbuf, NTP_PACKET_SIZE);
|
||||
ntpUdp.endPacket();
|
||||
}
|
||||
|
||||
@@ -96,13 +118,13 @@ bool checkNTPResponse()
|
||||
{
|
||||
int cb = ntpUdp.parsePacket();
|
||||
if (cb) {
|
||||
DEBUG_PRINT("packet received, l=");
|
||||
DEBUG_PRINT("NTP recv, l=");
|
||||
DEBUG_PRINTLN(cb);
|
||||
byte pbuf[NTP_PACKET_SIZE];
|
||||
ntpUdp.read(pbuf, NTP_PACKET_SIZE); // read the packet into the buffer
|
||||
|
||||
ntpUdp.read(obuf, NTP_PACKET_SIZE); // read the packet into the buffer
|
||||
|
||||
unsigned long highWord = word(obuf[40], obuf[41]);
|
||||
unsigned long lowWord = word(obuf[42], obuf[43]);
|
||||
unsigned long highWord = word(pbuf[40], pbuf[41]);
|
||||
unsigned long lowWord = word(pbuf[42], pbuf[43]);
|
||||
if (highWord == 0 && lowWord == 0) return false;
|
||||
|
||||
unsigned long secsSince1900 = highWord << 16 | lowWord;
|
||||
@@ -123,27 +145,22 @@ void updateLocalTime()
|
||||
local = timezones[currentTimezone]->toLocal(tmc);
|
||||
}
|
||||
|
||||
String getTimeString()
|
||||
void getTimeString(char* out)
|
||||
{
|
||||
updateLocalTime();
|
||||
String ret = monthStr(month(local));
|
||||
ret = ret + " ";
|
||||
ret = ret + day(local);
|
||||
ret = ret + " ";
|
||||
ret = ret + year(local);
|
||||
ret = ret + ", ";
|
||||
ret += (useAMPM)? hour(local)%12:hour(local);
|
||||
ret = ret + ":";
|
||||
if (minute(local) < 10) ret = ret + "0";
|
||||
ret = ret + minute(local);
|
||||
ret = ret + ":";
|
||||
if (second(local) < 10) ret = ret + "0";
|
||||
ret = ret + second(local);
|
||||
byte hr = hour(local);
|
||||
if (useAMPM)
|
||||
{
|
||||
ret += (hour(local) > 11)? " PM":" AM";
|
||||
if (hr > 11) hr -= 12;
|
||||
if (hr == 0) hr = 12;
|
||||
}
|
||||
sprintf(out,"%i-%i-%i, %i:%s%i:%s%i",year(local), month(local), day(local),
|
||||
hr,(minute(local)<10)?"0":"",minute(local),
|
||||
(second(local)<10)?"0":"",second(local));
|
||||
if (useAMPM)
|
||||
{
|
||||
strcat(out,(hour(local) > 11)? " PM":" AM");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void setCountdown()
|
||||
@@ -155,13 +172,16 @@ void setCountdown()
|
||||
//returns true if countdown just over
|
||||
bool checkCountdown()
|
||||
{
|
||||
long diff = countdownTime - now();
|
||||
local = abs(diff);
|
||||
if (diff <0 && !countdownOverTriggered)
|
||||
{
|
||||
if (macroCountdown != 0) applyMacro(macroCountdown);
|
||||
countdownOverTriggered = true;
|
||||
return true;
|
||||
unsigned long n = now();
|
||||
if (countdownMode) local = countdownTime - n + utcOffsetSecs;
|
||||
if (n > countdownTime) {
|
||||
if (countdownMode) local = n - countdownTime + utcOffsetSecs;
|
||||
if (!countdownOverTriggered)
|
||||
{
|
||||
if (macroCountdown != 0) applyMacro(macroCountdown);
|
||||
countdownOverTriggered = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1,6 +1,142 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Used to draw clock overlays over the strip
|
||||
*/
|
||||
|
||||
void initCronixie()
|
||||
{
|
||||
if (overlayCurrent == 3 && !cronixieInit)
|
||||
{
|
||||
setCronixie();
|
||||
strip.getSegment(0).grouping = 10; //10 LEDs per digit
|
||||
cronixieInit = true;
|
||||
} else if (cronixieInit && overlayCurrent != 3)
|
||||
{
|
||||
strip.getSegment(0).grouping = 1;
|
||||
cronixieInit = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handleOverlays()
|
||||
{
|
||||
if (millis() - overlayRefreshedTime > overlayRefreshMs)
|
||||
{
|
||||
initCronixie();
|
||||
updateLocalTime();
|
||||
checkTimers();
|
||||
checkCountdown();
|
||||
if (overlayCurrent == 3) _overlayCronixie();//Diamex cronixie clock kit
|
||||
overlayRefreshedTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _overlayAnalogClock()
|
||||
{
|
||||
int overlaySize = overlayMax - overlayMin +1;
|
||||
if (countdownMode)
|
||||
{
|
||||
_overlayAnalogCountdown(); return;
|
||||
}
|
||||
double hourP = ((double)(hour(local)%12))/12;
|
||||
double minuteP = ((double)minute(local))/60;
|
||||
hourP = hourP + minuteP/12;
|
||||
double secondP = ((double)second(local))/60;
|
||||
int hourPixel = floor(analogClock12pixel + overlaySize*hourP);
|
||||
if (hourPixel > overlayMax) hourPixel = overlayMin -1 + hourPixel - overlayMax;
|
||||
int minutePixel = floor(analogClock12pixel + overlaySize*minuteP);
|
||||
if (minutePixel > overlayMax) minutePixel = overlayMin -1 + minutePixel - overlayMax;
|
||||
int secondPixel = floor(analogClock12pixel + overlaySize*secondP);
|
||||
if (secondPixel > overlayMax) secondPixel = overlayMin -1 + secondPixel - overlayMax;
|
||||
if (analogClockSecondsTrail)
|
||||
{
|
||||
if (secondPixel < analogClock12pixel)
|
||||
{
|
||||
strip.setRange(analogClock12pixel, overlayMax, 0xFF0000);
|
||||
strip.setRange(overlayMin, secondPixel, 0xFF0000);
|
||||
} else
|
||||
{
|
||||
strip.setRange(analogClock12pixel, secondPixel, 0xFF0000);
|
||||
}
|
||||
}
|
||||
if (analogClock5MinuteMarks)
|
||||
{
|
||||
int pix;
|
||||
for (int i = 0; i <= 12; i++)
|
||||
{
|
||||
pix = analogClock12pixel + round((overlaySize / 12.0) *i);
|
||||
if (pix > overlayMax) pix -= overlaySize;
|
||||
strip.setPixelColor(pix, 0x00FFAA);
|
||||
}
|
||||
}
|
||||
if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, 0xFF0000);
|
||||
strip.setPixelColor(minutePixel, 0x00FF00);
|
||||
strip.setPixelColor(hourPixel, 0x0000FF);
|
||||
overlayRefreshMs = 998;
|
||||
}
|
||||
|
||||
|
||||
void _overlayAnalogCountdown()
|
||||
{
|
||||
if (now() < countdownTime)
|
||||
{
|
||||
long diff = countdownTime - now();
|
||||
double pval = 60;
|
||||
if (diff > 31557600L) //display in years if more than 365 days
|
||||
{
|
||||
pval = 315576000L; //10 years
|
||||
} else if (diff > 2592000L) //display in months if more than a month
|
||||
{
|
||||
pval = 31557600L; //1 year
|
||||
} else if (diff > 604800) //display in weeks if more than a week
|
||||
{
|
||||
pval = 2592000L; //1 month
|
||||
} else if (diff > 86400) //display in days if more than 24 hours
|
||||
{
|
||||
pval = 604800; //1 week
|
||||
} else if (diff > 3600) //display in hours if more than 60 minutes
|
||||
{
|
||||
pval = 86400; //1 day
|
||||
} else if (diff > 60) //display in minutes if more than 60 seconds
|
||||
{
|
||||
pval = 3600; //1 hour
|
||||
}
|
||||
int overlaySize = overlayMax - overlayMin +1;
|
||||
double perc = (pval-(double)diff)/pval;
|
||||
if (perc > 1.0) perc = 1.0;
|
||||
byte pixelCnt = perc*overlaySize;
|
||||
if (analogClock12pixel + pixelCnt > overlayMax)
|
||||
{
|
||||
strip.setRange(analogClock12pixel, overlayMax, ((uint32_t)colSec[3] << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]);
|
||||
strip.setRange(overlayMin, overlayMin +pixelCnt -(1+ overlayMax -analogClock12pixel), ((uint32_t)colSec[3] << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]);
|
||||
} else
|
||||
{
|
||||
strip.setRange(analogClock12pixel, analogClock12pixel + pixelCnt, ((uint32_t)colSec[3] << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]);
|
||||
}
|
||||
}
|
||||
overlayRefreshMs = 998;
|
||||
}
|
||||
|
||||
|
||||
void handleOverlayDraw() {
|
||||
if (!overlayCurrent) return;
|
||||
switch (overlayCurrent)
|
||||
{
|
||||
case 1: _overlayAnalogClock(); break;
|
||||
case 3: _drawOverlayCronixie(); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Support for the Cronixie clock
|
||||
*/
|
||||
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
byte _digitOut[6] = {10,10,10,10,10,10};
|
||||
|
||||
byte getSameCodeLength(char code, int index, char const cronixieDisplay[])
|
||||
{
|
||||
byte counter = 0;
|
||||
@@ -19,7 +155,6 @@ byte getSameCodeLength(char code, int index, char const cronixieDisplay[])
|
||||
|
||||
void setCronixie()
|
||||
{
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
/*
|
||||
* digit purpose index
|
||||
* 0-9 | 0-9 (incl. random)
|
||||
@@ -97,8 +232,8 @@ void setCronixie()
|
||||
case '-': dP[i] = 11; break;
|
||||
case 'r': dP[i] = random(1,7); break; //random btw. 1-6
|
||||
case 'R': dP[i] = random(0,10); break; //random btw. 0-9
|
||||
case 't': break; //Test upw.
|
||||
case 'T': break; //Test dnw.
|
||||
//case 't': break; //Test upw.
|
||||
//case 'T': break; //Test dnw.
|
||||
case 'b': dP[i] = 14 + getSameCodeLength('b',i,cronixieDisplay); i = i+dP[i]-14; break;
|
||||
case 'B': dP[i] = 14 + getSameCodeLength('B',i,cronixieDisplay); i = i+dP[i]-14; break;
|
||||
case 'h': dP[i] = 70 + getSameCodeLength('h',i,cronixieDisplay); i = i+dP[i]-70; break;
|
||||
@@ -113,8 +248,8 @@ void setCronixie()
|
||||
case 'y': dP[i] = 86 + getSameCodeLength('y',i,cronixieDisplay); i = i+dP[i]-86; break;
|
||||
case 'I': dP[i] = 39 + getSameCodeLength('I',i,cronixieDisplay); i = i+dP[i]-39; break; //Month. Don't ask me why month and minute both start with M.
|
||||
case 'i': dP[i] = 89 + getSameCodeLength('i',i,cronixieDisplay); i = i+dP[i]-89; break;
|
||||
case 'W': break;
|
||||
case 'w': break;
|
||||
//case 'W': break;
|
||||
//case 'w': break;
|
||||
case 'D': dP[i] = 43 + getSameCodeLength('D',i,cronixieDisplay); i = i+dP[i]-43; break;
|
||||
case 'd': dP[i] = 93 + getSameCodeLength('d',i,cronixieDisplay); i = i+dP[i]-93; break;
|
||||
case '0': dP[i] = 0; break;
|
||||
@@ -127,8 +262,8 @@ void setCronixie()
|
||||
case '7': dP[i] = 7; break;
|
||||
case '8': dP[i] = 8; break;
|
||||
case '9': dP[i] = 9; break;
|
||||
case 'V': break; //user var0
|
||||
case 'v': break; //user var1
|
||||
//case 'V': break; //user var0
|
||||
//case 'v': break; //user var1
|
||||
}
|
||||
}
|
||||
DEBUG_PRINT("result ");
|
||||
@@ -140,14 +275,10 @@ void setCronixie()
|
||||
DEBUG_PRINTLN((int)dP[5]);
|
||||
|
||||
_overlayCronixie(); //refresh
|
||||
#endif
|
||||
}
|
||||
|
||||
void _overlayCronixie()
|
||||
{
|
||||
if (countdownMode) checkCountdown();
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
|
||||
byte h = hour(local);
|
||||
byte h0 = h;
|
||||
byte m = minute(local);
|
||||
@@ -163,7 +294,6 @@ void _overlayCronixie()
|
||||
if (h>12) h-=12;
|
||||
else if (h==0) h+=12;
|
||||
}
|
||||
byte _digitOut[]{10,10,10,10,10,10};
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (dP[i] < 12) _digitOut[i] = dP[i];
|
||||
@@ -186,8 +316,8 @@ void _overlayCronixie()
|
||||
case 37: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //YY
|
||||
case 39: _digitOut[i] = 2; _digitOut[i+1] = 0; _digitOut[i+2] = y/10; _digitOut[i+3] = y- _digitOut[i+2]*10; i+=3; break; //YYYY
|
||||
|
||||
case 16: _digitOut[i+2] = ((h0/3)&1)?1:0; i++; //BBB (BBBB NI)
|
||||
case 15: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:0; i++; //BB
|
||||
//case 16: _digitOut[i+2] = ((h0/3)&1)?1:0; i++; //BBB (BBBB NI)
|
||||
//case 15: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:0; i++; //BB
|
||||
case 14: _digitOut[i] = (h0>11)?1:0; break; //B
|
||||
}
|
||||
} else
|
||||
@@ -197,8 +327,8 @@ void _overlayCronixie()
|
||||
case 71: _digitOut[i] = h/10; _digitOut[i+1] = h- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //hh
|
||||
case 75: _digitOut[i] = m/10; _digitOut[i+1] = m- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //mm
|
||||
case 81: _digitOut[i] = s/10; _digitOut[i+1] = s- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //ss
|
||||
case 66: _digitOut[i+2] = ((h0/3)&1)?1:10; i++; //bbb (bbbb NI)
|
||||
case 65: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:10; i++; //bb
|
||||
//case 66: _digitOut[i+2] = ((h0/3)&1)?1:10; i++; //bbb (bbbb NI)
|
||||
//case 65: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:10; i++; //bb
|
||||
case 64: _digitOut[i] = (h0>11)?1:10; break; //b
|
||||
|
||||
case 93: _digitOut[i] = weekday(local); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //d
|
||||
@@ -210,7 +340,37 @@ void _overlayCronixie()
|
||||
}
|
||||
}
|
||||
}
|
||||
strip.setCronixieDigits(_digitOut);
|
||||
//strip.trigger(); //this has a drawback, no effects slower than RefreshMs. advantage: Quick update, not dependant on effect time
|
||||
#endif
|
||||
}
|
||||
|
||||
void _drawOverlayCronixie()
|
||||
{
|
||||
byte offsets[] = {5, 0, 6, 1, 7, 2, 8, 3, 9, 4};
|
||||
|
||||
for (uint16_t i = 0; i < 6; i++)
|
||||
{
|
||||
byte o = 10*i;
|
||||
byte excl = 10;
|
||||
if(_digitOut[i] < 10) excl = offsets[_digitOut[i]];
|
||||
excl += o;
|
||||
|
||||
if (cronixieBacklight && _digitOut[i] <11)
|
||||
{
|
||||
uint32_t col = strip.gamma32(strip.getSegment(0).colors[1]);
|
||||
for (uint16_t j=o; j< o+10; j++) {
|
||||
if (j != excl) strip.setPixelColor(j, col);
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (uint16_t j=o; j< o+10; j++) {
|
||||
if (j != excl) strip.setPixelColor(j, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else // WLED_DISABLE_CRONIXIE
|
||||
byte getSameCodeLength(char code, int index, char const cronixieDisplay[]) {}
|
||||
void setCronixie() {}
|
||||
void _overlayCronixie() {}
|
||||
void _drawOverlayCronixie() {}
|
||||
#endif
|
||||
@@ -13,7 +13,9 @@
|
||||
#ifndef PalettesWLED_h
|
||||
#define PalettesWLED_h
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( ib_jul01_gp ) {
|
||||
#define GRADIENT_PALETTE_COUNT 39
|
||||
|
||||
const byte ib_jul01_gp[] PROGMEM = {
|
||||
0, 194, 1, 1,
|
||||
94, 1, 29, 18,
|
||||
132, 57,131, 28,
|
||||
@@ -24,7 +26,7 @@ DEFINE_GRADIENT_PALETTE( ib_jul01_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_vintage_57_gp ) {
|
||||
const byte es_vintage_57_gp[] PROGMEM = {
|
||||
0, 2, 1, 1,
|
||||
53, 18, 1, 0,
|
||||
104, 69, 29, 1,
|
||||
@@ -37,7 +39,7 @@ DEFINE_GRADIENT_PALETTE( es_vintage_57_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 32 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_vintage_01_gp ) {
|
||||
const byte es_vintage_01_gp[] PROGMEM = {
|
||||
0, 4, 1, 1,
|
||||
51, 16, 0, 1,
|
||||
76, 97,104, 3,
|
||||
@@ -53,7 +55,7 @@ DEFINE_GRADIENT_PALETTE( es_vintage_01_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_rivendell_15_gp ) {
|
||||
const byte es_rivendell_15_gp[] PROGMEM = {
|
||||
0, 1, 14, 5,
|
||||
101, 16, 36, 14,
|
||||
165, 56, 68, 30,
|
||||
@@ -67,7 +69,7 @@ DEFINE_GRADIENT_PALETTE( es_rivendell_15_gp ) {
|
||||
// Size: 36 bytes of program space.
|
||||
// Edited to be brighter
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( rgi_15_gp ) {
|
||||
const byte rgi_15_gp[] PROGMEM = {
|
||||
0, 4, 1, 70,
|
||||
31, 55, 1, 30,
|
||||
63, 255, 4, 7,
|
||||
@@ -84,7 +86,7 @@ DEFINE_GRADIENT_PALETTE( rgi_15_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 8 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( retro2_16_gp ) {
|
||||
const byte retro2_16_gp[] PROGMEM = {
|
||||
0, 188,135, 1,
|
||||
255, 46, 7, 1};
|
||||
|
||||
@@ -94,7 +96,7 @@ DEFINE_GRADIENT_PALETTE( retro2_16_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Analogous_1_gp ) {
|
||||
const byte Analogous_1_gp[] PROGMEM = {
|
||||
0, 3, 0,255,
|
||||
63, 23, 0,255,
|
||||
127, 67, 0,255,
|
||||
@@ -107,7 +109,7 @@ DEFINE_GRADIENT_PALETTE( Analogous_1_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_pinksplash_08_gp ) {
|
||||
const byte es_pinksplash_08_gp[] PROGMEM = {
|
||||
0, 126, 11,255,
|
||||
127, 197, 1, 22,
|
||||
175, 210,157,172,
|
||||
@@ -120,7 +122,7 @@ DEFINE_GRADIENT_PALETTE( es_pinksplash_08_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 16 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_ocean_breeze_036_gp ) {
|
||||
const byte es_ocean_breeze_036_gp[] PROGMEM = {
|
||||
0, 1, 6, 7,
|
||||
89, 1, 99,111,
|
||||
153, 144,209,255,
|
||||
@@ -132,7 +134,7 @@ DEFINE_GRADIENT_PALETTE( es_ocean_breeze_036_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 88 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( departure_gp ) {
|
||||
const byte departure_gp[] PROGMEM = {
|
||||
0, 8, 3, 0,
|
||||
42, 23, 7, 0,
|
||||
63, 75, 38, 6,
|
||||
@@ -152,7 +154,7 @@ DEFINE_GRADIENT_PALETTE( departure_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 36 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_landscape_64_gp ) {
|
||||
const byte es_landscape_64_gp[] PROGMEM = {
|
||||
0, 0, 0, 0,
|
||||
37, 2, 25, 1,
|
||||
76, 15,115, 5,
|
||||
@@ -169,7 +171,7 @@ DEFINE_GRADIENT_PALETTE( es_landscape_64_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 24 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_landscape_33_gp ) {
|
||||
const byte es_landscape_33_gp[] PROGMEM = {
|
||||
0, 1, 5, 0,
|
||||
19, 32, 23, 1,
|
||||
38, 161, 55, 1,
|
||||
@@ -183,7 +185,7 @@ DEFINE_GRADIENT_PALETTE( es_landscape_33_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( rainbowsherbet_gp ) {
|
||||
const byte rainbowsherbet_gp[] PROGMEM = {
|
||||
0, 255, 33, 4,
|
||||
43, 255, 68, 25,
|
||||
86, 255, 7, 25,
|
||||
@@ -198,7 +200,7 @@ DEFINE_GRADIENT_PALETTE( rainbowsherbet_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 24 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( gr65_hult_gp ) {
|
||||
const byte gr65_hult_gp[] PROGMEM = {
|
||||
0, 247,176,247,
|
||||
48, 255,136,255,
|
||||
89, 220, 29,226,
|
||||
@@ -212,7 +214,7 @@ DEFINE_GRADIENT_PALETTE( gr65_hult_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 32 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( gr64_hult_gp ) {
|
||||
const byte gr64_hult_gp[] PROGMEM = {
|
||||
0, 1,124,109,
|
||||
66, 1, 93, 79,
|
||||
104, 52, 65, 1,
|
||||
@@ -228,7 +230,7 @@ DEFINE_GRADIENT_PALETTE( gr64_hult_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( GMT_drywet_gp ) {
|
||||
const byte GMT_drywet_gp[] PROGMEM = {
|
||||
0, 47, 30, 2,
|
||||
42, 213,147, 24,
|
||||
84, 103,219, 52,
|
||||
@@ -243,7 +245,7 @@ DEFINE_GRADIENT_PALETTE( GMT_drywet_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 24 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( ib15_gp ) {
|
||||
const byte ib15_gp[] PROGMEM = {
|
||||
0, 113, 91,147,
|
||||
72, 157, 88, 78,
|
||||
89, 208, 85, 33,
|
||||
@@ -257,7 +259,7 @@ DEFINE_GRADIENT_PALETTE( ib15_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Tertiary_01_gp ) {
|
||||
const byte Tertiary_01_gp[] PROGMEM = {
|
||||
0, 0, 1,255,
|
||||
63, 3, 68, 45,
|
||||
127, 23,255, 0,
|
||||
@@ -270,7 +272,7 @@ DEFINE_GRADIENT_PALETTE( Tertiary_01_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 52 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( lava_gp ) {
|
||||
const byte lava_gp[] PROGMEM = {
|
||||
0, 0, 0, 0,
|
||||
46, 18, 0, 0,
|
||||
96, 113, 0, 0,
|
||||
@@ -291,7 +293,7 @@ DEFINE_GRADIENT_PALETTE( lava_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( fierce_ice_gp ) {
|
||||
const byte fierce_ice_gp[] PROGMEM = {
|
||||
0, 0, 0, 0,
|
||||
59, 0, 9, 45,
|
||||
119, 0, 38,255,
|
||||
@@ -306,7 +308,7 @@ DEFINE_GRADIENT_PALETTE( fierce_ice_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 44 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Colorfull_gp ) {
|
||||
const byte Colorfull_gp[] PROGMEM = {
|
||||
0, 10, 85, 5,
|
||||
25, 29,109, 18,
|
||||
60, 59,138, 42,
|
||||
@@ -325,7 +327,7 @@ DEFINE_GRADIENT_PALETTE( Colorfull_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 44 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Pink_Purple_gp ) {
|
||||
const byte Pink_Purple_gp[] PROGMEM = {
|
||||
0, 19, 2, 39,
|
||||
25, 26, 4, 45,
|
||||
51, 33, 6, 52,
|
||||
@@ -344,7 +346,7 @@ DEFINE_GRADIENT_PALETTE( Pink_Purple_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Sunset_Real_gp ) {
|
||||
const byte Sunset_Real_gp[] PROGMEM = {
|
||||
0, 120, 0, 0,
|
||||
22, 179, 22, 0,
|
||||
51, 255,104, 0,
|
||||
@@ -359,7 +361,7 @@ DEFINE_GRADIENT_PALETTE( Sunset_Real_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 44 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Sunset_Yellow_gp ) {
|
||||
const byte Sunset_Yellow_gp[] PROGMEM = {
|
||||
0, 10, 62,123,
|
||||
36, 56,130,103,
|
||||
87, 153,225, 85,
|
||||
@@ -378,7 +380,7 @@ DEFINE_GRADIENT_PALETTE( Sunset_Yellow_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 60 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Beech_gp ) {
|
||||
const byte Beech_gp[] PROGMEM = {
|
||||
0, 255,252,214,
|
||||
12, 255,252,214,
|
||||
22, 255,252,214,
|
||||
@@ -401,7 +403,7 @@ DEFINE_GRADIENT_PALETTE( Beech_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 32 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Another_Sunset_gp ) {
|
||||
const byte Another_Sunset_gp[] PROGMEM = {
|
||||
0, 110, 49, 11,
|
||||
29, 55, 34, 10,
|
||||
68, 22, 22, 9,
|
||||
@@ -420,7 +422,7 @@ DEFINE_GRADIENT_PALETTE( Another_Sunset_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 52 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_autumn_19_gp ) {
|
||||
const byte es_autumn_19_gp[] PROGMEM = {
|
||||
0, 26, 1, 1,
|
||||
51, 67, 4, 1,
|
||||
84, 118, 14, 1,
|
||||
@@ -441,7 +443,7 @@ DEFINE_GRADIENT_PALETTE( es_autumn_19_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( BlacK_Blue_Magenta_White_gp ) {
|
||||
const byte BlacK_Blue_Magenta_White_gp[] PROGMEM = {
|
||||
0, 0, 0, 0,
|
||||
42, 0, 0, 45,
|
||||
84, 0, 0,255,
|
||||
@@ -456,7 +458,7 @@ DEFINE_GRADIENT_PALETTE( BlacK_Blue_Magenta_White_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( BlacK_Magenta_Red_gp ) {
|
||||
const byte BlacK_Magenta_Red_gp[] PROGMEM = {
|
||||
0, 0, 0, 0,
|
||||
63, 42, 0, 45,
|
||||
127, 255, 0,255,
|
||||
@@ -469,7 +471,7 @@ DEFINE_GRADIENT_PALETTE( BlacK_Magenta_Red_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( BlacK_Red_Magenta_Yellow_gp ) {
|
||||
const byte BlacK_Red_Magenta_Yellow_gp[] PROGMEM = {
|
||||
0, 0, 0, 0,
|
||||
42, 42, 0, 0,
|
||||
84, 255, 0, 0,
|
||||
@@ -484,7 +486,7 @@ DEFINE_GRADIENT_PALETTE( BlacK_Red_Magenta_Yellow_gp ) {
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Blue_Cyan_Yellow_gp ) {
|
||||
const byte Blue_Cyan_Yellow_gp[] PROGMEM = {
|
||||
0, 0, 0,255,
|
||||
63, 0, 55,255,
|
||||
127, 0,255,255,
|
||||
@@ -494,7 +496,7 @@ DEFINE_GRADIENT_PALETTE( Blue_Cyan_Yellow_gp ) {
|
||||
|
||||
//Custom palette by Aircoookie
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Orange_Teal_gp ) {
|
||||
const byte Orange_Teal_gp[] PROGMEM = {
|
||||
0, 0,150, 92,
|
||||
55, 0,150, 92,
|
||||
200, 255, 72, 0,
|
||||
@@ -502,7 +504,7 @@ DEFINE_GRADIENT_PALETTE( Orange_Teal_gp ) {
|
||||
|
||||
//Custom palette by Aircoookie
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Tiamat_gp ) {
|
||||
const byte Tiamat_gp[] PROGMEM = {
|
||||
0, 1, 2, 14, //gc
|
||||
33, 2, 5, 35, //gc from 47, 61,126
|
||||
100, 13,135, 92, //gc from 88,242,247
|
||||
@@ -517,7 +519,7 @@ DEFINE_GRADIENT_PALETTE( Tiamat_gp ) {
|
||||
|
||||
//Custom palette by Aircoookie
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( April_Night_gp ) {
|
||||
const byte April_Night_gp[] PROGMEM = {
|
||||
0, 1, 5, 45, //deep blue
|
||||
10, 1, 5, 45,
|
||||
25, 5,169,175, //light blue
|
||||
@@ -529,25 +531,64 @@ DEFINE_GRADIENT_PALETTE( April_Night_gp ) {
|
||||
127, 249,150, 5, //yellow
|
||||
143, 1, 5, 45,
|
||||
162, 1, 5, 45,
|
||||
178, 255,92, 0, //pastel orange
|
||||
178, 255, 92, 0, //pastel orange
|
||||
193, 1, 5, 45,
|
||||
214, 1, 5, 45,
|
||||
229, 223, 45, 72, //pink
|
||||
244, 1, 5, 45,
|
||||
255, 1, 5, 45};
|
||||
|
||||
const byte Orangery_gp[] PROGMEM = {
|
||||
0, 255, 95, 23,
|
||||
30, 255, 82, 0,
|
||||
60, 223, 13, 8,
|
||||
90, 144, 44, 2,
|
||||
120, 255,110, 17,
|
||||
150, 255, 69, 0,
|
||||
180, 158, 13, 11,
|
||||
210, 241, 82, 17,
|
||||
255, 213, 37, 4};
|
||||
|
||||
//inspired by Mark Kriegsman https://gist.github.com/kriegsman/756ea6dcae8e30845b5a
|
||||
const byte C9_gp[] PROGMEM = {
|
||||
0, 184, 4, 0, //red
|
||||
60, 184, 4, 0,
|
||||
65, 144, 44, 2, //amber
|
||||
125, 144, 44, 2,
|
||||
130, 4, 96, 2, //green
|
||||
190, 4, 96, 2,
|
||||
195, 7, 7, 88, //blue
|
||||
255, 7, 7, 88};
|
||||
|
||||
const byte Sakura_gp[] PROGMEM = {
|
||||
0, 196, 19, 10,
|
||||
65, 255, 69, 45,
|
||||
130, 223, 45, 72,
|
||||
195, 255, 82,103,
|
||||
255, 223, 13, 17};
|
||||
|
||||
const byte Aurora_gp[] PROGMEM = {
|
||||
0, 1, 5, 45, //deep blue
|
||||
64, 0,200, 23,
|
||||
128, 0,255, 0, //green
|
||||
170, 0,243, 45,
|
||||
200, 0,135, 7,
|
||||
255, 1, 5, 45};//deep blue
|
||||
|
||||
const byte Atlantica_gp[] PROGMEM = {
|
||||
0, 0, 28,112, //#001C70
|
||||
50, 32, 96,255, //#2060FF
|
||||
100, 0,243, 45,
|
||||
150, 12, 95, 82, //#0C5F52
|
||||
200, 25,190, 95, //#19BE5F
|
||||
255, 40,170, 80};//#28AA50
|
||||
|
||||
|
||||
// Single array of defined cpt-city color palettes.
|
||||
// This will let us programmatically choose one based on
|
||||
// a number, rather than having to activate each explicitly
|
||||
// by name every time.
|
||||
// Since it is const, this array could also be moved
|
||||
// into PROGMEM to save SRAM, but for simplicity of illustration
|
||||
// we'll keep it in a regular SRAM array.
|
||||
//
|
||||
// This list of color palettes acts as a "playlist"; you can
|
||||
// add or delete, or re-arrange as you wish.
|
||||
const TProgmemRGBGradientPalettePtr gGradientPalettes[] = {
|
||||
const byte* const gGradientPalettes[] PROGMEM = {
|
||||
Sunset_Real_gp, //13-00 Sunset
|
||||
es_rivendell_15_gp, //14-01 Rivendell
|
||||
es_ocean_breeze_036_gp, //15-02 Breeze
|
||||
@@ -581,12 +622,12 @@ const TProgmemRGBGradientPalettePtr gGradientPalettes[] = {
|
||||
Blue_Cyan_Yellow_gp, //43-30 Yelblu
|
||||
Orange_Teal_gp, //44-31 Orange & Teal
|
||||
Tiamat_gp, //45-32 Tiamat
|
||||
April_Night_gp //46-33 April Night
|
||||
April_Night_gp, //46-33 April Night
|
||||
Orangery_gp, //47-34 Orangery
|
||||
C9_gp, //48-35 C9
|
||||
Sakura_gp, //49-36 Sakura
|
||||
Aurora_gp, //50-37 Aurora
|
||||
Atlantica_gp, //51-38 Atlantica
|
||||
};
|
||||
|
||||
|
||||
// Count of how many cpt-city gradients are defined:
|
||||
const uint8_t gGradientPaletteCount =
|
||||
sizeof( gGradientPalettes) / sizeof( TProgmemRGBGradientPalettePtr );
|
||||
|
||||
#endif
|
||||
|
||||
704
wled00/set.cpp
Normal file
704
wled00/set.cpp
Normal file
@@ -0,0 +1,704 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Receives client input
|
||||
*/
|
||||
|
||||
void _setRandomColor(bool _sec,bool fromButton)
|
||||
{
|
||||
lastRandomIndex = strip.get_random_wheel_index(lastRandomIndex);
|
||||
if (_sec){
|
||||
colorHStoRGB(lastRandomIndex*256,255,colSec);
|
||||
} else {
|
||||
colorHStoRGB(lastRandomIndex*256,255,col);
|
||||
}
|
||||
if (fromButton) colorUpdated(2);
|
||||
}
|
||||
|
||||
|
||||
bool isAsterisksOnly(const char* str, byte maxLen)
|
||||
{
|
||||
for (byte i = 0; i < maxLen; i++) {
|
||||
if (str[i] == 0) break;
|
||||
if (str[i] != '*') return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//called upon POST settings form submit
|
||||
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
{
|
||||
|
||||
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec 7: DMX
|
||||
if (subPage <1 || subPage >7) return;
|
||||
|
||||
//WIFI SETTINGS
|
||||
if (subPage == 1)
|
||||
{
|
||||
strlcpy(clientSSID,request->arg("CS").c_str(), 33);
|
||||
|
||||
if (!isAsterisksOnly(request->arg("CP").c_str(), 65)) strlcpy(clientPass, request->arg("CP").c_str(), 65);
|
||||
|
||||
strlcpy(cmDNS, request->arg("CM").c_str(), 33);
|
||||
|
||||
apBehavior = request->arg("AB").toInt();
|
||||
strlcpy(apSSID, request->arg("AS").c_str(), 33);
|
||||
apHide = request->hasArg("AH");
|
||||
int passlen = request->arg("AP").length();
|
||||
if (passlen == 0 || (passlen > 7 && !isAsterisksOnly(request->arg("AP").c_str(), 65))) strlcpy(apPass, request->arg("AP").c_str(), 65);
|
||||
int t = request->arg("AC").toInt(); if (t > 0 && t < 14) apChannel = t;
|
||||
|
||||
noWifiSleep = request->hasArg("WS");
|
||||
|
||||
char k[3]; k[2] = 0;
|
||||
for (int i = 0; i<4; i++)
|
||||
{
|
||||
k[1] = i+48;//ascii 0,1,2,3
|
||||
|
||||
k[0] = 'I'; //static IP
|
||||
staticIP[i] = request->arg(k).toInt();
|
||||
|
||||
k[0] = 'G'; //gateway
|
||||
staticGateway[i] = request->arg(k).toInt();
|
||||
|
||||
k[0] = 'S'; //subnet
|
||||
staticSubnet[i] = request->arg(k).toInt();
|
||||
}
|
||||
}
|
||||
|
||||
//LED SETTINGS
|
||||
if (subPage == 2)
|
||||
{
|
||||
int t = request->arg("LC").toInt();
|
||||
if (t > 0 && t <= MAX_LEDS) ledCount = t;
|
||||
#ifdef ESP8266
|
||||
#if LEDPIN == 3
|
||||
if (ledCount > MAX_LEDS_DMA) ledCount = MAX_LEDS_DMA; //DMA method uses too much ram
|
||||
#endif
|
||||
#endif
|
||||
strip.ablMilliampsMax = request->arg("MA").toInt();
|
||||
strip.milliampsPerLed = request->arg("LA").toInt();
|
||||
|
||||
useRGBW = request->hasArg("EW");
|
||||
strip.colorOrder = request->arg("CO").toInt();
|
||||
strip.rgbwMode = request->arg("AW").toInt();
|
||||
|
||||
briS = request->arg("CA").toInt();
|
||||
|
||||
saveCurrPresetCycConf = request->hasArg("PC");
|
||||
turnOnAtBoot = request->hasArg("BO");
|
||||
t = request->arg("BP").toInt();
|
||||
if (t <= 25) bootPreset = t;
|
||||
strip.gammaCorrectBri = request->hasArg("GB");
|
||||
strip.gammaCorrectCol = request->hasArg("GC");
|
||||
|
||||
fadeTransition = request->hasArg("TF");
|
||||
t = request->arg("TD").toInt();
|
||||
if (t > 0) transitionDelay = t;
|
||||
transitionDelayDefault = t;
|
||||
strip.paletteFade = request->hasArg("PF");
|
||||
|
||||
nightlightTargetBri = request->arg("TB").toInt();
|
||||
t = request->arg("TL").toInt();
|
||||
if (t > 0) nightlightDelayMinsDefault = t;
|
||||
nightlightDelayMins = nightlightDelayMinsDefault;
|
||||
nightlightFade = request->hasArg("TW");
|
||||
|
||||
t = request->arg("PB").toInt();
|
||||
if (t >= 0 && t < 4) strip.paletteBlend = t;
|
||||
strip.reverseMode = request->hasArg("RV");
|
||||
skipFirstLed = request->hasArg("SL");
|
||||
t = request->arg("BF").toInt();
|
||||
if (t > 0) briMultiplier = t;
|
||||
}
|
||||
|
||||
//UI
|
||||
if (subPage == 3)
|
||||
{
|
||||
strlcpy(serverDescription, request->arg("DS").c_str(), 33);
|
||||
syncToggleReceive = request->hasArg("ST");
|
||||
}
|
||||
|
||||
//SYNC
|
||||
if (subPage == 4)
|
||||
{
|
||||
buttonEnabled = request->hasArg("BT");
|
||||
irEnabled = request->arg("IR").toInt();
|
||||
int t = request->arg("UP").toInt();
|
||||
if (t > 0) udpPort = t;
|
||||
receiveNotificationBrightness = request->hasArg("RB");
|
||||
receiveNotificationColor = request->hasArg("RC");
|
||||
receiveNotificationEffects = request->hasArg("RX");
|
||||
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
||||
notifyDirectDefault = request->hasArg("SD");
|
||||
notifyDirect = notifyDirectDefault;
|
||||
notifyButton = request->hasArg("SB");
|
||||
notifyAlexa = request->hasArg("SA");
|
||||
notifyHue = request->hasArg("SH");
|
||||
notifyMacro = request->hasArg("SM");
|
||||
notifyTwice = request->hasArg("S2");
|
||||
|
||||
receiveDirect = request->hasArg("RD");
|
||||
e131SkipOutOfSequence = request->hasArg("ES");
|
||||
e131Multicast = request->hasArg("EM");
|
||||
t = request->arg("EP").toInt();
|
||||
if (t > 0) e131Port = t;
|
||||
t = request->arg("EU").toInt();
|
||||
if (t >= 0 && t <= 63999) e131Universe = t;
|
||||
t = request->arg("DA").toInt();
|
||||
if (t >= 0 && t <= 510) DMXAddress = t;
|
||||
t = request->arg("DM").toInt();
|
||||
if (t >= DMX_MODE_DISABLED && t <= DMX_MODE_MULTIPLE_DRGB) DMXMode = t;
|
||||
t = request->arg("ET").toInt();
|
||||
if (t > 99 && t <= 65000) realtimeTimeoutMs = t;
|
||||
arlsForceMaxBri = request->hasArg("FB");
|
||||
arlsDisableGammaCorrection = request->hasArg("RG");
|
||||
t = request->arg("WO").toInt();
|
||||
if (t >= -255 && t <= 255) arlsOffset = t;
|
||||
|
||||
alexaEnabled = request->hasArg("AL");
|
||||
strlcpy(alexaInvocationName, request->arg("AI").c_str(), 33);
|
||||
|
||||
if (request->hasArg("BK") && !request->arg("BK").equals("Hidden")) {
|
||||
strlcpy(blynkApiKey, request->arg("BK").c_str(), 36); initBlynk(blynkApiKey);
|
||||
}
|
||||
|
||||
#ifdef WLED_ENABLE_MQTT
|
||||
mqttEnabled = request->hasArg("MQ");
|
||||
strlcpy(mqttServer, request->arg("MS").c_str(), 33);
|
||||
t = request->arg("MQPORT").toInt();
|
||||
if (t > 0) mqttPort = t;
|
||||
strlcpy(mqttUser, request->arg("MQUSER").c_str(), 41);
|
||||
if (!isAsterisksOnly(request->arg("MQPASS").c_str(), 41)) strlcpy(mqttPass, request->arg("MQPASS").c_str(), 41);
|
||||
strlcpy(mqttClientID, request->arg("MQCID").c_str(), 41);
|
||||
strlcpy(mqttDeviceTopic, request->arg("MD").c_str(), 33);
|
||||
strlcpy(mqttGroupTopic, request->arg("MG").c_str(), 33);
|
||||
#endif
|
||||
|
||||
#ifndef WLED_DISABLE_HUESYNC
|
||||
for (int i=0;i<4;i++){
|
||||
String a = "H"+String(i);
|
||||
hueIP[i] = request->arg(a).toInt();
|
||||
}
|
||||
|
||||
t = request->arg("HL").toInt();
|
||||
if (t > 0) huePollLightId = t;
|
||||
|
||||
t = request->arg("HI").toInt();
|
||||
if (t > 50) huePollIntervalMs = t;
|
||||
|
||||
hueApplyOnOff = request->hasArg("HO");
|
||||
hueApplyBri = request->hasArg("HB");
|
||||
hueApplyColor = request->hasArg("HC");
|
||||
huePollingEnabled = request->hasArg("HP");
|
||||
hueStoreAllowed = true;
|
||||
reconnectHue();
|
||||
#endif
|
||||
}
|
||||
|
||||
//TIME
|
||||
if (subPage == 5)
|
||||
{
|
||||
ntpEnabled = request->hasArg("NT");
|
||||
strlcpy(ntpServerName, request->arg("NS").c_str(), 33);
|
||||
useAMPM = !request->hasArg("CF");
|
||||
currentTimezone = request->arg("TZ").toInt();
|
||||
utcOffsetSecs = request->arg("UO").toInt();
|
||||
|
||||
//start ntp if not already connected
|
||||
if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
|
||||
|
||||
if (request->hasArg("OL")){
|
||||
overlayDefault = request->arg("OL").toInt();
|
||||
overlayCurrent = overlayDefault;
|
||||
}
|
||||
|
||||
overlayMin = request->arg("O1").toInt();
|
||||
overlayMax = request->arg("O2").toInt();
|
||||
analogClock12pixel = request->arg("OM").toInt();
|
||||
analogClock5MinuteMarks = request->hasArg("O5");
|
||||
analogClockSecondsTrail = request->hasArg("OS");
|
||||
|
||||
strcpy(cronixieDisplay,request->arg("CX").c_str());
|
||||
cronixieBacklight = request->hasArg("CB");
|
||||
countdownMode = request->hasArg("CE");
|
||||
countdownYear = request->arg("CY").toInt();
|
||||
countdownMonth = request->arg("CI").toInt();
|
||||
countdownDay = request->arg("CD").toInt();
|
||||
countdownHour = request->arg("CH").toInt();
|
||||
countdownMin = request->arg("CM").toInt();
|
||||
countdownSec = request->arg("CS").toInt();
|
||||
|
||||
for (int i=1;i<17;i++)
|
||||
{
|
||||
String a = "M"+String(i);
|
||||
if (request->hasArg(a.c_str())) saveMacro(i,request->arg(a),false);
|
||||
}
|
||||
|
||||
macroBoot = request->arg("MB").toInt();
|
||||
macroAlexaOn = request->arg("A0").toInt();
|
||||
macroAlexaOff = request->arg("A1").toInt();
|
||||
macroButton = request->arg("MP").toInt();
|
||||
macroLongPress = request->arg("ML").toInt();
|
||||
macroCountdown = request->arg("MC").toInt();
|
||||
macroNl = request->arg("MN").toInt();
|
||||
macroDoublePress = request->arg("MD").toInt();
|
||||
|
||||
char k[3]; k[2] = 0;
|
||||
for (int i = 0; i<8; i++)
|
||||
{
|
||||
k[1] = i+48;//ascii 0,1,2,3
|
||||
|
||||
k[0] = 'H'; //timer hours
|
||||
timerHours[i] = request->arg(k).toInt();
|
||||
|
||||
k[0] = 'N'; //minutes
|
||||
timerMinutes[i] = request->arg(k).toInt();
|
||||
|
||||
k[0] = 'T'; //macros
|
||||
timerMacro[i] = request->arg(k).toInt();
|
||||
|
||||
k[0] = 'W'; //weekdays
|
||||
timerWeekday[i] = request->arg(k).toInt();
|
||||
}
|
||||
}
|
||||
|
||||
//SECURITY
|
||||
if (subPage == 6)
|
||||
{
|
||||
if (request->hasArg("RS")) //complete factory reset
|
||||
{
|
||||
clearEEPROM();
|
||||
serveMessage(request, 200, "All Settings erased.", "Connect to WLED-AP to setup again",255);
|
||||
doReboot = true;
|
||||
}
|
||||
|
||||
bool pwdCorrect = !otaLock; //always allow access if ota not locked
|
||||
if (request->hasArg("OP"))
|
||||
{
|
||||
if (otaLock && strcmp(otaPass,request->arg("OP").c_str()) == 0)
|
||||
{
|
||||
pwdCorrect = true;
|
||||
}
|
||||
if (!otaLock && request->arg("OP").length() > 0)
|
||||
{
|
||||
strlcpy(otaPass,request->arg("OP").c_str(), 33);
|
||||
}
|
||||
}
|
||||
|
||||
if (pwdCorrect) //allow changes if correct pwd or no ota active
|
||||
{
|
||||
otaLock = request->hasArg("NO");
|
||||
wifiLock = request->hasArg("OW");
|
||||
aOtaEnabled = request->hasArg("AO");
|
||||
}
|
||||
}
|
||||
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
||||
if (subPage == 7)
|
||||
{
|
||||
int t = request->arg("CN").toInt();
|
||||
if (t>0 && t<16) {
|
||||
DMXChannels = t;
|
||||
}
|
||||
t = request->arg("CS").toInt();
|
||||
if (t>0 && t<513) {
|
||||
DMXStart = t;
|
||||
}
|
||||
t = request->arg("CG").toInt();
|
||||
if (t>0 && t<513) {
|
||||
DMXGap = t;
|
||||
}
|
||||
t = request->arg("SL").toInt();
|
||||
if (t>=0 && t < MAX_LEDS) {
|
||||
DMXStartLED = t;
|
||||
}
|
||||
for (int i=0; i<15; i++) {
|
||||
String argname = "CH" + String((i+1));
|
||||
t = request->arg(argname).toInt();
|
||||
DMXFixtureMap[i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
if (subPage != 6 || !doReboot) saveSettingsToEEPROM(); //do not save if factory reset
|
||||
if (subPage == 2) {
|
||||
strip.init(useRGBW,ledCount,skipFirstLed);
|
||||
}
|
||||
if (subPage == 4) alexaInit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//helper to get int value at a position in string
|
||||
int getNumVal(const String* req, uint16_t pos)
|
||||
{
|
||||
return req->substring(pos+3).toInt();
|
||||
}
|
||||
|
||||
|
||||
//helper to get int value at a position in string
|
||||
bool updateVal(const String* req, const char* key, byte* val, byte minv, byte maxv)
|
||||
{
|
||||
int pos = req->indexOf(key);
|
||||
if (pos < 1) return false;
|
||||
|
||||
if (req->charAt(pos+3) == '~') {
|
||||
int out = getNumVal(req, pos+1);
|
||||
if (out == 0)
|
||||
{
|
||||
if (req->charAt(pos+4) == '-')
|
||||
{
|
||||
*val = (*val <= minv)? maxv : *val -1;
|
||||
} else {
|
||||
*val = (*val >= maxv)? minv : *val +1;
|
||||
}
|
||||
} else {
|
||||
out += *val;
|
||||
if (out > maxv) out = maxv;
|
||||
if (out < minv) out = minv;
|
||||
*val = out;
|
||||
}
|
||||
} else
|
||||
{
|
||||
*val = getNumVal(req, pos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//HTTP API request parser
|
||||
bool handleSet(AsyncWebServerRequest *request, const String& req)
|
||||
{
|
||||
if (!(req.indexOf("win") >= 0)) return false;
|
||||
|
||||
int pos = 0;
|
||||
DEBUG_PRINT("API req: ");
|
||||
DEBUG_PRINTLN(req);
|
||||
|
||||
//write presets and macros saved to flash directly?
|
||||
bool persistSaves = true;
|
||||
pos = req.indexOf("NP");
|
||||
if (pos > 0) {
|
||||
persistSaves = false;
|
||||
}
|
||||
|
||||
//save macro, requires &MS=<slot>(<macro>) format
|
||||
pos = req.indexOf("&MS=");
|
||||
if (pos > 0) {
|
||||
int i = req.substring(pos + 4).toInt();
|
||||
pos = req.indexOf('(') +1;
|
||||
if (pos > 0) {
|
||||
int en = req.indexOf(')');
|
||||
String mc = req.substring(pos);
|
||||
if (en > 0) mc = req.substring(pos, en);
|
||||
saveMacro(i, mc, persistSaves);
|
||||
}
|
||||
|
||||
pos = req.indexOf("IN");
|
||||
if (pos < 1) XML_response(request);
|
||||
return true;
|
||||
//if you save a macro in one request, other commands in that request are ignored due to unwanted behavior otherwise
|
||||
}
|
||||
|
||||
strip.applyToAllSelected = true;
|
||||
|
||||
//segment select (sets main segment)
|
||||
byte prevMain = strip.getMainSegmentId();
|
||||
pos = req.indexOf("SM=");
|
||||
if (pos > 0) {
|
||||
strip.mainSegment = getNumVal(&req, pos);
|
||||
}
|
||||
byte main = strip.getMainSegmentId();
|
||||
if (main != prevMain) setValuesFromMainSeg();
|
||||
|
||||
pos = req.indexOf("SS=");
|
||||
if (pos > 0) {
|
||||
byte t = getNumVal(&req, pos);
|
||||
if (t < strip.getMaxSegments()) main = t;
|
||||
}
|
||||
|
||||
WS2812FX::Segment& mainseg = strip.getSegment(main);
|
||||
pos = req.indexOf("SV="); //segment selected
|
||||
if (pos > 0) mainseg.setOption(SEG_OPTION_SELECTED, (req.charAt(pos+3) != '0'));
|
||||
|
||||
uint16_t startI = mainseg.start;
|
||||
uint16_t stopI = mainseg.stop;
|
||||
uint8_t grpI = mainseg.grouping;
|
||||
uint16_t spcI = mainseg.spacing;
|
||||
pos = req.indexOf("&S="); //segment start
|
||||
if (pos > 0) {
|
||||
startI = getNumVal(&req, pos);
|
||||
}
|
||||
pos = req.indexOf("S2="); //segment stop
|
||||
if (pos > 0) {
|
||||
stopI = getNumVal(&req, pos);
|
||||
}
|
||||
pos = req.indexOf("GP="); //segment grouping
|
||||
if (pos > 0) {
|
||||
grpI = getNumVal(&req, pos);
|
||||
if (grpI == 0) grpI = 1;
|
||||
}
|
||||
pos = req.indexOf("SP="); //segment spacing
|
||||
if (pos > 0) {
|
||||
spcI = getNumVal(&req, pos);
|
||||
}
|
||||
strip.setSegment(main, startI, stopI, grpI, spcI);
|
||||
|
||||
main = strip.getMainSegmentId();
|
||||
|
||||
//set presets
|
||||
pos = req.indexOf("P1="); //sets first preset for cycle
|
||||
if (pos > 0) presetCycleMin = getNumVal(&req, pos);
|
||||
|
||||
pos = req.indexOf("P2="); //sets last preset for cycle
|
||||
if (pos > 0) presetCycleMax = getNumVal(&req, pos);
|
||||
|
||||
//preset cycle
|
||||
pos = req.indexOf("CY=");
|
||||
if (pos > 0)
|
||||
{
|
||||
presetCyclingEnabled = (req.charAt(pos+3) != '0');
|
||||
presetCycCurr = presetCycleMin;
|
||||
}
|
||||
|
||||
pos = req.indexOf("PT="); //sets cycle time in ms
|
||||
if (pos > 0) {
|
||||
int v = getNumVal(&req, pos);
|
||||
if (v > 49) presetCycleTime = v;
|
||||
}
|
||||
|
||||
pos = req.indexOf("PA="); //apply brightness from preset
|
||||
if (pos > 0) presetApplyBri = (req.charAt(pos+3) != '0');
|
||||
|
||||
pos = req.indexOf("PS="); //saves current in preset
|
||||
if (pos > 0) savePreset(getNumVal(&req, pos), persistSaves);
|
||||
|
||||
//apply preset
|
||||
if (updateVal(&req, "PL=", &presetCycCurr, presetCycleMin, presetCycleMax)) {
|
||||
applyPreset(presetCycCurr, presetApplyBri);
|
||||
}
|
||||
|
||||
//set brightness
|
||||
updateVal(&req, "&A=", &bri);
|
||||
|
||||
//set colors
|
||||
updateVal(&req, "&R=", &col[0]);
|
||||
updateVal(&req, "&G=", &col[1]);
|
||||
updateVal(&req, "&B=", &col[2]);
|
||||
updateVal(&req, "&W=", &col[3]);
|
||||
updateVal(&req, "R2=", &colSec[0]);
|
||||
updateVal(&req, "G2=", &colSec[1]);
|
||||
updateVal(&req, "B2=", &colSec[2]);
|
||||
updateVal(&req, "W2=", &colSec[3]);
|
||||
|
||||
//set hue
|
||||
pos = req.indexOf("HU=");
|
||||
if (pos > 0) {
|
||||
uint16_t temphue = getNumVal(&req, pos);
|
||||
byte tempsat = 255;
|
||||
pos = req.indexOf("SA=");
|
||||
if (pos > 0) {
|
||||
tempsat = getNumVal(&req, pos);
|
||||
}
|
||||
colorHStoRGB(temphue,tempsat,(req.indexOf("H2")>0)? colSec:col);
|
||||
}
|
||||
|
||||
//set color from HEX or 32bit DEC
|
||||
pos = req.indexOf("CL=");
|
||||
if (pos > 0) {
|
||||
colorFromDecOrHexString(col, (char*)req.substring(pos + 3).c_str());
|
||||
}
|
||||
pos = req.indexOf("C2=");
|
||||
if (pos > 0) {
|
||||
colorFromDecOrHexString(colSec, (char*)req.substring(pos + 3).c_str());
|
||||
}
|
||||
pos = req.indexOf("C3=");
|
||||
if (pos > 0) {
|
||||
byte t[4];
|
||||
colorFromDecOrHexString(t, (char*)req.substring(pos + 3).c_str());
|
||||
strip.setColor(2, t[0], t[1], t[2], t[3]);
|
||||
}
|
||||
|
||||
//set to random hue SR=0->1st SR=1->2nd
|
||||
pos = req.indexOf("SR");
|
||||
if (pos > 0) {
|
||||
_setRandomColor(getNumVal(&req, pos));
|
||||
}
|
||||
|
||||
//swap 2nd & 1st
|
||||
pos = req.indexOf("SC");
|
||||
if (pos > 0) {
|
||||
byte temp;
|
||||
for (uint8_t i=0; i<4; i++)
|
||||
{
|
||||
temp = col[i];
|
||||
col[i] = colSec[i];
|
||||
colSec[i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
//set effect parameters
|
||||
if (updateVal(&req, "FX=", &effectCurrent, 0, strip.getModeCount()-1)) presetCyclingEnabled = false;
|
||||
updateVal(&req, "SX=", &effectSpeed);
|
||||
updateVal(&req, "IX=", &effectIntensity);
|
||||
updateVal(&req, "FP=", &effectPalette, 0, strip.getPaletteCount()-1);
|
||||
|
||||
//set advanced overlay
|
||||
pos = req.indexOf("OL=");
|
||||
if (pos > 0) {
|
||||
overlayCurrent = getNumVal(&req, pos);
|
||||
}
|
||||
|
||||
//apply macro
|
||||
pos = req.indexOf("&M=");
|
||||
if (pos > 0) {
|
||||
applyMacro(getNumVal(&req, pos));
|
||||
}
|
||||
|
||||
//toggle send UDP direct notifications
|
||||
pos = req.indexOf("SN=");
|
||||
if (pos > 0) notifyDirect = (req.charAt(pos+3) != '0');
|
||||
|
||||
//toggle receive UDP direct notifications
|
||||
pos = req.indexOf("RN=");
|
||||
if (pos > 0) receiveNotifications = (req.charAt(pos+3) != '0');
|
||||
|
||||
//receive live data via UDP/Hyperion
|
||||
pos = req.indexOf("RD=");
|
||||
if (pos > 0) receiveDirect = (req.charAt(pos+3) != '0');
|
||||
|
||||
//toggle nightlight mode
|
||||
bool aNlDef = false;
|
||||
if (req.indexOf("&ND") > 0) aNlDef = true;
|
||||
pos = req.indexOf("NL=");
|
||||
if (pos > 0)
|
||||
{
|
||||
if (req.charAt(pos+3) == '0')
|
||||
{
|
||||
nightlightActive = false;
|
||||
bri = briT;
|
||||
} else {
|
||||
nightlightActive = true;
|
||||
if (!aNlDef) nightlightDelayMins = getNumVal(&req, pos);
|
||||
nightlightStartTime = millis();
|
||||
}
|
||||
} else if (aNlDef)
|
||||
{
|
||||
nightlightActive = true;
|
||||
nightlightStartTime = millis();
|
||||
}
|
||||
|
||||
//set nightlight target brightness
|
||||
pos = req.indexOf("NT=");
|
||||
if (pos > 0) {
|
||||
nightlightTargetBri = getNumVal(&req, pos);
|
||||
nightlightActiveOld = false; //re-init
|
||||
}
|
||||
|
||||
//toggle nightlight fade
|
||||
pos = req.indexOf("NF=");
|
||||
if (pos > 0)
|
||||
{
|
||||
nightlightFade = (req.charAt(pos+3) != '0');
|
||||
nightlightColorFade = (req.charAt(pos+3) == '2'); //NighLightColorFade can only be enabled via API or Macro with "NF=2"
|
||||
nightlightActiveOld = false; //re-init
|
||||
}
|
||||
|
||||
#if AUXPIN >= 0
|
||||
//toggle general purpose output
|
||||
pos = req.indexOf("AX=");
|
||||
if (pos > 0) {
|
||||
auxTime = getNumVal(&req, pos);
|
||||
auxActive = true;
|
||||
if (auxTime == 0) auxActive = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
pos = req.indexOf("TT=");
|
||||
if (pos > 0) transitionDelay = getNumVal(&req, pos);
|
||||
|
||||
//main toggle on/off
|
||||
pos = req.indexOf("&T=");
|
||||
if (pos > 0) {
|
||||
nightlightActive = false; //always disable nightlight when toggling
|
||||
switch (getNumVal(&req, pos))
|
||||
{
|
||||
case 0: if (bri != 0){briLast = bri; bri = 0;} break; //off
|
||||
case 1: bri = briLast; break; //on
|
||||
default: toggleOnOff(); //toggle
|
||||
}
|
||||
}
|
||||
|
||||
//Segment reverse
|
||||
pos = req.indexOf("RV=");
|
||||
if (pos > 0) strip.getSegment(main).setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0');
|
||||
|
||||
//Segment brightness/opacity
|
||||
pos = req.indexOf("SB=");
|
||||
if (pos > 0) {
|
||||
byte segbri = getNumVal(&req, pos);
|
||||
strip.getSegment(main).setOption(SEG_OPTION_ON, segbri);
|
||||
if (segbri) {
|
||||
strip.getSegment(main).opacity = segbri;
|
||||
}
|
||||
}
|
||||
|
||||
//deactivate nightlight if target brightness is reached
|
||||
if (bri == nightlightTargetBri) nightlightActive = false;
|
||||
//set time (unix timestamp)
|
||||
pos = req.indexOf("ST=");
|
||||
if (pos > 0) {
|
||||
setTime(getNumVal(&req, pos));
|
||||
}
|
||||
|
||||
//set countdown goal (unix timestamp)
|
||||
pos = req.indexOf("CT=");
|
||||
if (pos > 0) {
|
||||
countdownTime = getNumVal(&req, pos);
|
||||
if (countdownTime - now() > 0) countdownOverTriggered = false;
|
||||
}
|
||||
|
||||
pos = req.indexOf("RB");
|
||||
if (pos > 0) doReboot = true;
|
||||
|
||||
//cronixie
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
//mode, 1 countdown
|
||||
pos = req.indexOf("NM=");
|
||||
if (pos > 0) countdownMode = (req.charAt(pos+3) != '0');
|
||||
|
||||
pos = req.indexOf("NX="); //sets digits to code
|
||||
if (pos > 0) {
|
||||
strlcpy(cronixieDisplay, req.substring(pos + 3, pos + 9).c_str(), 6);
|
||||
setCronixie();
|
||||
}
|
||||
|
||||
pos = req.indexOf("NB=");
|
||||
if (pos > 0) //sets backlight
|
||||
{
|
||||
cronixieBacklight = (req.charAt(pos+3) != '0');
|
||||
overlayRefreshedTime = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
pos = req.indexOf("U0="); //user var 0
|
||||
if (pos > 0) {
|
||||
userVar0 = getNumVal(&req, pos);
|
||||
}
|
||||
|
||||
pos = req.indexOf("U1="); //user var 1
|
||||
if (pos > 0) {
|
||||
userVar1 = getNumVal(&req, pos);
|
||||
}
|
||||
//you can add more if you need
|
||||
|
||||
//internal call, does not send XML response
|
||||
pos = req.indexOf("IN");
|
||||
if (pos < 1) XML_response(request);
|
||||
|
||||
pos = req.indexOf("&NN"); //do not send UDP notifications this time
|
||||
colorUpdated((pos > 0) ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
|
||||
return true;
|
||||
}
|
||||
318
wled00/src/dependencies/arduino/core_esp8266_waveform.cpp
Normal file
318
wled00/src/dependencies/arduino/core_esp8266_waveform.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
esp8266_waveform - General purpose waveform generation and control,
|
||||
supporting outputs on all pins in parallel.
|
||||
|
||||
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
The core idea is to have a programmable waveform generator with a unique
|
||||
high and low period (defined in microseconds). TIMER1 is set to 1-shot
|
||||
mode and is always loaded with the time until the next edge of any live
|
||||
waveforms.
|
||||
|
||||
Up to one waveform generator per pin supported.
|
||||
|
||||
Each waveform generator is synchronized to the ESP cycle counter, not the
|
||||
timer. This allows for removing interrupt jitter and delay as the counter
|
||||
always increments once per 80MHz clock. Changes to a waveform are
|
||||
contiguous and only take effect on the next waveform transition,
|
||||
allowing for smooth transitions.
|
||||
|
||||
This replaces older tone(), analogWrite(), and the Servo classes.
|
||||
|
||||
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
|
||||
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#ifdef ESP8266
|
||||
#include <Arduino.h>
|
||||
#include "ets_sys.h"
|
||||
#include "core_esp8266_waveform.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Maximum delay between IRQs
|
||||
#define MAXIRQUS (10000)
|
||||
|
||||
// Set/clear GPIO 0-15 by bitmask
|
||||
#define SetGPIO(a) do { GPOS = a; } while (0)
|
||||
#define ClearGPIO(a) do { GPOC = a; } while (0)
|
||||
|
||||
// Waveform generator can create tones, PWM, and servos
|
||||
typedef struct {
|
||||
uint32_t nextServiceCycle; // ESP cycle timer when a transition required
|
||||
uint32_t expiryCycle; // For time-limited waveform, the cycle when this waveform must stop
|
||||
uint32_t nextTimeHighCycles; // Copy over low->high to keep smooth waveform
|
||||
uint32_t nextTimeLowCycles; // Copy over high->low to keep smooth waveform
|
||||
} Waveform;
|
||||
|
||||
static Waveform waveform[17]; // State of all possible pins
|
||||
static volatile uint32_t waveformState = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code
|
||||
static volatile uint32_t waveformEnabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code
|
||||
|
||||
// Enable lock-free by only allowing updates to waveformState and waveformEnabled from IRQ service routine
|
||||
static volatile uint32_t waveformToEnable = 0; // Message to the NMI handler to start a waveform on a inactive pin
|
||||
static volatile uint32_t waveformToDisable = 0; // Message to the NMI handler to disable a pin from waveform generation
|
||||
|
||||
static uint32_t (*timer1CB)() = NULL;
|
||||
|
||||
|
||||
// Non-speed critical bits
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
static inline ICACHE_RAM_ATTR uint32_t GetCycleCount() {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("esync; rsr %0,ccount":"=a"(ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
// Interrupt on/off control
|
||||
static ICACHE_RAM_ATTR void timer1Interrupt();
|
||||
static bool timerRunning = false;
|
||||
|
||||
static void initTimer() {
|
||||
timer1_disable();
|
||||
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt);
|
||||
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
|
||||
timerRunning = true;
|
||||
}
|
||||
|
||||
static void ICACHE_RAM_ATTR deinitTimer() {
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
|
||||
timer1_disable();
|
||||
timer1_isr_init();
|
||||
timerRunning = false;
|
||||
}
|
||||
|
||||
// Set a callback. Pass in NULL to stop it
|
||||
void setTimer1Callback(uint32_t (*fn)()) {
|
||||
timer1CB = fn;
|
||||
if (!timerRunning && fn) {
|
||||
initTimer();
|
||||
timer1_write(microsecondsToClockCycles(1)); // Cause an interrupt post-haste
|
||||
} else if (timerRunning && !fn && !waveformEnabled) {
|
||||
deinitTimer();
|
||||
}
|
||||
}
|
||||
|
||||
// Start up a waveform on a pin, or change the current one. Will change to the new
|
||||
// waveform smoothly on next low->high transition. For immediate change, stopWaveform()
|
||||
// first, then it will immediately begin.
|
||||
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) {
|
||||
if ((pin > 16) || isFlashInterfacePin(pin)) {
|
||||
return false;
|
||||
}
|
||||
Waveform *wave = &waveform[pin];
|
||||
// Adjust to shave off some of the IRQ time, approximately
|
||||
wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS);
|
||||
wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS);
|
||||
wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0;
|
||||
if (runTimeUS && !wave->expiryCycle) {
|
||||
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
|
||||
}
|
||||
|
||||
uint32_t mask = 1<<pin;
|
||||
if (!(waveformEnabled & mask)) {
|
||||
// Actually set the pin high or low in the IRQ service to guarantee times
|
||||
wave->nextServiceCycle = GetCycleCount() + microsecondsToClockCycles(1);
|
||||
waveformToEnable |= mask;
|
||||
if (!timerRunning) {
|
||||
initTimer();
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
} else {
|
||||
// Ensure timely service....
|
||||
if (T1L > microsecondsToClockCycles(10)) {
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
}
|
||||
}
|
||||
while (waveformToEnable) {
|
||||
delay(0); // Wait for waveform to update
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Speed critical bits
|
||||
#pragma GCC optimize ("O2")
|
||||
// Normally would not want two copies like this, but due to different
|
||||
// optimization levels the inline attribute gets lost if we try the
|
||||
// other version.
|
||||
|
||||
static inline ICACHE_RAM_ATTR uint32_t GetCycleCountIRQ() {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a"(ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
static inline ICACHE_RAM_ATTR uint32_t min_u32(uint32_t a, uint32_t b) {
|
||||
if (a < b) {
|
||||
return a;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// Stops a waveform on a pin
|
||||
int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
|
||||
// Can't possibly need to stop anything if there is no timer active
|
||||
if (!timerRunning) {
|
||||
return false;
|
||||
}
|
||||
// If user sends in a pin >16 but <32, this will always point to a 0 bit
|
||||
// If they send >=32, then the shift will result in 0 and it will also return false
|
||||
uint32_t mask = 1<<pin;
|
||||
if (!(waveformEnabled & mask)) {
|
||||
return false; // It's not running, nothing to do here
|
||||
}
|
||||
waveformToDisable |= mask;
|
||||
// Ensure timely service....
|
||||
if (T1L > microsecondsToClockCycles(10)) {
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
}
|
||||
while (waveformToDisable) {
|
||||
/* no-op */ // Can't delay() since stopWaveform may be called from an IRQ
|
||||
}
|
||||
if (!waveformEnabled && !timer1CB) {
|
||||
deinitTimer();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// The SDK and hardware take some time to actually get to our NMI code, so
|
||||
// decrement the next IRQ's timer value by a bit so we can actually catch the
|
||||
// real CPU cycle counter we want for the waveforms.
|
||||
#if F_CPU == 80000000
|
||||
#define DELTAIRQ (microsecondsToClockCycles(3))
|
||||
#else
|
||||
#define DELTAIRQ (microsecondsToClockCycles(2))
|
||||
#endif
|
||||
|
||||
|
||||
static ICACHE_RAM_ATTR void timer1Interrupt() {
|
||||
// Optimize the NMI inner loop by keeping track of the min and max GPIO that we
|
||||
// are generating. In the common case (1 PWM) these may be the same pin and
|
||||
// we can avoid looking at the other pins.
|
||||
static int startPin = 0;
|
||||
static int endPin = 0;
|
||||
|
||||
uint32_t nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
|
||||
uint32_t timeoutCycle = GetCycleCountIRQ() + microsecondsToClockCycles(14);
|
||||
|
||||
if (waveformToEnable || waveformToDisable) {
|
||||
// Handle enable/disable requests from main app.
|
||||
waveformEnabled = (waveformEnabled & ~waveformToDisable) | waveformToEnable; // Set the requested waveforms on/off
|
||||
waveformState &= ~waveformToEnable; // And clear the state of any just started
|
||||
waveformToEnable = 0;
|
||||
waveformToDisable = 0;
|
||||
// Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t)
|
||||
startPin = __builtin_ffs(waveformEnabled) - 1;
|
||||
// Find the last bit by subtracting off GCC's count-leading-zeros (no offset in this one)
|
||||
endPin = 32 - __builtin_clz(waveformEnabled);
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
if (waveformEnabled) {
|
||||
do {
|
||||
nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
|
||||
for (int i = startPin; i <= endPin; i++) {
|
||||
uint32_t mask = 1<<i;
|
||||
|
||||
// If it's not on, ignore!
|
||||
if (!(waveformEnabled & mask)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Waveform *wave = &waveform[i];
|
||||
uint32_t now = GetCycleCountIRQ();
|
||||
|
||||
// Disable any waveforms that are done
|
||||
if (wave->expiryCycle) {
|
||||
int32_t expiryToGo = wave->expiryCycle - now;
|
||||
if (expiryToGo < 0) {
|
||||
// Done, remove!
|
||||
waveformEnabled &= ~mask;
|
||||
if (i == 16) {
|
||||
GP16O &= ~1;
|
||||
} else {
|
||||
ClearGPIO(mask);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for toggles
|
||||
int32_t cyclesToGo = wave->nextServiceCycle - now;
|
||||
if (cyclesToGo < 0) {
|
||||
// See #7057
|
||||
// The following is a no-op unless we have overshot by an entire waveform cycle.
|
||||
// As modulus is an expensive operation, this code is removed for now:
|
||||
// cyclesToGo = -((-cyclesToGo) % (wave->nextTimeHighCycles + wave->nextTimeLowCycles));
|
||||
//
|
||||
// Alternative version with lower CPU impact:
|
||||
// while (-cyclesToGo > wave->nextTimeHighCycles + wave->nextTimeLowCycles) { cyclesToGo += wave->nextTimeHighCycles + wave->nextTimeLowCycles)};
|
||||
waveformState ^= mask;
|
||||
if (waveformState & mask) {
|
||||
if (i == 16) {
|
||||
GP16O |= 1; // GPIO16 write slow as it's RMW
|
||||
} else {
|
||||
SetGPIO(mask);
|
||||
}
|
||||
wave->nextServiceCycle = now + wave->nextTimeHighCycles + cyclesToGo;
|
||||
nextEventCycles = min_u32(nextEventCycles, min_u32(wave->nextTimeHighCycles + cyclesToGo, 1));
|
||||
} else {
|
||||
if (i == 16) {
|
||||
GP16O &= ~1; // GPIO16 write slow as it's RMW
|
||||
} else {
|
||||
ClearGPIO(mask);
|
||||
}
|
||||
wave->nextServiceCycle = now + wave->nextTimeLowCycles + cyclesToGo;
|
||||
nextEventCycles = min_u32(nextEventCycles, min_u32(wave->nextTimeLowCycles + cyclesToGo, 1));
|
||||
}
|
||||
} else {
|
||||
uint32_t deltaCycles = wave->nextServiceCycle - now;
|
||||
nextEventCycles = min_u32(nextEventCycles, deltaCycles);
|
||||
}
|
||||
}
|
||||
|
||||
// Exit the loop if we've hit the fixed runtime limit or the next event is known to be after that timeout would occur
|
||||
uint32_t now = GetCycleCountIRQ();
|
||||
int32_t cycleDeltaNextEvent = timeoutCycle - (now + nextEventCycles);
|
||||
int32_t cyclesLeftTimeout = timeoutCycle - now;
|
||||
done = (cycleDeltaNextEvent < 0) || (cyclesLeftTimeout < 0);
|
||||
} while (!done);
|
||||
} // if (waveformEnabled)
|
||||
|
||||
if (timer1CB) {
|
||||
nextEventCycles = min_u32(nextEventCycles, timer1CB());
|
||||
}
|
||||
|
||||
if (nextEventCycles < microsecondsToClockCycles(10)) {
|
||||
nextEventCycles = microsecondsToClockCycles(10);
|
||||
}
|
||||
nextEventCycles -= DELTAIRQ;
|
||||
|
||||
// Do it here instead of global function to save time and because we know it's edge-IRQ
|
||||
#if F_CPU == 160000000
|
||||
T1L = nextEventCycles >> 1; // Already know we're in range by MAXIRQUS
|
||||
#else
|
||||
T1L = nextEventCycles; // Already know we're in range by MAXIRQUS
|
||||
#endif
|
||||
TEIE |= TEIE1; // Edge int enable
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
71
wled00/src/dependencies/arduino/core_esp8266_waveform.h
Normal file
71
wled00/src/dependencies/arduino/core_esp8266_waveform.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
esp8266_waveform - General purpose waveform generation and control,
|
||||
supporting outputs on all pins in parallel.
|
||||
|
||||
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
The core idea is to have a programmable waveform generator with a unique
|
||||
high and low period (defined in microseconds). TIMER1 is set to 1-shot
|
||||
mode and is always loaded with the time until the next edge of any live
|
||||
waveforms.
|
||||
|
||||
Up to one waveform generator per pin supported.
|
||||
|
||||
Each waveform generator is synchronized to the ESP cycle counter, not the
|
||||
timer. This allows for removing interrupt jitter and delay as the counter
|
||||
always increments once per 80MHz clock. Changes to a waveform are
|
||||
contiguous and only take effect on the next waveform transition,
|
||||
allowing for smooth transitions.
|
||||
|
||||
This replaces older tone(), analogWrite(), and the Servo classes.
|
||||
|
||||
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
|
||||
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifndef __ESP8266_WAVEFORM_H
|
||||
#define __ESP8266_WAVEFORM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Start or change a waveform of the specified high and low times on specific pin.
|
||||
// If runtimeUS > 0 then automatically stop it after that many usecs.
|
||||
// Returns true or false on success or failure.
|
||||
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS);
|
||||
// Stop a waveform, if any, on the specified pin.
|
||||
// Returns true or false on success or failure.
|
||||
int stopWaveform(uint8_t pin);
|
||||
|
||||
// Add a callback function to be called on *EVERY* timer1 trigger. The
|
||||
// callback returns the number of microseconds until the next desired call.
|
||||
// However, since it is called every timer1 interrupt, it may be called
|
||||
// again before this period. It should therefore use the ESP Cycle Counter
|
||||
// to determine whether or not to perform an operation.
|
||||
// Pass in NULL to disable the callback and, if no other waveforms being
|
||||
// generated, stop the timer as well.
|
||||
// Make sure the CB function has the ICACHE_RAM_ATTR decorator.
|
||||
void setTimer1Callback(uint32_t (*fn)());
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
877
wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp
Normal file
877
wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.cpp
Normal file
@@ -0,0 +1,877 @@
|
||||
#include "AsyncMqttClient.hpp"
|
||||
|
||||
AsyncMqttClient::AsyncMqttClient()
|
||||
: _connected(false)
|
||||
, _connectPacketNotEnoughSpace(false)
|
||||
, _disconnectFlagged(false)
|
||||
, _tlsBadFingerprint(false)
|
||||
, _lastClientActivity(0)
|
||||
, _lastServerActivity(0)
|
||||
, _lastPingRequestTime(0)
|
||||
, _host(nullptr)
|
||||
, _useIp(false)
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
, _secure(false)
|
||||
#endif
|
||||
, _port(0)
|
||||
, _keepAlive(15)
|
||||
, _cleanSession(true)
|
||||
, _clientId(nullptr)
|
||||
, _username(nullptr)
|
||||
, _password(nullptr)
|
||||
, _willTopic(nullptr)
|
||||
, _willPayload(nullptr)
|
||||
, _willPayloadLength(0)
|
||||
, _willQos(0)
|
||||
, _willRetain(false)
|
||||
, _parsingInformation { .bufferState = AsyncMqttClientInternals::BufferState::NONE }
|
||||
, _currentParsedPacket(nullptr)
|
||||
, _remainingLengthBufferPosition(0)
|
||||
, _nextPacketId(1) {
|
||||
_client.onConnect([](void* obj, AsyncClient* c) { (static_cast<AsyncMqttClient*>(obj))->_onConnect(c); }, this);
|
||||
_client.onDisconnect([](void* obj, AsyncClient* c) { (static_cast<AsyncMqttClient*>(obj))->_onDisconnect(c); }, this);
|
||||
_client.onError([](void* obj, AsyncClient* c, int8_t error) { (static_cast<AsyncMqttClient*>(obj))->_onError(c, error); }, this);
|
||||
_client.onTimeout([](void* obj, AsyncClient* c, uint32_t time) { (static_cast<AsyncMqttClient*>(obj))->_onTimeout(c, time); }, this);
|
||||
_client.onAck([](void* obj, AsyncClient* c, size_t len, uint32_t time) { (static_cast<AsyncMqttClient*>(obj))->_onAck(c, len, time); }, this);
|
||||
_client.onData([](void* obj, AsyncClient* c, void* data, size_t len) { (static_cast<AsyncMqttClient*>(obj))->_onData(c, static_cast<char*>(data), len); }, this);
|
||||
_client.onPoll([](void* obj, AsyncClient* c) { (static_cast<AsyncMqttClient*>(obj))->_onPoll(c); }, this);
|
||||
|
||||
#ifdef ESP32
|
||||
sprintf(_generatedClientId, "esp32%06x", ESP.getEfuseMac());
|
||||
_xSemaphore = xSemaphoreCreateMutex();
|
||||
#elif defined(ESP8266)
|
||||
sprintf(_generatedClientId, "esp8266%06x", ESP.getChipId());
|
||||
#endif
|
||||
_clientId = _generatedClientId;
|
||||
|
||||
setMaxTopicLength(128);
|
||||
}
|
||||
|
||||
AsyncMqttClient::~AsyncMqttClient() {
|
||||
delete _currentParsedPacket;
|
||||
delete[] _parsingInformation.topicBuffer;
|
||||
#ifdef ESP32
|
||||
vSemaphoreDelete(_xSemaphore);
|
||||
#endif
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::setKeepAlive(uint16_t keepAlive) {
|
||||
_keepAlive = keepAlive;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::setClientId(const char* clientId) {
|
||||
_clientId = clientId;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::setCleanSession(bool cleanSession) {
|
||||
_cleanSession = cleanSession;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::setMaxTopicLength(uint16_t maxTopicLength) {
|
||||
_parsingInformation.maxTopicLength = maxTopicLength;
|
||||
delete[] _parsingInformation.topicBuffer;
|
||||
_parsingInformation.topicBuffer = new char[maxTopicLength + 1];
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::setCredentials(const char* username, const char* password) {
|
||||
_username = username;
|
||||
_password = password;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::setWill(const char* topic, uint8_t qos, bool retain, const char* payload, size_t length) {
|
||||
_willTopic = topic;
|
||||
_willQos = qos;
|
||||
_willRetain = retain;
|
||||
_willPayload = payload;
|
||||
_willPayloadLength = length;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::setServer(IPAddress ip, uint16_t port) {
|
||||
_useIp = true;
|
||||
_ip = ip;
|
||||
_port = port;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::setServer(const char* host, uint16_t port) {
|
||||
_useIp = false;
|
||||
_host = host;
|
||||
_port = port;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
AsyncMqttClient& AsyncMqttClient::setSecure(bool secure) {
|
||||
_secure = secure;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::addServerFingerprint(const uint8_t* fingerprint) {
|
||||
std::array<uint8_t, SHA1_SIZE> newFingerprint;
|
||||
memcpy(newFingerprint.data(), fingerprint, SHA1_SIZE);
|
||||
_secureServerFingerprints.push_back(newFingerprint);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::onConnect(AsyncMqttClientInternals::OnConnectUserCallback callback) {
|
||||
_onConnectUserCallbacks.push_back(callback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::onDisconnect(AsyncMqttClientInternals::OnDisconnectUserCallback callback) {
|
||||
_onDisconnectUserCallbacks.push_back(callback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::onSubscribe(AsyncMqttClientInternals::OnSubscribeUserCallback callback) {
|
||||
_onSubscribeUserCallbacks.push_back(callback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::onUnsubscribe(AsyncMqttClientInternals::OnUnsubscribeUserCallback callback) {
|
||||
_onUnsubscribeUserCallbacks.push_back(callback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::onMessage(AsyncMqttClientInternals::OnMessageUserCallback callback) {
|
||||
_onMessageUserCallbacks.push_back(callback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AsyncMqttClient& AsyncMqttClient::onPublish(AsyncMqttClientInternals::OnPublishUserCallback callback) {
|
||||
_onPublishUserCallbacks.push_back(callback);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_freeCurrentParsedPacket() {
|
||||
delete _currentParsedPacket;
|
||||
_currentParsedPacket = nullptr;
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_clear() {
|
||||
_lastPingRequestTime = 0;
|
||||
_connected = false;
|
||||
_disconnectFlagged = false;
|
||||
_connectPacketNotEnoughSpace = false;
|
||||
_tlsBadFingerprint = false;
|
||||
_freeCurrentParsedPacket();
|
||||
|
||||
_pendingPubRels.clear();
|
||||
_pendingPubRels.shrink_to_fit();
|
||||
|
||||
_toSendAcks.clear();
|
||||
_toSendAcks.shrink_to_fit();
|
||||
|
||||
_nextPacketId = 1;
|
||||
_parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::NONE;
|
||||
}
|
||||
|
||||
/* TCP */
|
||||
void AsyncMqttClient::_onConnect(AsyncClient* client) {
|
||||
(void)client;
|
||||
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
if (_secure && _secureServerFingerprints.size() > 0) {
|
||||
SSL* clientSsl = _client.getSSL();
|
||||
|
||||
bool sslFoundFingerprint = false;
|
||||
for (std::array<uint8_t, SHA1_SIZE> fingerprint : _secureServerFingerprints) {
|
||||
if (ssl_match_fingerprint(clientSsl, fingerprint.data()) == SSL_OK) {
|
||||
sslFoundFingerprint = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sslFoundFingerprint) {
|
||||
_tlsBadFingerprint = true;
|
||||
_client.close(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
char fixedHeader[5];
|
||||
fixedHeader[0] = AsyncMqttClientInternals::PacketType.CONNECT;
|
||||
fixedHeader[0] = fixedHeader[0] << 4;
|
||||
fixedHeader[0] = fixedHeader[0] | AsyncMqttClientInternals::HeaderFlag.CONNECT_RESERVED;
|
||||
|
||||
uint16_t protocolNameLength = 4;
|
||||
char protocolNameLengthBytes[2];
|
||||
protocolNameLengthBytes[0] = protocolNameLength >> 8;
|
||||
protocolNameLengthBytes[1] = protocolNameLength & 0xFF;
|
||||
|
||||
char protocolLevel[1];
|
||||
protocolLevel[0] = 0x04;
|
||||
|
||||
char connectFlags[1];
|
||||
connectFlags[0] = 0;
|
||||
if (_cleanSession) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.CLEAN_SESSION;
|
||||
if (_username != nullptr) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.USERNAME;
|
||||
if (_password != nullptr) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.PASSWORD;
|
||||
if (_willTopic != nullptr) {
|
||||
connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL;
|
||||
if (_willRetain) connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_RETAIN;
|
||||
switch (_willQos) {
|
||||
case 0:
|
||||
connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS0;
|
||||
break;
|
||||
case 1:
|
||||
connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS1;
|
||||
break;
|
||||
case 2:
|
||||
connectFlags[0] |= AsyncMqttClientInternals::ConnectFlag.WILL_QOS2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char keepAliveBytes[2];
|
||||
keepAliveBytes[0] = _keepAlive >> 8;
|
||||
keepAliveBytes[1] = _keepAlive & 0xFF;
|
||||
|
||||
uint16_t clientIdLength = strlen(_clientId);
|
||||
char clientIdLengthBytes[2];
|
||||
clientIdLengthBytes[0] = clientIdLength >> 8;
|
||||
clientIdLengthBytes[1] = clientIdLength & 0xFF;
|
||||
|
||||
// Optional fields
|
||||
uint16_t willTopicLength = 0;
|
||||
char willTopicLengthBytes[2];
|
||||
uint16_t willPayloadLength = _willPayloadLength;
|
||||
char willPayloadLengthBytes[2];
|
||||
if (_willTopic != nullptr) {
|
||||
willTopicLength = strlen(_willTopic);
|
||||
willTopicLengthBytes[0] = willTopicLength >> 8;
|
||||
willTopicLengthBytes[1] = willTopicLength & 0xFF;
|
||||
|
||||
if (_willPayload != nullptr && willPayloadLength == 0) willPayloadLength = strlen(_willPayload);
|
||||
|
||||
willPayloadLengthBytes[0] = willPayloadLength >> 8;
|
||||
willPayloadLengthBytes[1] = willPayloadLength & 0xFF;
|
||||
}
|
||||
|
||||
uint16_t usernameLength = 0;
|
||||
char usernameLengthBytes[2];
|
||||
if (_username != nullptr) {
|
||||
usernameLength = strlen(_username);
|
||||
usernameLengthBytes[0] = usernameLength >> 8;
|
||||
usernameLengthBytes[1] = usernameLength & 0xFF;
|
||||
}
|
||||
|
||||
uint16_t passwordLength = 0;
|
||||
char passwordLengthBytes[2];
|
||||
if (_password != nullptr) {
|
||||
passwordLength = strlen(_password);
|
||||
passwordLengthBytes[0] = passwordLength >> 8;
|
||||
passwordLengthBytes[1] = passwordLength & 0xFF;
|
||||
}
|
||||
|
||||
uint32_t remainingLength = 2 + protocolNameLength + 1 + 1 + 2 + 2 + clientIdLength; // always present
|
||||
if (_willTopic != nullptr) remainingLength += 2 + willTopicLength + 2 + willPayloadLength;
|
||||
if (_username != nullptr) remainingLength += 2 + usernameLength;
|
||||
if (_password != nullptr) remainingLength += 2 + passwordLength;
|
||||
uint8_t remainingLengthLength = AsyncMqttClientInternals::Helpers::encodeRemainingLength(remainingLength, fixedHeader + 1);
|
||||
|
||||
uint32_t neededSpace = 1 + remainingLengthLength;
|
||||
neededSpace += 2;
|
||||
neededSpace += protocolNameLength;
|
||||
neededSpace += 1;
|
||||
neededSpace += 1;
|
||||
neededSpace += 2;
|
||||
neededSpace += 2;
|
||||
neededSpace += clientIdLength;
|
||||
if (_willTopic != nullptr) {
|
||||
neededSpace += 2;
|
||||
neededSpace += willTopicLength;
|
||||
|
||||
neededSpace += 2;
|
||||
if (_willPayload != nullptr) neededSpace += willPayloadLength;
|
||||
}
|
||||
if (_username != nullptr) {
|
||||
neededSpace += 2;
|
||||
neededSpace += usernameLength;
|
||||
}
|
||||
if (_password != nullptr) {
|
||||
neededSpace += 2;
|
||||
neededSpace += passwordLength;
|
||||
}
|
||||
|
||||
SEMAPHORE_TAKE();
|
||||
if (_client.space() < neededSpace) {
|
||||
_connectPacketNotEnoughSpace = true;
|
||||
_client.close(true);
|
||||
SEMAPHORE_GIVE();
|
||||
return;
|
||||
}
|
||||
|
||||
_client.add(fixedHeader, 1 + remainingLengthLength);
|
||||
_client.add(protocolNameLengthBytes, 2);
|
||||
_client.add("MQTT", protocolNameLength);
|
||||
_client.add(protocolLevel, 1);
|
||||
_client.add(connectFlags, 1);
|
||||
_client.add(keepAliveBytes, 2);
|
||||
_client.add(clientIdLengthBytes, 2);
|
||||
_client.add(_clientId, clientIdLength);
|
||||
if (_willTopic != nullptr) {
|
||||
_client.add(willTopicLengthBytes, 2);
|
||||
_client.add(_willTopic, willTopicLength);
|
||||
|
||||
_client.add(willPayloadLengthBytes, 2);
|
||||
if (_willPayload != nullptr) _client.add(_willPayload, willPayloadLength);
|
||||
}
|
||||
if (_username != nullptr) {
|
||||
_client.add(usernameLengthBytes, 2);
|
||||
_client.add(_username, usernameLength);
|
||||
}
|
||||
if (_password != nullptr) {
|
||||
_client.add(passwordLengthBytes, 2);
|
||||
_client.add(_password, passwordLength);
|
||||
}
|
||||
_client.send();
|
||||
_lastClientActivity = millis();
|
||||
SEMAPHORE_GIVE();
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onDisconnect(AsyncClient* client) {
|
||||
(void)client;
|
||||
if (!_disconnectFlagged) {
|
||||
AsyncMqttClientDisconnectReason reason;
|
||||
|
||||
if (_connectPacketNotEnoughSpace) {
|
||||
reason = AsyncMqttClientDisconnectReason::ESP8266_NOT_ENOUGH_SPACE;
|
||||
} else if (_tlsBadFingerprint) {
|
||||
reason = AsyncMqttClientDisconnectReason::TLS_BAD_FINGERPRINT;
|
||||
} else {
|
||||
reason = AsyncMqttClientDisconnectReason::TCP_DISCONNECTED;
|
||||
}
|
||||
for (auto callback : _onDisconnectUserCallbacks) callback(reason);
|
||||
}
|
||||
_clear();
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onError(AsyncClient* client, int8_t error) {
|
||||
(void)client;
|
||||
(void)error;
|
||||
// _onDisconnect called anyway
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onTimeout(AsyncClient* client, uint32_t time) {
|
||||
(void)client;
|
||||
(void)time;
|
||||
// disconnection will be handled by ping/pong management
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onAck(AsyncClient* client, size_t len, uint32_t time) {
|
||||
(void)client;
|
||||
(void)len;
|
||||
(void)time;
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onData(AsyncClient* client, char* data, size_t len) {
|
||||
(void)client;
|
||||
size_t currentBytePosition = 0;
|
||||
char currentByte;
|
||||
do {
|
||||
switch (_parsingInformation.bufferState) {
|
||||
case AsyncMqttClientInternals::BufferState::NONE:
|
||||
currentByte = data[currentBytePosition++];
|
||||
_parsingInformation.packetType = currentByte >> 4;
|
||||
_parsingInformation.packetFlags = (currentByte << 4) >> 4;
|
||||
_parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::REMAINING_LENGTH;
|
||||
_lastServerActivity = millis();
|
||||
switch (_parsingInformation.packetType) {
|
||||
case AsyncMqttClientInternals::PacketType.CONNACK:
|
||||
_currentParsedPacket = new AsyncMqttClientInternals::ConnAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onConnAck, this, std::placeholders::_1, std::placeholders::_2));
|
||||
break;
|
||||
case AsyncMqttClientInternals::PacketType.PINGRESP:
|
||||
_currentParsedPacket = new AsyncMqttClientInternals::PingRespPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPingResp, this));
|
||||
break;
|
||||
case AsyncMqttClientInternals::PacketType.SUBACK:
|
||||
_currentParsedPacket = new AsyncMqttClientInternals::SubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onSubAck, this, std::placeholders::_1, std::placeholders::_2));
|
||||
break;
|
||||
case AsyncMqttClientInternals::PacketType.UNSUBACK:
|
||||
_currentParsedPacket = new AsyncMqttClientInternals::UnsubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onUnsubAck, this, std::placeholders::_1));
|
||||
break;
|
||||
case AsyncMqttClientInternals::PacketType.PUBLISH:
|
||||
_currentParsedPacket = new AsyncMqttClientInternals::PublishPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7, std::placeholders::_8, std::placeholders::_9), std::bind(&AsyncMqttClient::_onPublish, this, std::placeholders::_1, std::placeholders::_2));
|
||||
break;
|
||||
case AsyncMqttClientInternals::PacketType.PUBREL:
|
||||
_currentParsedPacket = new AsyncMqttClientInternals::PubRelPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubRel, this, std::placeholders::_1));
|
||||
break;
|
||||
case AsyncMqttClientInternals::PacketType.PUBACK:
|
||||
_currentParsedPacket = new AsyncMqttClientInternals::PubAckPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubAck, this, std::placeholders::_1));
|
||||
break;
|
||||
case AsyncMqttClientInternals::PacketType.PUBREC:
|
||||
_currentParsedPacket = new AsyncMqttClientInternals::PubRecPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubRec, this, std::placeholders::_1));
|
||||
break;
|
||||
case AsyncMqttClientInternals::PacketType.PUBCOMP:
|
||||
_currentParsedPacket = new AsyncMqttClientInternals::PubCompPacket(&_parsingInformation, std::bind(&AsyncMqttClient::_onPubComp, this, std::placeholders::_1));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case AsyncMqttClientInternals::BufferState::REMAINING_LENGTH:
|
||||
currentByte = data[currentBytePosition++];
|
||||
_remainingLengthBuffer[_remainingLengthBufferPosition++] = currentByte;
|
||||
if (currentByte >> 7 == 0) {
|
||||
_parsingInformation.remainingLength = AsyncMqttClientInternals::Helpers::decodeRemainingLength(_remainingLengthBuffer);
|
||||
_remainingLengthBufferPosition = 0;
|
||||
if (_parsingInformation.remainingLength > 0) {
|
||||
_parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::VARIABLE_HEADER;
|
||||
} else {
|
||||
// PINGRESP is a special case where it has no variable header, so the packet ends right here
|
||||
_parsingInformation.bufferState = AsyncMqttClientInternals::BufferState::NONE;
|
||||
_onPingResp();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AsyncMqttClientInternals::BufferState::VARIABLE_HEADER:
|
||||
_currentParsedPacket->parseVariableHeader(data, len, ¤tBytePosition);
|
||||
break;
|
||||
case AsyncMqttClientInternals::BufferState::PAYLOAD:
|
||||
_currentParsedPacket->parsePayload(data, len, ¤tBytePosition);
|
||||
break;
|
||||
default:
|
||||
currentBytePosition = len;
|
||||
}
|
||||
} while (currentBytePosition != len);
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onPoll(AsyncClient* client) {
|
||||
if (!_connected) return;
|
||||
|
||||
// if there is too much time the client has sent a ping request without a response, disconnect client to avoid half open connections
|
||||
if (_lastPingRequestTime != 0 && (millis() - _lastPingRequestTime) >= (_keepAlive * 1000 * 2)) {
|
||||
disconnect();
|
||||
return;
|
||||
// send ping to ensure the server will receive at least one message inside keepalive window
|
||||
} else if (_lastPingRequestTime == 0 && (millis() - _lastClientActivity) >= (_keepAlive * 1000 * 0.7)) {
|
||||
_sendPing();
|
||||
|
||||
// send ping to verify if the server is still there (ensure this is not a half connection)
|
||||
} else if (_connected && _lastPingRequestTime == 0 && (millis() - _lastServerActivity) >= (_keepAlive * 1000 * 0.7)) {
|
||||
_sendPing();
|
||||
}
|
||||
|
||||
// handle to send ack packets
|
||||
|
||||
_sendAcks();
|
||||
|
||||
// handle disconnect
|
||||
|
||||
if (_disconnectFlagged) {
|
||||
_sendDisconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/* MQTT */
|
||||
void AsyncMqttClient::_onPingResp() {
|
||||
_freeCurrentParsedPacket();
|
||||
_lastPingRequestTime = 0;
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onConnAck(bool sessionPresent, uint8_t connectReturnCode) {
|
||||
(void)sessionPresent;
|
||||
_freeCurrentParsedPacket();
|
||||
|
||||
if (connectReturnCode == 0) {
|
||||
_connected = true;
|
||||
for (auto callback : _onConnectUserCallbacks) callback(sessionPresent);
|
||||
} else {
|
||||
for (auto callback : _onDisconnectUserCallbacks) callback(static_cast<AsyncMqttClientDisconnectReason>(connectReturnCode));
|
||||
_disconnectFlagged = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onSubAck(uint16_t packetId, char status) {
|
||||
_freeCurrentParsedPacket();
|
||||
|
||||
for (auto callback : _onSubscribeUserCallbacks) callback(packetId, status);
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onUnsubAck(uint16_t packetId) {
|
||||
_freeCurrentParsedPacket();
|
||||
|
||||
for (auto callback : _onUnsubscribeUserCallbacks) callback(packetId);
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onMessage(char* topic, char* payload, uint8_t qos, bool dup, bool retain, size_t len, size_t index, size_t total, uint16_t packetId) {
|
||||
bool notifyPublish = true;
|
||||
|
||||
if (qos == 2) {
|
||||
for (AsyncMqttClientInternals::PendingPubRel pendingPubRel : _pendingPubRels) {
|
||||
if (pendingPubRel.packetId == packetId) {
|
||||
notifyPublish = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (notifyPublish) {
|
||||
AsyncMqttClientMessageProperties properties;
|
||||
properties.qos = qos;
|
||||
properties.dup = dup;
|
||||
properties.retain = retain;
|
||||
|
||||
for (auto callback : _onMessageUserCallbacks) callback(topic, payload, properties, len, index, total);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onPublish(uint16_t packetId, uint8_t qos) {
|
||||
AsyncMqttClientInternals::PendingAck pendingAck;
|
||||
|
||||
if (qos == 1) {
|
||||
pendingAck.packetType = AsyncMqttClientInternals::PacketType.PUBACK;
|
||||
pendingAck.headerFlag = AsyncMqttClientInternals::HeaderFlag.PUBACK_RESERVED;
|
||||
pendingAck.packetId = packetId;
|
||||
_toSendAcks.push_back(pendingAck);
|
||||
} else if (qos == 2) {
|
||||
pendingAck.packetType = AsyncMqttClientInternals::PacketType.PUBREC;
|
||||
pendingAck.headerFlag = AsyncMqttClientInternals::HeaderFlag.PUBREC_RESERVED;
|
||||
pendingAck.packetId = packetId;
|
||||
_toSendAcks.push_back(pendingAck);
|
||||
|
||||
bool pubRelAwaiting = false;
|
||||
for (AsyncMqttClientInternals::PendingPubRel pendingPubRel : _pendingPubRels) {
|
||||
if (pendingPubRel.packetId == packetId) {
|
||||
pubRelAwaiting = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pubRelAwaiting) {
|
||||
AsyncMqttClientInternals::PendingPubRel pendingPubRel;
|
||||
pendingPubRel.packetId = packetId;
|
||||
_pendingPubRels.push_back(pendingPubRel);
|
||||
}
|
||||
|
||||
_sendAcks();
|
||||
}
|
||||
|
||||
_freeCurrentParsedPacket();
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onPubRel(uint16_t packetId) {
|
||||
_freeCurrentParsedPacket();
|
||||
|
||||
AsyncMqttClientInternals::PendingAck pendingAck;
|
||||
pendingAck.packetType = AsyncMqttClientInternals::PacketType.PUBCOMP;
|
||||
pendingAck.headerFlag = AsyncMqttClientInternals::HeaderFlag.PUBCOMP_RESERVED;
|
||||
pendingAck.packetId = packetId;
|
||||
_toSendAcks.push_back(pendingAck);
|
||||
|
||||
for (size_t i = 0; i < _pendingPubRels.size(); i++) {
|
||||
if (_pendingPubRels[i].packetId == packetId) {
|
||||
_pendingPubRels.erase(_pendingPubRels.begin() + i);
|
||||
_pendingPubRels.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
||||
_sendAcks();
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onPubAck(uint16_t packetId) {
|
||||
_freeCurrentParsedPacket();
|
||||
|
||||
for (auto callback : _onPublishUserCallbacks) callback(packetId);
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onPubRec(uint16_t packetId) {
|
||||
_freeCurrentParsedPacket();
|
||||
|
||||
AsyncMqttClientInternals::PendingAck pendingAck;
|
||||
pendingAck.packetType = AsyncMqttClientInternals::PacketType.PUBREL;
|
||||
pendingAck.headerFlag = AsyncMqttClientInternals::HeaderFlag.PUBREL_RESERVED;
|
||||
pendingAck.packetId = packetId;
|
||||
_toSendAcks.push_back(pendingAck);
|
||||
|
||||
_sendAcks();
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_onPubComp(uint16_t packetId) {
|
||||
_freeCurrentParsedPacket();
|
||||
|
||||
for (auto callback : _onPublishUserCallbacks) callback(packetId);
|
||||
}
|
||||
|
||||
bool AsyncMqttClient::_sendPing() {
|
||||
char fixedHeader[2];
|
||||
fixedHeader[0] = AsyncMqttClientInternals::PacketType.PINGREQ;
|
||||
fixedHeader[0] = fixedHeader[0] << 4;
|
||||
fixedHeader[0] = fixedHeader[0] | AsyncMqttClientInternals::HeaderFlag.PINGREQ_RESERVED;
|
||||
fixedHeader[1] = 0;
|
||||
|
||||
size_t neededSpace = 2;
|
||||
|
||||
SEMAPHORE_TAKE(false);
|
||||
if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return false; }
|
||||
|
||||
_client.add(fixedHeader, 2);
|
||||
_client.send();
|
||||
_lastClientActivity = millis();
|
||||
_lastPingRequestTime = millis();
|
||||
|
||||
SEMAPHORE_GIVE();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AsyncMqttClient::_sendAcks() {
|
||||
uint8_t neededAckSpace = 2 + 2;
|
||||
|
||||
SEMAPHORE_TAKE();
|
||||
for (size_t i = 0; i < _toSendAcks.size(); i++) {
|
||||
if (_client.space() < neededAckSpace) break;
|
||||
|
||||
AsyncMqttClientInternals::PendingAck pendingAck = _toSendAcks[i];
|
||||
|
||||
char fixedHeader[2];
|
||||
fixedHeader[0] = pendingAck.packetType;
|
||||
fixedHeader[0] = fixedHeader[0] << 4;
|
||||
fixedHeader[0] = fixedHeader[0] | pendingAck.headerFlag;
|
||||
fixedHeader[1] = 2;
|
||||
|
||||
char packetIdBytes[2];
|
||||
packetIdBytes[0] = pendingAck.packetId >> 8;
|
||||
packetIdBytes[1] = pendingAck.packetId & 0xFF;
|
||||
|
||||
_client.add(fixedHeader, 2);
|
||||
_client.add(packetIdBytes, 2);
|
||||
_client.send();
|
||||
|
||||
_toSendAcks.erase(_toSendAcks.begin() + i);
|
||||
_toSendAcks.shrink_to_fit();
|
||||
|
||||
_lastClientActivity = millis();
|
||||
}
|
||||
SEMAPHORE_GIVE();
|
||||
}
|
||||
|
||||
bool AsyncMqttClient::_sendDisconnect() {
|
||||
if (!_connected) return true;
|
||||
|
||||
const uint8_t neededSpace = 2;
|
||||
|
||||
SEMAPHORE_TAKE(false);
|
||||
|
||||
if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return false; }
|
||||
|
||||
char fixedHeader[2];
|
||||
fixedHeader[0] = AsyncMqttClientInternals::PacketType.DISCONNECT;
|
||||
fixedHeader[0] = fixedHeader[0] << 4;
|
||||
fixedHeader[0] = fixedHeader[0] | AsyncMqttClientInternals::HeaderFlag.DISCONNECT_RESERVED;
|
||||
fixedHeader[1] = 0;
|
||||
|
||||
_client.add(fixedHeader, 2);
|
||||
_client.send();
|
||||
_client.close(true);
|
||||
|
||||
_disconnectFlagged = false;
|
||||
|
||||
SEMAPHORE_GIVE();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t AsyncMqttClient::_getNextPacketId() {
|
||||
uint16_t nextPacketId = _nextPacketId;
|
||||
|
||||
if (_nextPacketId == 65535) _nextPacketId = 0; // 0 is forbidden
|
||||
_nextPacketId++;
|
||||
|
||||
return nextPacketId;
|
||||
}
|
||||
|
||||
bool AsyncMqttClient::connected() const {
|
||||
return _connected;
|
||||
}
|
||||
|
||||
void AsyncMqttClient::connect() {
|
||||
if (_connected) return;
|
||||
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
if (_useIp) {
|
||||
_client.connect(_ip, _port, _secure);
|
||||
} else {
|
||||
_client.connect(_host, _port, _secure);
|
||||
}
|
||||
#else
|
||||
if (_useIp) {
|
||||
_client.connect(_ip, _port);
|
||||
} else {
|
||||
_client.connect(_host, _port);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AsyncMqttClient::disconnect(bool force) {
|
||||
if (!_connected) return;
|
||||
|
||||
if (force) {
|
||||
_client.close(true);
|
||||
} else {
|
||||
_disconnectFlagged = true;
|
||||
_sendDisconnect();
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t AsyncMqttClient::subscribe(const char* topic, uint8_t qos) {
|
||||
if (!_connected) return 0;
|
||||
|
||||
char fixedHeader[5];
|
||||
fixedHeader[0] = AsyncMqttClientInternals::PacketType.SUBSCRIBE;
|
||||
fixedHeader[0] = fixedHeader[0] << 4;
|
||||
fixedHeader[0] = fixedHeader[0] | AsyncMqttClientInternals::HeaderFlag.SUBSCRIBE_RESERVED;
|
||||
|
||||
uint16_t topicLength = strlen(topic);
|
||||
char topicLengthBytes[2];
|
||||
topicLengthBytes[0] = topicLength >> 8;
|
||||
topicLengthBytes[1] = topicLength & 0xFF;
|
||||
|
||||
char qosByte[1];
|
||||
qosByte[0] = qos;
|
||||
|
||||
uint8_t remainingLengthLength = AsyncMqttClientInternals::Helpers::encodeRemainingLength(2 + 2 + topicLength + 1, fixedHeader + 1);
|
||||
|
||||
size_t neededSpace = 0;
|
||||
neededSpace += 1 + remainingLengthLength;
|
||||
neededSpace += 2;
|
||||
neededSpace += 2;
|
||||
neededSpace += topicLength;
|
||||
neededSpace += 1;
|
||||
|
||||
SEMAPHORE_TAKE(0);
|
||||
if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return 0; }
|
||||
|
||||
uint16_t packetId = _getNextPacketId();
|
||||
char packetIdBytes[2];
|
||||
packetIdBytes[0] = packetId >> 8;
|
||||
packetIdBytes[1] = packetId & 0xFF;
|
||||
|
||||
_client.add(fixedHeader, 1 + remainingLengthLength);
|
||||
_client.add(packetIdBytes, 2);
|
||||
_client.add(topicLengthBytes, 2);
|
||||
_client.add(topic, topicLength);
|
||||
_client.add(qosByte, 1);
|
||||
_client.send();
|
||||
_lastClientActivity = millis();
|
||||
|
||||
SEMAPHORE_GIVE();
|
||||
return packetId;
|
||||
}
|
||||
|
||||
uint16_t AsyncMqttClient::unsubscribe(const char* topic) {
|
||||
if (!_connected) return 0;
|
||||
|
||||
char fixedHeader[5];
|
||||
fixedHeader[0] = AsyncMqttClientInternals::PacketType.UNSUBSCRIBE;
|
||||
fixedHeader[0] = fixedHeader[0] << 4;
|
||||
fixedHeader[0] = fixedHeader[0] | AsyncMqttClientInternals::HeaderFlag.UNSUBSCRIBE_RESERVED;
|
||||
|
||||
uint16_t topicLength = strlen(topic);
|
||||
char topicLengthBytes[2];
|
||||
topicLengthBytes[0] = topicLength >> 8;
|
||||
topicLengthBytes[1] = topicLength & 0xFF;
|
||||
|
||||
uint8_t remainingLengthLength = AsyncMqttClientInternals::Helpers::encodeRemainingLength(2 + 2 + topicLength, fixedHeader + 1);
|
||||
|
||||
size_t neededSpace = 0;
|
||||
neededSpace += 1 + remainingLengthLength;
|
||||
neededSpace += 2;
|
||||
neededSpace += 2;
|
||||
neededSpace += topicLength;
|
||||
|
||||
SEMAPHORE_TAKE(0);
|
||||
if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return 0; }
|
||||
|
||||
uint16_t packetId = _getNextPacketId();
|
||||
char packetIdBytes[2];
|
||||
packetIdBytes[0] = packetId >> 8;
|
||||
packetIdBytes[1] = packetId & 0xFF;
|
||||
|
||||
_client.add(fixedHeader, 1 + remainingLengthLength);
|
||||
_client.add(packetIdBytes, 2);
|
||||
_client.add(topicLengthBytes, 2);
|
||||
_client.add(topic, topicLength);
|
||||
_client.send();
|
||||
_lastClientActivity = millis();
|
||||
|
||||
SEMAPHORE_GIVE();
|
||||
return packetId;
|
||||
}
|
||||
|
||||
uint16_t AsyncMqttClient::publish(const char* topic, uint8_t qos, bool retain, const char* payload, size_t length, bool dup, uint16_t message_id) {
|
||||
if (!_connected) return 0;
|
||||
|
||||
char fixedHeader[5];
|
||||
fixedHeader[0] = AsyncMqttClientInternals::PacketType.PUBLISH;
|
||||
fixedHeader[0] = fixedHeader[0] << 4;
|
||||
if (dup) fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_DUP;
|
||||
if (retain) fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_RETAIN;
|
||||
switch (qos) {
|
||||
case 0:
|
||||
fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS0;
|
||||
break;
|
||||
case 1:
|
||||
fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS1;
|
||||
break;
|
||||
case 2:
|
||||
fixedHeader[0] |= AsyncMqttClientInternals::HeaderFlag.PUBLISH_QOS2;
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t topicLength = strlen(topic);
|
||||
char topicLengthBytes[2];
|
||||
topicLengthBytes[0] = topicLength >> 8;
|
||||
topicLengthBytes[1] = topicLength & 0xFF;
|
||||
|
||||
uint32_t payloadLength = length;
|
||||
if (payload != nullptr && payloadLength == 0) payloadLength = strlen(payload);
|
||||
|
||||
uint32_t remainingLength = 2 + topicLength + payloadLength;
|
||||
if (qos != 0) remainingLength += 2;
|
||||
uint8_t remainingLengthLength = AsyncMqttClientInternals::Helpers::encodeRemainingLength(remainingLength, fixedHeader + 1);
|
||||
|
||||
size_t neededSpace = 0;
|
||||
neededSpace += 1 + remainingLengthLength;
|
||||
neededSpace += 2;
|
||||
neededSpace += topicLength;
|
||||
if (qos != 0) neededSpace += 2;
|
||||
if (payload != nullptr) neededSpace += payloadLength;
|
||||
|
||||
SEMAPHORE_TAKE(0);
|
||||
if (_client.space() < neededSpace) { SEMAPHORE_GIVE(); return 0; }
|
||||
|
||||
uint16_t packetId = 0;
|
||||
char packetIdBytes[2];
|
||||
if (qos != 0) {
|
||||
if (dup && message_id > 0) {
|
||||
packetId = message_id;
|
||||
} else {
|
||||
packetId = _getNextPacketId();
|
||||
}
|
||||
|
||||
packetIdBytes[0] = packetId >> 8;
|
||||
packetIdBytes[1] = packetId & 0xFF;
|
||||
}
|
||||
|
||||
_client.add(fixedHeader, 1 + remainingLengthLength);
|
||||
_client.add(topicLengthBytes, 2);
|
||||
_client.add(topic, topicLength);
|
||||
if (qos != 0) _client.add(packetIdBytes, 2);
|
||||
if (payload != nullptr) _client.add(payload, payloadLength);
|
||||
_client.send();
|
||||
_lastClientActivity = millis();
|
||||
|
||||
SEMAPHORE_GIVE();
|
||||
if (qos != 0) {
|
||||
return packetId;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef SRC_ASYNCMQTTCLIENT_H_
|
||||
#define SRC_ASYNCMQTTCLIENT_H_
|
||||
|
||||
#include "AsyncMqttClient.hpp"
|
||||
|
||||
#endif // SRC_ASYNCMQTTCLIENT_H_
|
||||
166
wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp
Normal file
166
wled00/src/dependencies/async-mqtt-client/AsyncMqttClient.hpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef ESP32
|
||||
#include <AsyncTCP.h>
|
||||
#include <freertos/semphr.h>
|
||||
#elif defined(ESP8266)
|
||||
#include <ESPAsyncTCP.h>
|
||||
#else
|
||||
#error Platform not supported
|
||||
#endif
|
||||
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
#include <tcp_axtls.h>
|
||||
#define SHA1_SIZE 20
|
||||
#endif
|
||||
|
||||
#include "AsyncMqttClient/Flags.hpp"
|
||||
#include "AsyncMqttClient/ParsingInformation.hpp"
|
||||
#include "AsyncMqttClient/MessageProperties.hpp"
|
||||
#include "AsyncMqttClient/Helpers.hpp"
|
||||
#include "AsyncMqttClient/Callbacks.hpp"
|
||||
#include "AsyncMqttClient/DisconnectReasons.hpp"
|
||||
#include "AsyncMqttClient/Storage.hpp"
|
||||
|
||||
#include "AsyncMqttClient/Packets/Packet.hpp"
|
||||
#include "AsyncMqttClient/Packets/ConnAckPacket.hpp"
|
||||
#include "AsyncMqttClient/Packets/PingRespPacket.hpp"
|
||||
#include "AsyncMqttClient/Packets/SubAckPacket.hpp"
|
||||
#include "AsyncMqttClient/Packets/UnsubAckPacket.hpp"
|
||||
#include "AsyncMqttClient/Packets/PublishPacket.hpp"
|
||||
#include "AsyncMqttClient/Packets/PubRelPacket.hpp"
|
||||
#include "AsyncMqttClient/Packets/PubAckPacket.hpp"
|
||||
#include "AsyncMqttClient/Packets/PubRecPacket.hpp"
|
||||
#include "AsyncMqttClient/Packets/PubCompPacket.hpp"
|
||||
|
||||
#if ESP32
|
||||
#define SEMAPHORE_TAKE(X) if (xSemaphoreTake(_xSemaphore, 1000 / portTICK_PERIOD_MS) != pdTRUE) { return X; } // Waits max 1000ms
|
||||
#define SEMAPHORE_GIVE() xSemaphoreGive(_xSemaphore);
|
||||
#elif defined(ESP8266)
|
||||
#define SEMAPHORE_TAKE(X) void()
|
||||
#define SEMAPHORE_GIVE() void()
|
||||
#endif
|
||||
|
||||
class AsyncMqttClient {
|
||||
public:
|
||||
AsyncMqttClient();
|
||||
~AsyncMqttClient();
|
||||
|
||||
AsyncMqttClient& setKeepAlive(uint16_t keepAlive);
|
||||
AsyncMqttClient& setClientId(const char* clientId);
|
||||
AsyncMqttClient& setCleanSession(bool cleanSession);
|
||||
AsyncMqttClient& setMaxTopicLength(uint16_t maxTopicLength);
|
||||
AsyncMqttClient& setCredentials(const char* username, const char* password = nullptr);
|
||||
AsyncMqttClient& setWill(const char* topic, uint8_t qos, bool retain, const char* payload = nullptr, size_t length = 0);
|
||||
AsyncMqttClient& setServer(IPAddress ip, uint16_t port);
|
||||
AsyncMqttClient& setServer(const char* host, uint16_t port);
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
AsyncMqttClient& setSecure(bool secure);
|
||||
AsyncMqttClient& addServerFingerprint(const uint8_t* fingerprint);
|
||||
#endif
|
||||
|
||||
AsyncMqttClient& onConnect(AsyncMqttClientInternals::OnConnectUserCallback callback);
|
||||
AsyncMqttClient& onDisconnect(AsyncMqttClientInternals::OnDisconnectUserCallback callback);
|
||||
AsyncMqttClient& onSubscribe(AsyncMqttClientInternals::OnSubscribeUserCallback callback);
|
||||
AsyncMqttClient& onUnsubscribe(AsyncMqttClientInternals::OnUnsubscribeUserCallback callback);
|
||||
AsyncMqttClient& onMessage(AsyncMqttClientInternals::OnMessageUserCallback callback);
|
||||
AsyncMqttClient& onPublish(AsyncMqttClientInternals::OnPublishUserCallback callback);
|
||||
|
||||
bool connected() const;
|
||||
void connect();
|
||||
void disconnect(bool force = false);
|
||||
uint16_t subscribe(const char* topic, uint8_t qos);
|
||||
uint16_t unsubscribe(const char* topic);
|
||||
uint16_t publish(const char* topic, uint8_t qos, bool retain, const char* payload = nullptr, size_t length = 0, bool dup = false, uint16_t message_id = 0);
|
||||
|
||||
private:
|
||||
AsyncClient _client;
|
||||
|
||||
bool _connected;
|
||||
bool _connectPacketNotEnoughSpace;
|
||||
bool _disconnectFlagged;
|
||||
bool _tlsBadFingerprint;
|
||||
uint32_t _lastClientActivity;
|
||||
uint32_t _lastServerActivity;
|
||||
uint32_t _lastPingRequestTime;
|
||||
|
||||
char _generatedClientId[13 + 1]; // esp8266abc123
|
||||
IPAddress _ip;
|
||||
const char* _host;
|
||||
bool _useIp;
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
bool _secure;
|
||||
#endif
|
||||
uint16_t _port;
|
||||
uint16_t _keepAlive;
|
||||
bool _cleanSession;
|
||||
const char* _clientId;
|
||||
const char* _username;
|
||||
const char* _password;
|
||||
const char* _willTopic;
|
||||
const char* _willPayload;
|
||||
uint16_t _willPayloadLength;
|
||||
uint8_t _willQos;
|
||||
bool _willRetain;
|
||||
|
||||
#if ASYNC_TCP_SSL_ENABLED
|
||||
std::vector<std::array<uint8_t, SHA1_SIZE>> _secureServerFingerprints;
|
||||
#endif
|
||||
|
||||
std::vector<AsyncMqttClientInternals::OnConnectUserCallback> _onConnectUserCallbacks;
|
||||
std::vector<AsyncMqttClientInternals::OnDisconnectUserCallback> _onDisconnectUserCallbacks;
|
||||
std::vector<AsyncMqttClientInternals::OnSubscribeUserCallback> _onSubscribeUserCallbacks;
|
||||
std::vector<AsyncMqttClientInternals::OnUnsubscribeUserCallback> _onUnsubscribeUserCallbacks;
|
||||
std::vector<AsyncMqttClientInternals::OnMessageUserCallback> _onMessageUserCallbacks;
|
||||
std::vector<AsyncMqttClientInternals::OnPublishUserCallback> _onPublishUserCallbacks;
|
||||
|
||||
AsyncMqttClientInternals::ParsingInformation _parsingInformation;
|
||||
AsyncMqttClientInternals::Packet* _currentParsedPacket;
|
||||
uint8_t _remainingLengthBufferPosition;
|
||||
char _remainingLengthBuffer[4];
|
||||
|
||||
uint16_t _nextPacketId;
|
||||
|
||||
std::vector<AsyncMqttClientInternals::PendingPubRel> _pendingPubRels;
|
||||
|
||||
std::vector<AsyncMqttClientInternals::PendingAck> _toSendAcks;
|
||||
|
||||
#ifdef ESP32
|
||||
SemaphoreHandle_t _xSemaphore = nullptr;
|
||||
#endif
|
||||
|
||||
void _clear();
|
||||
void _freeCurrentParsedPacket();
|
||||
|
||||
// TCP
|
||||
void _onConnect(AsyncClient* client);
|
||||
void _onDisconnect(AsyncClient* client);
|
||||
static void _onError(AsyncClient* client, int8_t error);
|
||||
void _onTimeout(AsyncClient* client, uint32_t time);
|
||||
static void _onAck(AsyncClient* client, size_t len, uint32_t time);
|
||||
void _onData(AsyncClient* client, char* data, size_t len);
|
||||
void _onPoll(AsyncClient* client);
|
||||
|
||||
// MQTT
|
||||
void _onPingResp();
|
||||
void _onConnAck(bool sessionPresent, uint8_t connectReturnCode);
|
||||
void _onSubAck(uint16_t packetId, char status);
|
||||
void _onUnsubAck(uint16_t packetId);
|
||||
void _onMessage(char* topic, char* payload, uint8_t qos, bool dup, bool retain, size_t len, size_t index, size_t total, uint16_t packetId);
|
||||
void _onPublish(uint16_t packetId, uint8_t qos);
|
||||
void _onPubRel(uint16_t packetId);
|
||||
void _onPubAck(uint16_t packetId);
|
||||
void _onPubRec(uint16_t packetId);
|
||||
void _onPubComp(uint16_t packetId);
|
||||
|
||||
bool _sendPing();
|
||||
void _sendAcks();
|
||||
bool _sendDisconnect();
|
||||
|
||||
uint16_t _getNextPacketId();
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "DisconnectReasons.hpp"
|
||||
#include "MessageProperties.hpp"
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
// user callbacks
|
||||
typedef std::function<void(bool sessionPresent)> OnConnectUserCallback;
|
||||
typedef std::function<void(AsyncMqttClientDisconnectReason reason)> OnDisconnectUserCallback;
|
||||
typedef std::function<void(uint16_t packetId, uint8_t qos)> OnSubscribeUserCallback;
|
||||
typedef std::function<void(uint16_t packetId)> OnUnsubscribeUserCallback;
|
||||
typedef std::function<void(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)> OnMessageUserCallback;
|
||||
typedef std::function<void(uint16_t packetId)> OnPublishUserCallback;
|
||||
|
||||
// internal callbacks
|
||||
typedef std::function<void(bool sessionPresent, uint8_t connectReturnCode)> OnConnAckInternalCallback;
|
||||
typedef std::function<void()> OnPingRespInternalCallback;
|
||||
typedef std::function<void(uint16_t packetId, char status)> OnSubAckInternalCallback;
|
||||
typedef std::function<void(uint16_t packetId)> OnUnsubAckInternalCallback;
|
||||
typedef std::function<void(char* topic, char* payload, uint8_t qos, bool dup, bool retain, size_t len, size_t index, size_t total, uint16_t packetId)> OnMessageInternalCallback;
|
||||
typedef std::function<void(uint16_t packetId, uint8_t qos)> OnPublishInternalCallback;
|
||||
typedef std::function<void(uint16_t packetId)> OnPubRelInternalCallback;
|
||||
typedef std::function<void(uint16_t packetId)> OnPubAckInternalCallback;
|
||||
typedef std::function<void(uint16_t packetId)> OnPubRecInternalCallback;
|
||||
typedef std::function<void(uint16_t packetId)> OnPubCompInternalCallback;
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
enum class AsyncMqttClientDisconnectReason : int8_t {
|
||||
TCP_DISCONNECTED = 0,
|
||||
|
||||
MQTT_UNACCEPTABLE_PROTOCOL_VERSION = 1,
|
||||
MQTT_IDENTIFIER_REJECTED = 2,
|
||||
MQTT_SERVER_UNAVAILABLE = 3,
|
||||
MQTT_MALFORMED_CREDENTIALS = 4,
|
||||
MQTT_NOT_AUTHORIZED = 5,
|
||||
|
||||
ESP8266_NOT_ENOUGH_SPACE = 6,
|
||||
|
||||
TLS_BAD_FINGERPRINT = 7
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
constexpr struct {
|
||||
const uint8_t RESERVED = 0;
|
||||
const uint8_t CONNECT = 1;
|
||||
const uint8_t CONNACK = 2;
|
||||
const uint8_t PUBLISH = 3;
|
||||
const uint8_t PUBACK = 4;
|
||||
const uint8_t PUBREC = 5;
|
||||
const uint8_t PUBREL = 6;
|
||||
const uint8_t PUBCOMP = 7;
|
||||
const uint8_t SUBSCRIBE = 8;
|
||||
const uint8_t SUBACK = 9;
|
||||
const uint8_t UNSUBSCRIBE = 10;
|
||||
const uint8_t UNSUBACK = 11;
|
||||
const uint8_t PINGREQ = 12;
|
||||
const uint8_t PINGRESP = 13;
|
||||
const uint8_t DISCONNECT = 14;
|
||||
const uint8_t RESERVED2 = 1;
|
||||
} PacketType;
|
||||
|
||||
constexpr struct {
|
||||
const uint8_t CONNECT_RESERVED = 0x00;
|
||||
const uint8_t CONNACK_RESERVED = 0x00;
|
||||
const uint8_t PUBLISH_DUP = 0x08;
|
||||
const uint8_t PUBLISH_QOS0 = 0x00;
|
||||
const uint8_t PUBLISH_QOS1 = 0x02;
|
||||
const uint8_t PUBLISH_QOS2 = 0x04;
|
||||
const uint8_t PUBLISH_QOSRESERVED = 0x06;
|
||||
const uint8_t PUBLISH_RETAIN = 0x01;
|
||||
const uint8_t PUBACK_RESERVED = 0x00;
|
||||
const uint8_t PUBREC_RESERVED = 0x00;
|
||||
const uint8_t PUBREL_RESERVED = 0x02;
|
||||
const uint8_t PUBCOMP_RESERVED = 0x00;
|
||||
const uint8_t SUBSCRIBE_RESERVED = 0x02;
|
||||
const uint8_t SUBACK_RESERVED = 0x00;
|
||||
const uint8_t UNSUBSCRIBE_RESERVED = 0x02;
|
||||
const uint8_t UNSUBACK_RESERVED = 0x00;
|
||||
const uint8_t PINGREQ_RESERVED = 0x00;
|
||||
const uint8_t PINGRESP_RESERVED = 0x00;
|
||||
const uint8_t DISCONNECT_RESERVED = 0x00;
|
||||
const uint8_t RESERVED2_RESERVED = 0x00;
|
||||
} HeaderFlag;
|
||||
|
||||
constexpr struct {
|
||||
const uint8_t USERNAME = 0x80;
|
||||
const uint8_t PASSWORD = 0x40;
|
||||
const uint8_t WILL_RETAIN = 0x20;
|
||||
const uint8_t WILL_QOS0 = 0x00;
|
||||
const uint8_t WILL_QOS1 = 0x08;
|
||||
const uint8_t WILL_QOS2 = 0x10;
|
||||
const uint8_t WILL = 0x04;
|
||||
const uint8_t CLEAN_SESSION = 0x02;
|
||||
const uint8_t RESERVED = 0x00;
|
||||
} ConnectFlag;
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
class Helpers {
|
||||
public:
|
||||
static uint32_t decodeRemainingLength(char* bytes) {
|
||||
uint32_t multiplier = 1;
|
||||
uint32_t value = 0;
|
||||
uint8_t currentByte = 0;
|
||||
uint8_t encodedByte;
|
||||
do {
|
||||
encodedByte = bytes[currentByte++];
|
||||
value += (encodedByte & 127) * multiplier;
|
||||
multiplier *= 128;
|
||||
} while ((encodedByte & 128) != 0);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint8_t encodeRemainingLength(uint32_t remainingLength, char* destination) {
|
||||
uint8_t currentByte = 0;
|
||||
uint8_t bytesNeeded = 0;
|
||||
|
||||
do {
|
||||
uint8_t encodedByte = remainingLength % 128;
|
||||
remainingLength /= 128;
|
||||
if (remainingLength > 0) {
|
||||
encodedByte = encodedByte | 128;
|
||||
}
|
||||
|
||||
destination[currentByte++] = encodedByte;
|
||||
bytesNeeded++;
|
||||
} while (remainingLength > 0);
|
||||
|
||||
return bytesNeeded;
|
||||
}
|
||||
};
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
struct AsyncMqttClientMessageProperties {
|
||||
uint8_t qos;
|
||||
bool dup;
|
||||
bool retain;
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "ConnAckPacket.hpp"
|
||||
|
||||
using AsyncMqttClientInternals::ConnAckPacket;
|
||||
|
||||
ConnAckPacket::ConnAckPacket(ParsingInformation* parsingInformation, OnConnAckInternalCallback callback)
|
||||
: _parsingInformation(parsingInformation)
|
||||
, _callback(callback)
|
||||
, _bytePosition(0)
|
||||
, _sessionPresent(false)
|
||||
, _connectReturnCode(0) {
|
||||
}
|
||||
|
||||
ConnAckPacket::~ConnAckPacket() {
|
||||
}
|
||||
|
||||
void ConnAckPacket::parseVariableHeader(char* data, size_t len, size_t* currentBytePosition) {
|
||||
char currentByte = data[(*currentBytePosition)++];
|
||||
if (_bytePosition++ == 0) {
|
||||
_sessionPresent = (currentByte << 7) >> 7;
|
||||
} else {
|
||||
_connectReturnCode = currentByte;
|
||||
_parsingInformation->bufferState = BufferState::NONE;
|
||||
_callback(_sessionPresent, _connectReturnCode);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnAckPacket::parsePayload(char* data, size_t len, size_t* currentBytePosition) {
|
||||
(void)data;
|
||||
(void)currentBytePosition;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Packet.hpp"
|
||||
#include "../ParsingInformation.hpp"
|
||||
#include "../Callbacks.hpp"
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
class ConnAckPacket : public Packet {
|
||||
public:
|
||||
explicit ConnAckPacket(ParsingInformation* parsingInformation, OnConnAckInternalCallback callback);
|
||||
~ConnAckPacket();
|
||||
|
||||
void parseVariableHeader(char* data, size_t len, size_t* currentBytePosition);
|
||||
void parsePayload(char* data, size_t len, size_t* currentBytePosition);
|
||||
|
||||
private:
|
||||
ParsingInformation* _parsingInformation;
|
||||
OnConnAckInternalCallback _callback;
|
||||
|
||||
uint8_t _bytePosition;
|
||||
bool _sessionPresent;
|
||||
uint8_t _connectReturnCode;
|
||||
};
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
namespace AsyncMqttClientInternals {
|
||||
class Packet {
|
||||
public:
|
||||
virtual ~Packet() {}
|
||||
|
||||
virtual void parseVariableHeader(char* data, size_t len, size_t* currentBytePosition) = 0;
|
||||
virtual void parsePayload(char* data, size_t len, size_t* currentBytePosition) = 0;
|
||||
};
|
||||
} // namespace AsyncMqttClientInternals
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "PingRespPacket.hpp"
|
||||
|
||||
using AsyncMqttClientInternals::PingRespPacket;
|
||||
|
||||
PingRespPacket::PingRespPacket(ParsingInformation* parsingInformation, OnPingRespInternalCallback callback)
|
||||
: _parsingInformation(parsingInformation)
|
||||
, _callback(callback) {
|
||||
}
|
||||
|
||||
PingRespPacket::~PingRespPacket() {
|
||||
}
|
||||
|
||||
void PingRespPacket::parseVariableHeader(char* data, size_t len, size_t* currentBytePosition) {
|
||||
(void)data;
|
||||
(void)currentBytePosition;
|
||||
}
|
||||
|
||||
void PingRespPacket::parsePayload(char* data, size_t len, size_t* currentBytePosition) {
|
||||
(void)data;
|
||||
(void)currentBytePosition;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user