mirror of
https://github.com/wled/WLED.git
synced 2025-10-23 18:58:54 +00:00
Compare commits
5498 Commits
v0.9.1
...
dnd-output
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a18b133942 | ||
|
|
00fab2e86d | ||
|
|
3bc728e068 | ||
|
|
7f1f986f13 | ||
|
|
91fdb5822b | ||
|
|
e4cabf8de6 | ||
|
|
f034601512 | ||
|
|
151a974607 | ||
|
|
9f583f16f8 | ||
|
|
4c4436f48c | ||
|
|
3562fa264e | ||
|
|
359d46c3e1 | ||
|
|
2b73a349dd | ||
|
|
d86ae7db40 | ||
|
|
f096320e63 | ||
|
|
e23751bd1d | ||
|
|
d5002cce25 | ||
|
|
daa833f33d | ||
|
|
7fe831c5e3 | ||
|
|
66069245a1 | ||
|
|
8b3975752c | ||
|
|
c6b4c77387 | ||
|
|
9152d9d2ed | ||
|
|
5a4a50415e | ||
|
|
640d0ee133 | ||
|
|
529edfc39b | ||
|
|
4b1b0fe045 | ||
|
|
4bfc9a9514 | ||
|
|
4d39dd0a5e | ||
|
|
15ba01a1c6 | ||
|
|
2593b11aba | ||
|
|
e7652e389f | ||
|
|
bd4a7e748d | ||
|
|
77f3426867 | ||
|
|
45615c07ee | ||
|
|
ee5a70a63e | ||
|
|
deac50409c | ||
|
|
c5119c8aa6 | ||
|
|
6c718c3558 | ||
|
|
75481d3251 | ||
|
|
7d6f47755c | ||
|
|
eb5d548ba7 | ||
|
|
3a7de8275f | ||
|
|
33d79e048c | ||
|
|
ed2b170e1b | ||
|
|
c73636d96d | ||
|
|
3410b785db | ||
|
|
762d4433d8 | ||
|
|
e69bf4eceb | ||
|
|
741fd8d9d3 | ||
|
|
684224c614 | ||
|
|
9826197083 | ||
|
|
2ba84b12f8 | ||
|
|
efeb791807 | ||
|
|
43e3578d50 | ||
|
|
b375c718b0 | ||
|
|
b16fbafd83 | ||
|
|
76cb2e9988 | ||
|
|
9d706010f5 | ||
|
|
97b20438fd | ||
|
|
65913f990d | ||
|
|
56d00357d3 | ||
|
|
1864e550e6 | ||
|
|
a79ae25621 | ||
|
|
05c481c5bb | ||
|
|
7ce0d69563 | ||
|
|
011e72c3c1 | ||
|
|
e44bdf6193 | ||
|
|
29dcdf8e85 | ||
|
|
e37d4cd8a8 | ||
|
|
46e60b4d0a | ||
|
|
75f6de9dc2 | ||
|
|
649d43b581 | ||
|
|
16cfbf7500 | ||
|
|
aecac2c56c | ||
|
|
385504e6db | ||
|
|
a0321170d0 | ||
|
|
d70018ae9f | ||
|
|
9359f0b7fc | ||
|
|
be74196a62 | ||
|
|
705f2035f4 | ||
|
|
65efcb351e | ||
|
|
72ad39d6a7 | ||
|
|
5950204d34 | ||
|
|
46df9410b3 | ||
|
|
b7e4cd0d9a | ||
|
|
0becd61323 | ||
|
|
3f2e92c4c5 | ||
|
|
666a59ff53 | ||
|
|
ce7ca3f2d2 | ||
|
|
87092ccb80 | ||
|
|
2e834852d5 | ||
|
|
3e9e18dae2 | ||
|
|
831b68e60b | ||
|
|
5e3803a5bb | ||
|
|
91d7e0c051 | ||
|
|
a037d99469 | ||
|
|
8cc5d64819 | ||
|
|
4c948cca13 | ||
|
|
5cb8dc3978 | ||
|
|
199bc45ae2 | ||
|
|
8fc87aa17d | ||
|
|
19a49e83d1 | ||
|
|
c8757d45c8 | ||
|
|
62fad4dcdf | ||
|
|
da7f107273 | ||
|
|
d5d7fde30f | ||
|
|
6f914d79b1 | ||
|
|
dd13c2df47 | ||
|
|
8aeb9e1abe | ||
|
|
cfad0b8a52 | ||
|
|
a60be251d2 | ||
|
|
f15c1fbca6 | ||
|
|
708baf1ed7 | ||
|
|
4155a6bc23 | ||
|
|
c92f0a9d90 | ||
|
|
5fa901c37c | ||
|
|
46f3bc0ced | ||
|
|
f8ce5980a1 | ||
|
|
4b5c3a396d | ||
|
|
550b4d9dea | ||
|
|
f3e3f585df | ||
|
|
2082b01a3c | ||
|
|
8baa6a4616 | ||
|
|
1fb9eb771e | ||
|
|
dee581f58d | ||
|
|
7943b00017 | ||
|
|
4de6656bc4 | ||
|
|
cd8ddb81e1 | ||
|
|
890860ebf6 | ||
|
|
624042d97e | ||
|
|
85d4db83ed | ||
|
|
5146926723 | ||
|
|
3b5c6ca284 | ||
|
|
dcc1fbc96e | ||
|
|
7865985eeb | ||
|
|
4ac7eb7eb2 | ||
|
|
7285efebca | ||
|
|
af2d46c30d | ||
|
|
f4d89c4196 | ||
|
|
c9c442a933 | ||
|
|
b8b59b2bb1 | ||
|
|
c33e303323 | ||
|
|
caf3c7a2f9 | ||
|
|
c8d8ab020e | ||
|
|
297d5ced75 | ||
|
|
3f90366aa8 | ||
|
|
e3653baf74 | ||
|
|
f74d1459b9 | ||
|
|
93e011d403 | ||
|
|
374d90629d | ||
|
|
bfe5cd52e7 | ||
|
|
e374c7ae55 | ||
|
|
9e4675ef46 | ||
|
|
b76ef231fc | ||
|
|
591dbe387c | ||
|
|
e5ba97bbe2 | ||
|
|
b79e81f3be | ||
|
|
ab5b6f9b7d | ||
|
|
4fd1b393a8 | ||
|
|
e2f5becdd0 | ||
|
|
71301ddc57 | ||
|
|
c30c7e1da5 | ||
|
|
806163f1ed | ||
|
|
ecc3eae247 | ||
|
|
07e303bcc1 | ||
|
|
24f2306129 | ||
|
|
79b3bc2573 | ||
|
|
5c74f0fa21 | ||
|
|
e7157e542a | ||
|
|
a24420ae70 | ||
|
|
b7bfd6fc67 | ||
|
|
8bcd4550f8 | ||
|
|
9569ec7ccf | ||
|
|
61990189de | ||
|
|
c0875b36bb | ||
|
|
929a5a8d80 | ||
|
|
731f140b88 | ||
|
|
127c700a99 | ||
|
|
a67a2cbf5c | ||
|
|
f9a6a3d36f | ||
|
|
9c38843747 | ||
|
|
3fc653bbff | ||
|
|
600603149e | ||
|
|
2b42049998 | ||
|
|
5f70fe57e3 | ||
|
|
a2fc1a4d88 | ||
|
|
beee4e9293 | ||
|
|
17f7b158fa | ||
|
|
697ef4bdb7 | ||
|
|
ce323bed7a | ||
|
|
db8b378ee0 | ||
|
|
85214f1f2b | ||
|
|
63c3d5c89d | ||
|
|
b43f85c305 | ||
|
|
f12840218e | ||
|
|
5f224fa5f9 | ||
|
|
263150aeb3 | ||
|
|
164f213094 | ||
|
|
06b4c05f73 | ||
|
|
38975dbfd4 | ||
|
|
a6ce136843 | ||
|
|
a678bd09e9 | ||
|
|
8215fefc2d | ||
|
|
86137a669e | ||
|
|
33650e3886 | ||
|
|
d090b11a47 | ||
|
|
e44456fc0b | ||
|
|
59f50a569a | ||
|
|
9fda639e00 | ||
|
|
0ff2b5d081 | ||
|
|
134ce5d42d | ||
|
|
0a9ed37244 | ||
|
|
6246e41b55 | ||
|
|
6b6d26b8f0 | ||
|
|
62c87e206e | ||
|
|
4905cdd2e3 | ||
|
|
ce3f88428e | ||
|
|
74644aa4a7 | ||
|
|
2ccb7312d0 | ||
|
|
bd7735af3d | ||
|
|
0c2ab7ef45 | ||
|
|
fab724a703 | ||
|
|
ea86973548 | ||
|
|
9eb0c3c8e5 | ||
|
|
f20b4c9e81 | ||
|
|
6540deb462 | ||
|
|
c80c9bd8b9 | ||
|
|
d7d1e929fe | ||
|
|
e2800d75f7 | ||
|
|
2c1cf87e08 | ||
|
|
e6716fe834 | ||
|
|
fc0d64ec78 | ||
|
|
7b0075d375 | ||
|
|
e227d01436 | ||
|
|
db55fec879 | ||
|
|
9099b13f69 | ||
|
|
0ba05877d7 | ||
|
|
b1ed99dfe6 | ||
|
|
a2e9e2b7d1 | ||
|
|
5163fbf36b | ||
|
|
b187f9427d | ||
|
|
7cc5c87a52 | ||
|
|
1c4141a2b1 | ||
|
|
cc81cc27b0 | ||
|
|
6a5dcb3a76 | ||
|
|
796494e925 | ||
|
|
7973fd84f1 | ||
|
|
66869f8341 | ||
|
|
10d1098403 | ||
|
|
a041fd1266 | ||
|
|
e2fd1559d2 | ||
|
|
9dbd5f89b6 | ||
|
|
0f00c95aba | ||
|
|
bbfe90d2ca | ||
|
|
3f03cb4d2b | ||
|
|
05557ca790 | ||
|
|
a53baa9b42 | ||
|
|
7eafc01ab9 | ||
|
|
57cc1ce5d0 | ||
|
|
368351bbdd | ||
|
|
f9bfcce65d | ||
|
|
e97723dcc7 | ||
|
|
3dc45b80ba | ||
|
|
020eca8292 | ||
|
|
fb469d7b24 | ||
|
|
0f5d297bfb | ||
|
|
a56bd3cb91 | ||
|
|
ddd5d4152b | ||
|
|
edf6cb146d | ||
|
|
4707a50fbb | ||
|
|
91bd6c3f35 | ||
|
|
009950e28f | ||
|
|
8ee12620f0 | ||
|
|
65edc50563 | ||
|
|
a6f5080a4f | ||
|
|
d2d5c423b7 | ||
|
|
42bf8fb40d | ||
|
|
b0dd9690e7 | ||
|
|
65a79d411d | ||
|
|
3a413a59ba | ||
|
|
16a88775c3 | ||
|
|
728b1e8ad4 | ||
|
|
7835550f1a | ||
|
|
a50b4f5e3c | ||
|
|
80c40f6afd | ||
|
|
f442d58b70 | ||
|
|
201d04910a | ||
|
|
65f2ced6c2 | ||
|
|
2a0e78c656 | ||
|
|
05f0630b9c | ||
|
|
ea231cbea8 | ||
|
|
24e71cc6d5 | ||
|
|
94f226aadf | ||
|
|
00d1fcc5fb | ||
|
|
caeda96fbd | ||
|
|
9805ae59d5 | ||
|
|
00eb4068b0 | ||
|
|
fc7d4dfcb0 | ||
|
|
ab28b6d58f | ||
|
|
4abaf13598 | ||
|
|
8b65d873b3 | ||
|
|
a87b562bc2 | ||
|
|
23a51e0982 | ||
|
|
4a3af814bf | ||
|
|
db22936153 | ||
|
|
a147f4120c | ||
|
|
dcd3e07273 | ||
|
|
f26733cd8c | ||
|
|
f3623158d7 | ||
|
|
e80a7c6b75 | ||
|
|
309c8d67f3 | ||
|
|
75c95d88e2 | ||
|
|
0a7d3a9d9b | ||
|
|
aa28769e71 | ||
|
|
75cd411073 | ||
|
|
792a7aa081 | ||
|
|
7ea510e75b | ||
|
|
242df4b049 | ||
|
|
358e38e056 | ||
|
|
c693f63244 | ||
|
|
817157bbc1 | ||
|
|
ac61eb4b1b | ||
|
|
24ab2952ee | ||
|
|
999637f8ad | ||
|
|
25223c446f | ||
|
|
66ad27ad3a | ||
|
|
d9ad4ec743 | ||
|
|
d381108dc0 | ||
|
|
cbe7d0678b | ||
|
|
42d9a41cf5 | ||
|
|
b5a710dbe4 | ||
|
|
40653b0d6f | ||
|
|
608aff1e17 | ||
|
|
5fe766399b | ||
|
|
891115ecee | ||
|
|
0fe722e478 | ||
|
|
ee3864175d | ||
|
|
849d5e6667 | ||
|
|
a8dd2435ec | ||
|
|
d9b086cbe9 | ||
|
|
6464c620c7 | ||
|
|
7998650e60 | ||
|
|
d10714d1c1 | ||
|
|
f721efca1e | ||
|
|
125a21da75 | ||
|
|
c934776f45 | ||
|
|
f1c88bc38d | ||
|
|
92db9e0e00 | ||
|
|
19ba257722 | ||
|
|
6c4d049c1a | ||
|
|
fbb7ef7cfc | ||
|
|
b77881f634 | ||
|
|
7852ff558e | ||
|
|
adb9b773b0 | ||
|
|
410025f30f | ||
|
|
f1d52a8ec1 | ||
|
|
7f2b6a3f10 | ||
|
|
0f321bfb38 | ||
|
|
10b925acb7 | ||
|
|
ee9ac947a1 | ||
|
|
8baf0fdef7 | ||
|
|
353868414a | ||
|
|
c661d8f5b7 | ||
|
|
ca7d7d9369 | ||
|
|
02f14baad4 | ||
|
|
88aa8e8178 | ||
|
|
e979c58c98 | ||
|
|
81b74227fa | ||
|
|
9e96bd6705 | ||
|
|
5203c3927f | ||
|
|
bc099baeb1 | ||
|
|
646ec30ae5 | ||
|
|
dc5eaf3ae9 | ||
|
|
b941654a68 | ||
|
|
6f5482782b | ||
|
|
8a6e3a9898 | ||
|
|
354a0aef52 | ||
|
|
b0b3196e52 | ||
|
|
0139c34ec2 | ||
|
|
ff3680813c | ||
|
|
7db52d794b | ||
|
|
fbbb369fa4 | ||
|
|
f719ee5b18 | ||
|
|
c3ab562258 | ||
|
|
62d3e155bd | ||
|
|
fab80f4e4e | ||
|
|
1cd3a97c51 | ||
|
|
ff99c7de70 | ||
|
|
e2c919d270 | ||
|
|
035d4aed26 | ||
|
|
d03604b14a | ||
|
|
468ef50f75 | ||
|
|
16525c2f3f | ||
|
|
af1a966986 | ||
|
|
1492f1ce89 | ||
|
|
7e87891701 | ||
|
|
e76e9a3e1f | ||
|
|
bfe6fa1e5d | ||
|
|
cf391034da | ||
|
|
36cb1cad36 | ||
|
|
22e2b6f3c5 | ||
|
|
9c8f8c645e | ||
|
|
e21a09cec9 | ||
|
|
a0d1a8cbc4 | ||
|
|
86393e0b1d | ||
|
|
f328713710 | ||
|
|
ed6efe4c9e | ||
|
|
befff2f034 | ||
|
|
630315180d | ||
|
|
a70bfa0c89 | ||
|
|
d2b7e474d6 | ||
|
|
494b72c287 | ||
|
|
229e7b940f | ||
|
|
95dcb03f6d | ||
|
|
a6d9a8220c | ||
|
|
0ba80ce61e | ||
|
|
7c23872e03 | ||
|
|
507938be35 | ||
|
|
8bee304e4d | ||
|
|
be239993f4 | ||
|
|
f396dac1cc | ||
|
|
ebba1f78ab | ||
|
|
c8c3fc2bcc | ||
|
|
14c6c05e00 | ||
|
|
3fbdd9635f | ||
|
|
d7be9c9a66 | ||
|
|
928c9fbacd | ||
|
|
2b666ab9f7 | ||
|
|
4ecc531998 | ||
|
|
b908384ba2 | ||
|
|
b27a4a94e4 | ||
|
|
5e8073022b | ||
|
|
9553425374 | ||
|
|
2012317bc9 | ||
|
|
18a118bb7a | ||
|
|
e00789f838 | ||
|
|
20563e6306 | ||
|
|
580c2d8213 | ||
|
|
c9b8789ea9 | ||
|
|
4271588ecd | ||
|
|
a5277ff4a0 | ||
|
|
a66f5d660d | ||
|
|
80061e8d76 | ||
|
|
d07a057f04 | ||
|
|
fa2949af7d | ||
|
|
a4680b7216 | ||
|
|
523eb910a6 | ||
|
|
2f21de79f7 | ||
|
|
092d402ff8 | ||
|
|
12e8d6c4c6 | ||
|
|
8c1486d577 | ||
|
|
57e9199baa | ||
|
|
f4aac0bd8d | ||
|
|
664150811a | ||
|
|
3cb4ae16ab | ||
|
|
73fc9ea54d | ||
|
|
dd80919ed6 | ||
|
|
d7103cd75c | ||
|
|
29beee367c | ||
|
|
d22fe9227b | ||
|
|
6ea9535463 | ||
|
|
bbd1b730b1 | ||
|
|
6e138e4f79 | ||
|
|
d6453bb53d | ||
|
|
9bfd34e6b2 | ||
|
|
7b13771cfe | ||
|
|
b70b222f80 | ||
|
|
2ffc8dd228 | ||
|
|
08d12f9ee6 | ||
|
|
7ce96c190f | ||
|
|
409b4b1963 | ||
|
|
05cd7d753e | ||
|
|
7be460e8b1 | ||
|
|
6dfbd07e86 | ||
|
|
7b56e53c47 | ||
|
|
a8cde3289a | ||
|
|
f4e7202dd0 | ||
|
|
a2de3d33bf | ||
|
|
46a3e3d353 | ||
|
|
756e27fb52 | ||
|
|
1d6e5a2464 | ||
|
|
dc77428df4 | ||
|
|
b293356cec | ||
|
|
1dc7647bb9 | ||
|
|
c3f6537a4d | ||
|
|
70a3dc938a | ||
|
|
1fd703aff9 | ||
|
|
aa3fb7d165 | ||
|
|
2b9ff3148c | ||
|
|
7f24269511 | ||
|
|
b34d65fce0 | ||
|
|
778cecb512 | ||
|
|
e7e0eb0f32 | ||
|
|
a0c55c6406 | ||
|
|
aba736cb96 | ||
|
|
bdec873fed | ||
|
|
2cc73660bf | ||
|
|
f3de45c6ad | ||
|
|
386e2c6306 | ||
|
|
2473065b98 | ||
|
|
ed91c54654 | ||
|
|
4d53e0adde | ||
|
|
35f87365c9 | ||
|
|
8e7d6d5dad | ||
|
|
95a10c692c | ||
|
|
3a31d5d49e | ||
|
|
77d7082ffc | ||
|
|
c43d09c8b1 | ||
|
|
d92e60ee5f | ||
|
|
b9ceacb43d | ||
|
|
2fe809f15a | ||
|
|
078a054dbd | ||
|
|
c57be77039 | ||
|
|
e6910f732f | ||
|
|
d0b599781d | ||
|
|
2431f2058b | ||
|
|
8c717537c4 | ||
|
|
e088f4654a | ||
|
|
b363b6151c | ||
|
|
3baa4f8223 | ||
|
|
373f4cfefd | ||
|
|
64a02b705a | ||
|
|
f72b5d04e8 | ||
|
|
1688546519 | ||
|
|
2eff6b7a3a | ||
|
|
58962f8470 | ||
|
|
dfd7ff5b39 | ||
|
|
d56ded8c18 | ||
|
|
af3ebbb3c2 | ||
|
|
1db3359b84 | ||
|
|
7a40ef74c6 | ||
|
|
b64cd36468 | ||
|
|
b3f9983f44 | ||
|
|
070b08a9e6 | ||
|
|
851e9ece03 | ||
|
|
51db63dff7 | ||
|
|
a5b972d87e | ||
|
|
4bc3408410 | ||
|
|
5d392d89ce | ||
|
|
86f97614b0 | ||
|
|
5b7bab6752 | ||
|
|
70042db2de | ||
|
|
bf69d37cbe | ||
|
|
ee7ec20f29 | ||
|
|
1e1ba9afa3 | ||
|
|
32a75c1ff5 | ||
|
|
f51783f039 | ||
|
|
c203ef8bcd | ||
|
|
61b99471a1 | ||
|
|
e27fa882fa | ||
|
|
7c05914e5a | ||
|
|
daa438b349 | ||
|
|
35624ab998 | ||
|
|
e6b145412b | ||
|
|
2d6ad41ed4 | ||
|
|
8544bdd881 | ||
|
|
a778ff01f6 | ||
|
|
e7c0ce794b | ||
|
|
4c50119ac2 | ||
|
|
2181618357 | ||
|
|
bec7e54f7f | ||
|
|
dc317220b3 | ||
|
|
981750a48a | ||
|
|
1df717084b | ||
|
|
f2caf14d6a | ||
|
|
199529a031 | ||
|
|
99108f9eff | ||
|
|
74672e2130 | ||
|
|
7d48bba926 | ||
|
|
5f19608e41 | ||
|
|
8d4c9119b4 | ||
|
|
b1b2eead26 | ||
|
|
b3af04d3ca | ||
|
|
04c7eace09 | ||
|
|
0e7d5dd013 | ||
|
|
27d3420ad7 | ||
|
|
c9672b35ce | ||
|
|
39512da74e | ||
|
|
0d44e7ec27 | ||
|
|
24082d169b | ||
|
|
3debaf0f41 | ||
|
|
2448266d7c | ||
|
|
3a426e258b | ||
|
|
b062d1ee3e | ||
|
|
ebc171d405 | ||
|
|
4951be6999 | ||
|
|
01a71132d5 | ||
|
|
a421a90e0a | ||
|
|
1d558e8391 | ||
|
|
30a697e708 | ||
|
|
0233daeda2 | ||
|
|
48372bcd91 | ||
|
|
44a1a1ebde | ||
|
|
2b07be1d09 | ||
|
|
a98685d89e | ||
|
|
1c4ba20646 | ||
|
|
d3954b94d3 | ||
|
|
7daea18907 | ||
|
|
0c84235a95 | ||
|
|
aab29cb0ab | ||
|
|
566c5057f9 | ||
|
|
cd52d7bcf6 | ||
|
|
ed3ec66d33 | ||
|
|
01c463c8e8 | ||
|
|
872465df40 | ||
|
|
b6f74287d0 | ||
|
|
013684b5ca | ||
|
|
90c2955a71 | ||
|
|
7be868db12 | ||
|
|
703f84e5e1 | ||
|
|
c92dbb10ac | ||
|
|
8ee2c44550 | ||
|
|
48f5099646 | ||
|
|
b9aeb19834 | ||
|
|
193926c795 | ||
|
|
a4c3491f0c | ||
|
|
ad65856b3d | ||
|
|
b2aac9f991 | ||
|
|
a582786655 | ||
|
|
953e994c88 | ||
|
|
9a6e91d3e5 | ||
|
|
fc4e7a2dee | ||
|
|
a56014bb66 | ||
|
|
ebfc438bd4 | ||
|
|
3996f02dea | ||
|
|
d637524bfc | ||
|
|
8570922dcc | ||
|
|
6598265f9b | ||
|
|
8f398dfd08 | ||
|
|
68e9d701de | ||
|
|
67e8a00b6d | ||
|
|
11b48bc374 | ||
|
|
fa80c62b28 | ||
|
|
7f9cc67518 | ||
|
|
84eb6fd460 | ||
|
|
2cc5a29b86 | ||
|
|
b178c08271 | ||
|
|
9a3b208ac5 | ||
|
|
2989155f05 | ||
|
|
50b56c64f5 | ||
|
|
be3e331afb | ||
|
|
9d8fdd0b20 | ||
|
|
033c7abe62 | ||
|
|
5525a21696 | ||
|
|
aed03cd03b | ||
|
|
5a5661f136 | ||
|
|
a3bcf92ea5 | ||
|
|
0ad31c90f6 | ||
|
|
789d68e80d | ||
|
|
f06a1e8b49 | ||
|
|
a0ca243955 | ||
|
|
9e2268bd74 | ||
|
|
702d085117 | ||
|
|
356a0d72c3 | ||
|
|
7fcc4a5283 | ||
|
|
15edfcd088 | ||
|
|
278d204d1c | ||
|
|
39b3e7e507 | ||
|
|
8487dd7cfd | ||
|
|
5d05d7936c | ||
|
|
0afd2fe720 | ||
|
|
59a79a30da | ||
|
|
5da380e1b0 | ||
|
|
2adf745d06 | ||
|
|
ef2eb0764c | ||
|
|
9e37d7051c | ||
|
|
05098c3382 | ||
|
|
32607ee74c | ||
|
|
30559cd2d3 | ||
|
|
8fd905215f | ||
|
|
270d75afe2 | ||
|
|
a65f97ac75 | ||
|
|
53c1856038 | ||
|
|
56b8af86d7 | ||
|
|
e852df3179 | ||
|
|
7c03f716a8 | ||
|
|
d4ba603cf7 | ||
|
|
deb0306347 | ||
|
|
881da25e8c | ||
|
|
a37b953e72 | ||
|
|
bba5188594 | ||
|
|
7dc633581d | ||
|
|
bd00d012e2 | ||
|
|
4f4476b79f | ||
|
|
0b8721c25e | ||
|
|
869e275e48 | ||
|
|
e4714870a4 | ||
|
|
1dbd7066de | ||
|
|
022e4986ee | ||
|
|
2c9c413e79 | ||
|
|
b380d5e2c7 | ||
|
|
650853c177 | ||
|
|
ae698f988a | ||
|
|
f920fdecfe | ||
|
|
4e4f823141 | ||
|
|
b421f7ae87 | ||
|
|
ca80d0489b | ||
|
|
1ed82426a1 | ||
|
|
7e9f7d4101 | ||
|
|
f240a33935 | ||
|
|
5bd0a26126 | ||
|
|
cc011e39ce | ||
|
|
29ee551b06 | ||
|
|
5b5e4157e3 | ||
|
|
3c19692312 | ||
|
|
24accf96a8 | ||
|
|
f2626b0fc0 | ||
|
|
cc9e9b109c | ||
|
|
adead9b578 | ||
|
|
8527d231e1 | ||
|
|
4c19341279 | ||
|
|
075fd4da2d | ||
|
|
52bee88ad2 | ||
|
|
52b784e0e5 | ||
|
|
3521732597 | ||
|
|
d3eec72e45 | ||
|
|
79bac912aa | ||
|
|
2381e323c1 | ||
|
|
d64cedd3fc | ||
|
|
c16d83fab0 | ||
|
|
cbed841414 | ||
|
|
67022beca0 | ||
|
|
6e76a72d78 | ||
|
|
a5575bc3a0 | ||
|
|
90b18158fc | ||
|
|
71b0e8e937 | ||
|
|
4d5e0ca7a3 | ||
|
|
b8685f2c39 | ||
|
|
c4e697d797 | ||
|
|
3502a39181 | ||
|
|
4a56c92e7b | ||
|
|
2aab617c2e | ||
|
|
471bd83eb2 | ||
|
|
ec7a7f4c25 | ||
|
|
bb0c0af189 | ||
|
|
d2f8f99683 | ||
|
|
1c146baeeb | ||
|
|
709aeff9ea | ||
|
|
34f18122f5 | ||
|
|
7208282431 | ||
|
|
204e72e9eb | ||
|
|
f626dfb7b7 | ||
|
|
08b263bf4e | ||
|
|
d0e99923fd | ||
|
|
1750512477 | ||
|
|
5e3b4c3a11 | ||
|
|
0c431d9746 | ||
|
|
438c5d9909 | ||
|
|
7d29edf6f4 | ||
|
|
50d505b896 | ||
|
|
2e06f5b1e8 | ||
|
|
3adcbb7904 | ||
|
|
f447df9873 | ||
|
|
27e98147ef | ||
|
|
48958cc638 | ||
|
|
ae4de2782a | ||
|
|
dcf89e0dbd | ||
|
|
35d92f43c0 | ||
|
|
12db60885f | ||
|
|
d637260dc3 | ||
|
|
0937064e18 | ||
|
|
54264efb20 | ||
|
|
6a1d3de75b | ||
|
|
3fc8c7d560 | ||
|
|
56e1d577fd | ||
|
|
272129f66c | ||
|
|
0441ede229 | ||
|
|
f001846e00 | ||
|
|
0ac627dfbb | ||
|
|
1a82a3bf7b | ||
|
|
a2d84886c0 | ||
|
|
97e8382a41 | ||
|
|
88738327fd | ||
|
|
0ad65f4748 | ||
|
|
9dad436f72 | ||
|
|
ebdc38fff2 | ||
|
|
97bbe6f305 | ||
|
|
2f0dbef1e5 | ||
|
|
1711286ef0 | ||
|
|
099d3f7b41 | ||
|
|
5f77478841 | ||
|
|
07cc3aa5c0 | ||
|
|
ff26f54bfd | ||
|
|
3323d2ed37 | ||
|
|
7b9b3f1ee2 | ||
|
|
cae98451e3 | ||
|
|
83da7569f5 | ||
|
|
26397ee8ad | ||
|
|
dcfebcb973 | ||
|
|
fd3b47908b | ||
|
|
217d2aeb7f | ||
|
|
e57c701837 | ||
|
|
b4aa8376de | ||
|
|
d4976ac47a | ||
|
|
b8a96d9a77 | ||
|
|
f75d582eee | ||
|
|
18e0ec9a55 | ||
|
|
68b80cdadc | ||
|
|
3d3c475d1b | ||
|
|
6668e72351 | ||
|
|
b72695f01a | ||
|
|
65f98c1f30 | ||
|
|
c6fd4c51cf | ||
|
|
3c11c8441f | ||
|
|
3261c5b071 | ||
|
|
c8625c70dd | ||
|
|
396e9d0c39 | ||
|
|
e16d3bf040 | ||
|
|
2c58a87982 | ||
|
|
a705ae5278 | ||
|
|
a426e93011 | ||
|
|
1c220d25ca | ||
|
|
039858dca2 | ||
|
|
4758b5efe8 | ||
|
|
36e065ab4d | ||
|
|
076497e14d | ||
|
|
e8d9891d13 | ||
|
|
4902d7fb9e | ||
|
|
a873ca6a3e | ||
|
|
a86cb27cfe | ||
|
|
d620930f10 | ||
|
|
8db8ecfef3 | ||
|
|
a0f99393f5 | ||
|
|
ae8c3b02d0 | ||
|
|
99427c2ef7 | ||
|
|
334f16c0b6 | ||
|
|
7a80a772c1 | ||
|
|
8b1d712e1e | ||
|
|
a121f5b61b | ||
|
|
251062170e | ||
|
|
92e59af4d8 | ||
|
|
fa4c23b76e | ||
|
|
a0a46850f5 | ||
|
|
4cd0563a93 | ||
|
|
b83f0f461c | ||
|
|
3668ede0ff | ||
|
|
945584384a | ||
|
|
b1dd27b516 | ||
|
|
dcba1aad10 | ||
|
|
acc8b9cdbc | ||
|
|
6cbdd825eb | ||
|
|
cc55f6015d | ||
|
|
95718ab6ec | ||
|
|
feab27295d | ||
|
|
ca176c7549 | ||
|
|
f8a7a0d6e8 | ||
|
|
0a05611e1d | ||
|
|
1a8aaa3b26 | ||
|
|
cd1c13b4b1 | ||
|
|
d87c5035dd | ||
|
|
77967731d5 | ||
|
|
0b54034470 | ||
|
|
8ad2583785 | ||
|
|
dd533a9ab4 | ||
|
|
7236589037 | ||
|
|
2c583c3071 | ||
|
|
5b989adebc | ||
|
|
855e606163 | ||
|
|
20f8d3c8a9 | ||
|
|
0c77dbb7ea | ||
|
|
2448e2ae3b | ||
|
|
d53d7aa2e2 | ||
|
|
0be1df7ee8 | ||
|
|
6aef0e145c | ||
|
|
4f1965fbaa | ||
|
|
32dc54ce72 | ||
|
|
548736f432 | ||
|
|
6790f8af08 | ||
|
|
89d587e7dd | ||
|
|
5c8b2ebf7a | ||
|
|
5ac8ba9bae | ||
|
|
8f8afd98a5 | ||
|
|
49fb16e2c6 | ||
|
|
0db47a8586 | ||
|
|
cec8978886 | ||
|
|
0160e3fa87 | ||
|
|
545bfa6ef9 | ||
|
|
c596b5a17d | ||
|
|
84dd26c1b7 | ||
|
|
a765903a41 | ||
|
|
25ab381916 | ||
|
|
4d3df5d98f | ||
|
|
6fe2024542 | ||
|
|
7f69a0bc5e | ||
|
|
5b829adedb | ||
|
|
4cd4c13b2d | ||
|
|
86be5df475 | ||
|
|
8c5e0cd4e9 | ||
|
|
d320c4650d | ||
|
|
a9b0b8adc8 | ||
|
|
ba01cb82f7 | ||
|
|
223b97b884 | ||
|
|
d437027f26 | ||
|
|
9a564ee204 | ||
|
|
d37ee89e84 | ||
|
|
5de86d3d91 | ||
|
|
4b6041302e | ||
|
|
536444f9d1 | ||
|
|
ba5ec57e4d | ||
|
|
9fa53ccf05 | ||
|
|
5c2bac4b9d | ||
|
|
ef1e24cec2 | ||
|
|
001e2ad287 | ||
|
|
0404ec9881 | ||
|
|
6ff5c88ebf | ||
|
|
1e761c31bd | ||
|
|
ab7b2d729e | ||
|
|
271a07a7d6 | ||
|
|
029293a086 | ||
|
|
cf1630a94a | ||
|
|
4634ace74e | ||
|
|
3733715184 | ||
|
|
bf37ac53a3 | ||
|
|
50934e6840 | ||
|
|
891ea48e11 | ||
|
|
70323b9477 | ||
|
|
451cd4c74a | ||
|
|
7d0951a08a | ||
|
|
d98ca9a202 | ||
|
|
3c2c5bedc5 | ||
|
|
749d34cd30 | ||
|
|
1898be2fe1 | ||
|
|
af34da4160 | ||
|
|
fa053b7e60 | ||
|
|
4588219e31 | ||
|
|
6e89346f00 | ||
|
|
2703c9899a | ||
|
|
d05c358fd2 | ||
|
|
7c6bc5c421 | ||
|
|
798c398f23 | ||
|
|
4cc2cc4ad4 | ||
|
|
dcfdca6351 | ||
|
|
832599b8c5 | ||
|
|
c81ef2669e | ||
|
|
19d837c222 | ||
|
|
4f48ddfaec | ||
|
|
2e01fe0b5b | ||
|
|
7d067d8c30 | ||
|
|
b3b326738c | ||
|
|
2bb2caf2d2 | ||
|
|
2a094883ad | ||
|
|
6d1126b8aa | ||
|
|
26a47537f9 | ||
|
|
01d43c69fb | ||
|
|
7db1989093 | ||
|
|
32eee3365a | ||
|
|
95b4bde918 | ||
|
|
0a97e28aab | ||
|
|
4fa8a3898a | ||
|
|
caa997fff1 | ||
|
|
bd68b977d5 | ||
|
|
98a6907976 | ||
|
|
e9d2182390 | ||
|
|
5e29f2c1b7 | ||
|
|
44e28f96e0 | ||
|
|
a0e81da8c5 | ||
|
|
85a7c3c60d | ||
|
|
01e07ca0bc | ||
|
|
1468ee5fde | ||
|
|
49f044ecde | ||
|
|
37f32ab197 | ||
|
|
de8a3666ec | ||
|
|
a60231ba59 | ||
|
|
c8dafede6d | ||
|
|
210191b251 | ||
|
|
7deea9eb75 | ||
|
|
5e9a46d54d | ||
|
|
be64930ebb | ||
|
|
488974dd3e | ||
|
|
5975b9125f | ||
|
|
f301296f1e | ||
|
|
407477dc68 | ||
|
|
eb5ad232a0 | ||
|
|
1b0ce9a123 | ||
|
|
7b855c851d | ||
|
|
f1b9952bf9 | ||
|
|
6f03854eda | ||
|
|
c356846d90 | ||
|
|
f7b8828deb | ||
|
|
4276671538 | ||
|
|
5b86c67a98 | ||
|
|
6ce6b9576d | ||
|
|
ca062140f3 | ||
|
|
a15c391e6c | ||
|
|
ba636b17a0 | ||
|
|
2a07eb84f6 | ||
|
|
949b9fb10e | ||
|
|
ae1b6af0d4 | ||
|
|
dd27504d30 | ||
|
|
c30a08cfc5 | ||
|
|
a4c49aa35e | ||
|
|
ba3a61f623 | ||
|
|
402fba734a | ||
|
|
262af0678f | ||
|
|
3765d558b6 | ||
|
|
4ed8ded502 | ||
|
|
ee380c5377 | ||
|
|
7fa25ca7ae | ||
|
|
d3c401ed4e | ||
|
|
cb8dae1ddb | ||
|
|
59deebc961 | ||
|
|
0ae73296cf | ||
|
|
8e78fb4caa | ||
|
|
336da25463 | ||
|
|
ffbc8c5f70 | ||
|
|
10d8cfde85 | ||
|
|
3c7f83407b | ||
|
|
fe4b668107 | ||
|
|
cc87b32206 | ||
|
|
9114867578 | ||
|
|
6f221852a2 | ||
|
|
c842994df5 | ||
|
|
202901b09f | ||
|
|
7c0fe1285a | ||
|
|
6dc2c680c5 | ||
|
|
9a4b56db6e | ||
|
|
8180f2c742 | ||
|
|
a76a895f1d | ||
|
|
b404458369 | ||
|
|
c44b9f8659 | ||
|
|
bef1ac2668 | ||
|
|
906f8fc2e7 | ||
|
|
c600c6da63 | ||
|
|
e789a18553 | ||
|
|
3f3c986932 | ||
|
|
3ccc5babc1 | ||
|
|
fafb2eba69 | ||
|
|
33cf82a982 | ||
|
|
e74eb7d3fc | ||
|
|
fbeead0c74 | ||
|
|
9a9c65ac8e | ||
|
|
0a8d86cfc3 | ||
|
|
8632a0a6ec | ||
|
|
e111b6e1b7 | ||
|
|
b7aba15d58 | ||
|
|
713cbb81b8 | ||
|
|
fc0739703b | ||
|
|
382d7e8ac3 | ||
|
|
23e578bfbf | ||
|
|
bd7cd32f91 | ||
|
|
0a5400263b | ||
|
|
17d59d3337 | ||
|
|
9cb3531e2d | ||
|
|
b50e6e0d90 | ||
|
|
a88436c620 | ||
|
|
45cf90094a | ||
|
|
ae1df20893 | ||
|
|
71148740d4 | ||
|
|
4ef583c844 | ||
|
|
16f61ea96d | ||
|
|
32f9616b6e | ||
|
|
1346eb4f76 | ||
|
|
d4268ba070 | ||
|
|
696290527a | ||
|
|
686866c6f9 | ||
|
|
72455ccde1 | ||
|
|
88fb860568 | ||
|
|
ceed494cf7 | ||
|
|
ac8f919304 | ||
|
|
7f1ec4802d | ||
|
|
d5777b7bce | ||
|
|
e34f179a82 | ||
|
|
6a90b9a512 | ||
|
|
ce5ee65d60 | ||
|
|
65a8dbfe41 | ||
|
|
1ff667b7ef | ||
|
|
0806c7fbdb | ||
|
|
5708d7a6b8 | ||
|
|
2264cc5d10 | ||
|
|
28cb3f9d0c | ||
|
|
f16ed4697f | ||
|
|
81e412fe5b | ||
|
|
f3137eb0a9 | ||
|
|
0e5bd4ed74 | ||
|
|
6a37f25c5d | ||
|
|
2afff05014 | ||
|
|
e3d9417b84 | ||
|
|
6a188033c6 | ||
|
|
df24fd7bf2 | ||
|
|
d45b4ad134 | ||
|
|
ec938f254c | ||
|
|
fa82e759bd | ||
|
|
daf0bcfac3 | ||
|
|
09428dcade | ||
|
|
49d51c5af8 | ||
|
|
ec7f69d559 | ||
|
|
a8c5bf2573 | ||
|
|
f12de61d7f | ||
|
|
71fcd6482d | ||
|
|
e59b38a5d2 | ||
|
|
b07658b460 | ||
|
|
5b8d9d1510 | ||
|
|
6169c458bf | ||
|
|
23400d0449 | ||
|
|
992d11be10 | ||
|
|
feac45fd0a | ||
|
|
934176818f | ||
|
|
c5435ec1fa | ||
|
|
c3f472fbcb | ||
|
|
1cee1c3562 | ||
|
|
eae5a74a11 | ||
|
|
5df1a223c2 | ||
|
|
81382a4bc0 | ||
|
|
750a429bd4 | ||
|
|
dbe78dff93 | ||
|
|
5869627b32 | ||
|
|
5bc5ef0ae8 | ||
|
|
2cfd2e1410 | ||
|
|
cce5e8f811 | ||
|
|
058e66c7fc | ||
|
|
8ae09c3d02 | ||
|
|
83699bc5c3 | ||
|
|
3a5eb8c5d2 | ||
|
|
fd00e5eaae | ||
|
|
20444ee7d5 | ||
|
|
eb06e575c2 | ||
|
|
ad402adf7a | ||
|
|
21c582ee1a | ||
|
|
e0d78d5328 | ||
|
|
f96acd6263 | ||
|
|
e185f2eaf6 | ||
|
|
78fb9dcc59 | ||
|
|
e066b502c3 | ||
|
|
e94943d505 | ||
|
|
b4315152e2 | ||
|
|
aae9446ce0 | ||
|
|
ecd46f2f06 | ||
|
|
74f77a7e8a | ||
|
|
340a9f8b76 | ||
|
|
81cec6a25a | ||
|
|
c5b31e2f63 | ||
|
|
0642b17ab0 | ||
|
|
ac689a9a2e | ||
|
|
43cc4ec009 | ||
|
|
9cc333b2bd | ||
|
|
55d98ff935 | ||
|
|
dc90a4ed42 | ||
|
|
ef80abd885 | ||
|
|
b9080f9479 | ||
|
|
092a5a1ca3 | ||
|
|
d3c31c52a2 | ||
|
|
329173e145 | ||
|
|
8e4f8fcbc8 | ||
|
|
c1c707c77a | ||
|
|
b1e58dd10d | ||
|
|
2cc0aceac7 | ||
|
|
d79d5dbadd | ||
|
|
ebd8a10cef | ||
|
|
be7475fe66 | ||
|
|
85e2f7eb34 | ||
|
|
9bb979f2e8 | ||
|
|
c942345453 | ||
|
|
fcc344ba99 | ||
|
|
a3b28871c6 | ||
|
|
2ca034bfa8 | ||
|
|
0d035a08d6 | ||
|
|
6655e2664e | ||
|
|
c51ce2eec7 | ||
|
|
b2e00eb868 | ||
|
|
820df0c596 | ||
|
|
865e3dcd0c | ||
|
|
f55e2fc7b8 | ||
|
|
cb22e1933e | ||
|
|
8818a9e82a | ||
|
|
dbb47d506c | ||
|
|
e4d5d77347 | ||
|
|
dd52124765 | ||
|
|
6f3267aee9 | ||
|
|
0bbd6b7c4b | ||
|
|
1cc47b02cf | ||
|
|
e7babc071d | ||
|
|
d11ca2e159 | ||
|
|
2d6365dc6a | ||
|
|
cc24119a59 | ||
|
|
b8f15333d8 | ||
|
|
e5a426419c | ||
|
|
8a1df1e700 | ||
|
|
cc298f56e2 | ||
|
|
665693a513 | ||
|
|
c35e82e59f | ||
|
|
72d38f4cff | ||
|
|
f6c47ac19c | ||
|
|
0430dc5a1f | ||
|
|
27bec89386 | ||
|
|
79b3ce141c | ||
|
|
011afd0910 | ||
|
|
8d00e4d31d | ||
|
|
8688777ae1 | ||
|
|
198aceee07 | ||
|
|
ee1bf1c221 | ||
|
|
24ecf1a166 | ||
|
|
5cb49c86a0 | ||
|
|
9940d2590b | ||
|
|
577fce69e2 | ||
|
|
e68375a71e | ||
|
|
fe7fb6c7a9 | ||
|
|
cec67d8eff | ||
|
|
2443e2ec7c | ||
|
|
bcf862044a | ||
|
|
b73f049484 | ||
|
|
cde5314d41 | ||
|
|
ed5eb28228 | ||
|
|
db5e66a9b0 | ||
|
|
77723b615f | ||
|
|
96c7716d3e | ||
|
|
ea80c1ed83 | ||
|
|
7d7b7c1e25 | ||
|
|
9d860c265c | ||
|
|
d234b4b0f1 | ||
|
|
e1598a9966 | ||
|
|
e82f38e277 | ||
|
|
1d27aa2f18 | ||
|
|
113dbbdf94 | ||
|
|
e701b5b5eb | ||
|
|
6f01896d04 | ||
|
|
5582bbac60 | ||
|
|
d2401a212a | ||
|
|
52548542d2 | ||
|
|
509cbdf476 | ||
|
|
5a6ebd6657 | ||
|
|
541d3f286a | ||
|
|
0191af412b | ||
|
|
abcd2a2d01 | ||
|
|
91efcb910b | ||
|
|
e9b7320d1c | ||
|
|
779744bd8e | ||
|
|
1123d85fd2 | ||
|
|
5c247d2833 | ||
|
|
17fdb4f5c9 | ||
|
|
365c1987ed | ||
|
|
c03422ee37 | ||
|
|
ef8f23ce90 | ||
|
|
050f7ebddf | ||
|
|
10fdf46410 | ||
|
|
49976ae35a | ||
|
|
21afb05409 | ||
|
|
0af1ec3bde | ||
|
|
343d766ddd | ||
|
|
02cae2e61e | ||
|
|
1975c9c34a | ||
|
|
42decbddd9 | ||
|
|
d88bb3c668 | ||
|
|
b71467b9be | ||
|
|
ac503ef72e | ||
|
|
ea608cecb0 | ||
|
|
2e266ec945 | ||
|
|
bec1adf7ad | ||
|
|
2fc2f47d06 | ||
|
|
3a8e19d1b4 | ||
|
|
cc9db0220c | ||
|
|
13ed78be96 | ||
|
|
cd1ede38a7 | ||
|
|
1ec68c428a | ||
|
|
f6ed3bc9db | ||
|
|
34cdda2e28 | ||
|
|
4ab2c907f5 | ||
|
|
8632d99341 | ||
|
|
efa32ed4f6 | ||
|
|
551b8af76d | ||
|
|
887254f5da | ||
|
|
0275bd1d45 | ||
|
|
f3891c305d | ||
|
|
5874b78349 | ||
|
|
a812fc07f2 | ||
|
|
78e7312adf | ||
|
|
593970ed6d | ||
|
|
693bf4816b | ||
|
|
b8b11880b0 | ||
|
|
0ff4016250 | ||
|
|
e753f3849e | ||
|
|
7b248c8fb2 | ||
|
|
f0e4dd90ee | ||
|
|
c540ec5417 | ||
|
|
3615ab535b | ||
|
|
b8d6ebe882 | ||
|
|
1f27872294 | ||
|
|
3815516022 | ||
|
|
a1dfdced31 | ||
|
|
ff39a8db3f | ||
|
|
9877e899e0 | ||
|
|
bc4a6138b1 | ||
|
|
f825cab54a | ||
|
|
57b01c2711 | ||
|
|
5f3e3d7796 | ||
|
|
bee75a4508 | ||
|
|
a4ac444bda | ||
|
|
d13b8c8421 | ||
|
|
0af3063127 | ||
|
|
17e1975dd8 | ||
|
|
166eeacab9 | ||
|
|
296df2660a | ||
|
|
017169f1a1 | ||
|
|
ed0e73803f | ||
|
|
f4475b9d2a | ||
|
|
b9849da66e | ||
|
|
8a1df9afee | ||
|
|
9cfb56d9c6 | ||
|
|
25ade86994 | ||
|
|
da484b07f5 | ||
|
|
20c0916adc | ||
|
|
c10ec2962b | ||
|
|
de5632b1cf | ||
|
|
1bb06106fd | ||
|
|
bc18cdbeea | ||
|
|
67df5d6dcc | ||
|
|
68a7282b27 | ||
|
|
5732b66c5a | ||
|
|
f1cce8ef46 | ||
|
|
e47932c9aa | ||
|
|
3a70fb0e15 | ||
|
|
d5da84dcb2 | ||
|
|
1bd051d703 | ||
|
|
abb55f8e4b | ||
|
|
46f6a257d0 | ||
|
|
97e4eec5be | ||
|
|
69b99abb7d | ||
|
|
08f6d5a683 | ||
|
|
627bea30ed | ||
|
|
caf0a5bbe8 | ||
|
|
501f988b0f | ||
|
|
5f0c6fce74 | ||
|
|
78089107b7 | ||
|
|
f3b0906cea | ||
|
|
9f581c6181 | ||
|
|
31b232d3f3 | ||
|
|
77e6a6de61 | ||
|
|
85702a8142 | ||
|
|
0bcdc9641d | ||
|
|
bfd1bdfc64 | ||
|
|
c1fed6d469 | ||
|
|
79ffe021e4 | ||
|
|
a1c348b365 | ||
|
|
904b1f114b | ||
|
|
63f481d498 | ||
|
|
fc5c19788e | ||
|
|
56e0bde8ab | ||
|
|
db2cdca71b | ||
|
|
faa2fba6b9 | ||
|
|
f727ea2874 | ||
|
|
4a7ef07089 | ||
|
|
0df726cdab | ||
|
|
2f6f0d2f3e | ||
|
|
fae5938b0a | ||
|
|
2ec3639900 | ||
|
|
4513404629 | ||
|
|
13bfda56ef | ||
|
|
075c164407 | ||
|
|
dcb5049f97 | ||
|
|
d24cf14009 | ||
|
|
3d34802ab2 | ||
|
|
2aec21a6d0 | ||
|
|
19ccff9ff1 | ||
|
|
1dd9c6754c | ||
|
|
f9467ceaf1 | ||
|
|
ccce0f2d3b | ||
|
|
f51da4f0c4 | ||
|
|
2eff389fff | ||
|
|
77ca2ec0e9 | ||
|
|
77e6ea8a6f | ||
|
|
e33299bbd7 | ||
|
|
74e273274c | ||
|
|
02bf5902f0 | ||
|
|
5f41de8938 | ||
|
|
f71d839009 | ||
|
|
3cb6b17316 | ||
|
|
c0cb677a4c | ||
|
|
a5a6a8eaee | ||
|
|
ecb861de56 | ||
|
|
1d20f18d3f | ||
|
|
68f6b3452e | ||
|
|
60075f6e8c | ||
|
|
1d7789f544 | ||
|
|
bd10a9aa26 | ||
|
|
1ceeed38bc | ||
|
|
2e1e917952 | ||
|
|
9e0b91ac17 | ||
|
|
ea83ec496b | ||
|
|
f26bb26ffa | ||
|
|
28348f919b | ||
|
|
c84d4c637d | ||
|
|
04706cfa9c | ||
|
|
3078bea7cc | ||
|
|
c91e0fc988 | ||
|
|
5183af4e8a | ||
|
|
1ff5cb0596 | ||
|
|
f441ce9c17 | ||
|
|
522e5e7957 | ||
|
|
9e468bd059 | ||
|
|
ecc9443677 | ||
|
|
6b8d8bf735 | ||
|
|
43d024fe42 | ||
|
|
c016dedea4 | ||
|
|
b9ca2cfe90 | ||
|
|
d3492b5b6c | ||
|
|
3682cd6a5e | ||
|
|
b209b1e481 | ||
|
|
4afed48f58 | ||
|
|
6a18ce078e | ||
|
|
bc5aadff7d | ||
|
|
de89b516dc | ||
|
|
4dbe9a7015 | ||
|
|
a320f16404 | ||
|
|
cec7241986 | ||
|
|
6de77293ad | ||
|
|
0ac53d8353 | ||
|
|
da79b93387 | ||
|
|
b88c300d04 | ||
|
|
88372cd516 | ||
|
|
b3206121cc | ||
|
|
5bccb5fc42 | ||
|
|
47e1cbdaff | ||
|
|
52020cbe26 | ||
|
|
d33651c25b | ||
|
|
18e9f9c304 | ||
|
|
2607c44fbb | ||
|
|
c8a7d44f55 | ||
|
|
a6e536189c | ||
|
|
3f9a6cae53 | ||
|
|
cd5494fdd2 | ||
|
|
5ab1b14d6b | ||
|
|
379f181362 | ||
|
|
dd19aa63d0 | ||
|
|
6df3b417a9 | ||
|
|
fa76431dd6 | ||
|
|
6504fb68b6 | ||
|
|
2ff49cf657 | ||
|
|
fa1aa1fe80 | ||
|
|
85b95a2940 | ||
|
|
5e38039c4d | ||
|
|
4df936a437 | ||
|
|
736a8b1b80 | ||
|
|
22f6128bc4 | ||
|
|
db475b6998 | ||
|
|
6daf7f6322 | ||
|
|
16086c0961 | ||
|
|
e88c81ad0d | ||
|
|
a2b9aed40d | ||
|
|
caa4fe1ec4 | ||
|
|
25fb878e54 | ||
|
|
a1d6ffadad | ||
|
|
3b89814b69 | ||
|
|
071e0be445 | ||
|
|
bed364d75e | ||
|
|
d2984e9e16 | ||
|
|
05a8c692f2 | ||
|
|
fd9570e782 | ||
|
|
35d26afcb4 | ||
|
|
2245ee6fce | ||
|
|
ff10130176 | ||
|
|
a13f1a9bee | ||
|
|
3cc60fa4d4 | ||
|
|
bd69c24231 | ||
|
|
c7d292a716 | ||
|
|
74bc159a52 | ||
|
|
9f99a1896d | ||
|
|
8110259d1c | ||
|
|
1048bf993a | ||
|
|
3eba0f4e0d | ||
|
|
d7e0b364d1 | ||
|
|
25dd43b949 | ||
|
|
8e8ffa30a6 | ||
|
|
69da2f4b23 | ||
|
|
d48bab02a1 | ||
|
|
886120fe9f | ||
|
|
bdd4d9f3ff | ||
|
|
6276c2f1f5 | ||
|
|
b3acc97d03 | ||
|
|
24bd1db4fc | ||
|
|
e83d3cb4a3 | ||
|
|
674481f0d1 | ||
|
|
5d271d21bc | ||
|
|
4e4493e627 | ||
|
|
1154905818 | ||
|
|
0d3ea848c2 | ||
|
|
8ffe1e65fd | ||
|
|
127ea7e351 | ||
|
|
34b16f1919 | ||
|
|
fa32faf759 | ||
|
|
6f3d7e76c9 | ||
|
|
57665e8964 | ||
|
|
5c502b1fe4 | ||
|
|
6d1410741d | ||
|
|
3e20724058 | ||
|
|
197f47befe | ||
|
|
d126611e87 | ||
|
|
1b75be5710 | ||
|
|
6272969983 | ||
|
|
084fc2fcd1 | ||
|
|
b2e68db380 | ||
|
|
459156fe57 | ||
|
|
7abfe68458 | ||
|
|
442d7a7226 | ||
|
|
80ebcb2c28 | ||
|
|
9735d1c6f3 | ||
|
|
ef017fd343 | ||
|
|
cd928bc586 | ||
|
|
d2b4d25317 | ||
|
|
a418cd2a2a | ||
|
|
94cdd88474 | ||
|
|
1bdf3876fc | ||
|
|
30435e6406 | ||
|
|
bd1c06a7a7 | ||
|
|
8358272b9a | ||
|
|
ff3cce0ed2 | ||
|
|
c3787af29d | ||
|
|
b3810a16cc | ||
|
|
38539aac74 | ||
|
|
58e8346209 | ||
|
|
ba9ce4adf2 | ||
|
|
a3a8fa1cef | ||
|
|
c6805271e9 | ||
|
|
bd60fe5a13 | ||
|
|
b72f3baab7 | ||
|
|
d1d54ce9c8 | ||
|
|
954f26308b | ||
|
|
1cafa0b33f | ||
|
|
18c17168e1 | ||
|
|
d3a97f1062 | ||
|
|
d18f078b1e | ||
|
|
9ffcde878a | ||
|
|
aa970d6ca5 | ||
|
|
503c68320a | ||
|
|
a106342439 | ||
|
|
00f5471270 | ||
|
|
3b0e6ec65c | ||
|
|
8691ddc081 | ||
|
|
f5199d2b73 | ||
|
|
0c8d9d5614 | ||
|
|
24c5935661 | ||
|
|
bff6697690 | ||
|
|
02405b4856 | ||
|
|
78b37b592e | ||
|
|
4db88cf86b | ||
|
|
a7e17eabff | ||
|
|
93d9ce18b2 | ||
|
|
6f7ac93d84 | ||
|
|
fa5d60ca26 | ||
|
|
20ed81cd86 | ||
|
|
6f38874096 | ||
|
|
b7db5be4df | ||
|
|
6d278994ec | ||
|
|
157dbffc59 | ||
|
|
f21ab3588d | ||
|
|
2900bda8f9 | ||
|
|
5f37c19d42 | ||
|
|
6f6356e617 | ||
|
|
5d152baac0 | ||
|
|
d7739f9764 | ||
|
|
d6e73fde50 | ||
|
|
fd149b3f46 | ||
|
|
d1d45e7166 | ||
|
|
4b19759dd6 | ||
|
|
47f44680a3 | ||
|
|
0a344ada97 | ||
|
|
3b98d01f71 | ||
|
|
23d8000239 | ||
|
|
c32ee40ca0 | ||
|
|
213f45494f | ||
|
|
85a51e6c42 | ||
|
|
ecfdc6f0a8 | ||
|
|
1c1c3fd832 | ||
|
|
7bafe995e5 | ||
|
|
3c23672347 | ||
|
|
33fe68d7eb | ||
|
|
b031fa1531 | ||
|
|
dab4dc3f41 | ||
|
|
78096803ea | ||
|
|
f1987b9544 | ||
|
|
8b6bf08a23 | ||
|
|
2640203c88 | ||
|
|
2dafa9644f | ||
|
|
92ebeddcb0 | ||
|
|
ecee073e08 | ||
|
|
6d1b9ffad2 | ||
|
|
7ee4b54154 | ||
|
|
e3271b8082 | ||
|
|
c6ff45f959 | ||
|
|
5d3f22e06a | ||
|
|
c77f6c5f7b | ||
|
|
6d03c3a54c | ||
|
|
92dc63e5c9 | ||
|
|
505d319e01 | ||
|
|
62f845a94e | ||
|
|
7a9eff7f35 | ||
|
|
b849ea8eaa | ||
|
|
f1635fa302 | ||
|
|
6110b72b87 | ||
|
|
247de600af | ||
|
|
3e60d3d96e | ||
|
|
6de617ecd5 | ||
|
|
7c8df97968 | ||
|
|
acf6736afd | ||
|
|
5f2480c3d9 | ||
|
|
0593a078c6 | ||
|
|
323c70dcdf | ||
|
|
a1b0f84444 | ||
|
|
df6c271830 | ||
|
|
12bf04826a | ||
|
|
52a1b0453c | ||
|
|
0dcb56eab5 | ||
|
|
a42f78b08b | ||
|
|
505768db04 | ||
|
|
c74db95c14 | ||
|
|
af3f27feae | ||
|
|
7b366d49d2 | ||
|
|
88b30e7e28 | ||
|
|
05c0febd04 | ||
|
|
9d70ec56f2 | ||
|
|
7f8ec59939 | ||
|
|
0398ec40b7 | ||
|
|
f55465f8b8 | ||
|
|
a4384bd340 | ||
|
|
a2368a75f7 | ||
|
|
68e5e74882 | ||
|
|
b2afac8914 | ||
|
|
0637c1c9d4 | ||
|
|
0453a5fb3d | ||
|
|
3ad56ea103 | ||
|
|
6322ab9f07 | ||
|
|
21d0f10dd7 | ||
|
|
51b9e81c3d | ||
|
|
7723011594 | ||
|
|
91c11a18e0 | ||
|
|
215ba35fe1 | ||
|
|
7e17011ebc | ||
|
|
1f25edc737 | ||
|
|
ab13db73e7 | ||
|
|
cb5eb9edc7 | ||
|
|
509675fe66 | ||
|
|
da5c12f466 | ||
|
|
f2ad10bbce | ||
|
|
99a7bece2e | ||
|
|
b305fd8865 | ||
|
|
c0beb621e2 | ||
|
|
da6d64e581 | ||
|
|
a6d58ee360 | ||
|
|
2a480ab7db | ||
|
|
5c09ee29db | ||
|
|
15526bd6e8 | ||
|
|
c8f48168b4 | ||
|
|
d937d473f9 | ||
|
|
66f14c6343 | ||
|
|
f25fadafd8 | ||
|
|
d9b0df94e2 | ||
|
|
200d11ca99 | ||
|
|
f8c48ef60a | ||
|
|
1fc0680c71 | ||
|
|
ec4afb2cbc | ||
|
|
a2a632c415 | ||
|
|
962e64106c | ||
|
|
c40b6088ee | ||
|
|
0d1a254ca8 | ||
|
|
fdbcb61a12 | ||
|
|
6435cb1466 | ||
|
|
4739cfab9a | ||
|
|
00a73e9cc8 | ||
|
|
0ff5dec004 | ||
|
|
07a15883bd | ||
|
|
2bd1e81917 | ||
|
|
755f91f5ab | ||
|
|
7603b5a56c | ||
|
|
7ef84cfbfe | ||
|
|
41129cf379 | ||
|
|
c8c394b4e9 | ||
|
|
59886a1528 | ||
|
|
a28d2c869f | ||
|
|
6f1fff44fa | ||
|
|
108978d1a5 | ||
|
|
a4733b4d91 | ||
|
|
66f4671ec0 | ||
|
|
c932621b5d | ||
|
|
21173dc907 | ||
|
|
f2c30ba3f7 | ||
|
|
989bdfb0d5 | ||
|
|
5761dce957 | ||
|
|
95e2e574b8 | ||
|
|
c789d80ce5 | ||
|
|
8422ffcd19 | ||
|
|
2d30535b69 | ||
|
|
0a815179a2 | ||
|
|
aa24e5d284 | ||
|
|
23aad24027 | ||
|
|
7ae5459fe7 | ||
|
|
0a8a88421e | ||
|
|
4f42a176ef | ||
|
|
4457067045 | ||
|
|
e7dc2048ad | ||
|
|
af6094bb06 | ||
|
|
0ab139cb24 | ||
|
|
500a7301f2 | ||
|
|
c92cef1780 | ||
|
|
49ceac1ac7 | ||
|
|
276a93605d | ||
|
|
0150c3fe23 | ||
|
|
34674501c3 | ||
|
|
f6206d4c30 | ||
|
|
6dcd9596a2 | ||
|
|
e165838e54 | ||
|
|
eae1707e97 | ||
|
|
ed2950f73b | ||
|
|
7eae8f68d8 | ||
|
|
0ab2d18b52 | ||
|
|
8ab621bc91 | ||
|
|
41e51bbeb5 | ||
|
|
66d9e8c038 | ||
|
|
f5e47b2b74 | ||
|
|
678a823e8b | ||
|
|
246746a82e | ||
|
|
00038453e1 | ||
|
|
9ce485eade | ||
|
|
8a6ff5a42b | ||
|
|
1eaac0072d | ||
|
|
35716a7e4c | ||
|
|
e0f89beebb | ||
|
|
b8bf2a707c | ||
|
|
7d616be8f4 | ||
|
|
0a7e9f9f8f | ||
|
|
226e188903 | ||
|
|
590d454119 | ||
|
|
06d5bd799f | ||
|
|
7fe6541b7c | ||
|
|
0f30fa5fb9 | ||
|
|
2c362315ad | ||
|
|
7dd79edc52 | ||
|
|
3d6f25a9d3 | ||
|
|
b3c21feba3 | ||
|
|
fe54fadbf8 | ||
|
|
caa0722d49 | ||
|
|
fee32622f1 | ||
|
|
d1910e4274 | ||
|
|
45eb11d7f4 | ||
|
|
874179fa75 | ||
|
|
8b16cb4bae | ||
|
|
777ed55c21 | ||
|
|
fcafd8b05e | ||
|
|
5f1cadfea4 | ||
|
|
917a981096 | ||
|
|
89f8b6060f | ||
|
|
345346315a | ||
|
|
f1c27e1798 | ||
|
|
4316024dc7 | ||
|
|
ca05aa84ff | ||
|
|
d10d7dc298 | ||
|
|
063af1dbc7 | ||
|
|
ef6fe43251 | ||
|
|
2659055c31 | ||
|
|
f5ed757780 | ||
|
|
e114b842ba | ||
|
|
12e2116acb | ||
|
|
bccc97d25f | ||
|
|
a9bcc75733 | ||
|
|
7b87475af8 | ||
|
|
2ac218886a | ||
|
|
97503897f0 | ||
|
|
7e06e32cb6 | ||
|
|
15b813c6af | ||
|
|
a71c9107bd | ||
|
|
4c2110189b | ||
|
|
df750c2a71 | ||
|
|
3eb412b750 | ||
|
|
5c7b7e4182 | ||
|
|
2b0fad87d2 | ||
|
|
8817d41275 | ||
|
|
04ef3f9496 | ||
|
|
fbe26e13ae | ||
|
|
4408dffa87 | ||
|
|
546192865c | ||
|
|
7afa550ba4 | ||
|
|
21a9372320 | ||
|
|
f4a2eec984 | ||
|
|
94b9455c9c | ||
|
|
c41c71c8c1 | ||
|
|
dde647c570 | ||
|
|
445a89ba6e | ||
|
|
07495f6621 | ||
|
|
5952edc550 | ||
|
|
b66a038a2f | ||
|
|
df1c8a64e5 | ||
|
|
3e2aebcd10 | ||
|
|
0d279cb4dd | ||
|
|
3942a76d15 | ||
|
|
1bebf3d3d6 | ||
|
|
d5f54c240a | ||
|
|
8868ecd11a | ||
|
|
8a31c57bfa | ||
|
|
7e2cce4a8d | ||
|
|
bfb217c203 | ||
|
|
593e55af95 | ||
|
|
29af62f956 | ||
|
|
2b022e1871 | ||
|
|
783a4d3996 | ||
|
|
ddfe925f8c | ||
|
|
1735bcab21 | ||
|
|
ff6cacf766 | ||
|
|
2a72eae77f | ||
|
|
39fb7fdfe3 | ||
|
|
e0facf35c8 | ||
|
|
73d48c8ac4 | ||
|
|
5080059143 | ||
|
|
90d5b77d74 | ||
|
|
e0f987328b | ||
|
|
04c3a925cc | ||
|
|
219b29991b | ||
|
|
5120045459 | ||
|
|
3bca4a73f4 | ||
|
|
b4857ab036 | ||
|
|
f3ae041691 | ||
|
|
a84627a465 | ||
|
|
78aeca6399 | ||
|
|
5dd8f0a0b7 | ||
|
|
9378fc7276 | ||
|
|
3a0d8069b6 | ||
|
|
bab42014a4 | ||
|
|
74fed5695f | ||
|
|
3be368c333 | ||
|
|
a4a8e2614e | ||
|
|
58eb151ba1 | ||
|
|
21d21ea7f0 | ||
|
|
45dc5e236d | ||
|
|
0597eeed6b | ||
|
|
0a66fe196a | ||
|
|
3f21b4aa7d | ||
|
|
b97186c5bf | ||
|
|
874b24fb32 | ||
|
|
97889b5e55 | ||
|
|
4b134194cf | ||
|
|
24b60a25d5 | ||
|
|
3e069376a7 | ||
|
|
5bdb2c9e86 | ||
|
|
71b0c5f805 | ||
|
|
a1f62e7a1f | ||
|
|
186c40801a | ||
|
|
bf867e84d6 | ||
|
|
27035a8e1d | ||
|
|
db3770c3e5 | ||
|
|
46337ca554 | ||
|
|
4f0f288000 | ||
|
|
8060bae1b8 | ||
|
|
ea32c97b82 | ||
|
|
99efbd30f1 | ||
|
|
a9eb7cb4fd | ||
|
|
a11cab0f88 | ||
|
|
447324b59f | ||
|
|
e580e815f0 | ||
|
|
5fc00840f2 | ||
|
|
ff59dcd66e | ||
|
|
0a1d82de2a | ||
|
|
26837645ac | ||
|
|
c318699d6a | ||
|
|
e5caab635a | ||
|
|
d5f96295ff | ||
|
|
4a6c78aaf3 | ||
|
|
c4d214f5c0 | ||
|
|
1ed7e6cb1c | ||
|
|
6b7f80f24a | ||
|
|
220217561a | ||
|
|
75e857a510 | ||
|
|
052bdd8eb0 | ||
|
|
9e54de8a8a | ||
|
|
fd2809e367 | ||
|
|
18874c2069 | ||
|
|
115eb0ddef | ||
|
|
9940258725 | ||
|
|
74e14a4fc3 | ||
|
|
90ea386c62 | ||
|
|
a5b132dfd7 | ||
|
|
157debf8e4 | ||
|
|
74a5528f17 | ||
|
|
21de9e938a | ||
|
|
9c4d3cd6e2 | ||
|
|
0616d184e0 | ||
|
|
6f8b3a6242 | ||
|
|
9a006dc84a | ||
|
|
d2dbaf52a1 | ||
|
|
0a9145cd3c | ||
|
|
e778b02c0c | ||
|
|
8fb5f0ef3c | ||
|
|
43f5e4360d | ||
|
|
cdc8640218 | ||
|
|
21f8d7a967 | ||
|
|
801d92bbba | ||
|
|
77116172e4 | ||
|
|
9d3c0f4ff0 | ||
|
|
6382d2b730 | ||
|
|
6ad4493a91 | ||
|
|
f070dc5527 | ||
|
|
fc6e7c81d3 | ||
|
|
59a725c52c | ||
|
|
51b3d7cb4a | ||
|
|
3baff4e675 | ||
|
|
06911e7ad0 | ||
|
|
4e0f3e35db | ||
|
|
fd6ce57003 | ||
|
|
4f55be4f19 | ||
|
|
bd20c83919 | ||
|
|
48f8a45031 | ||
|
|
680cec5abb | ||
|
|
e8b3c66c21 | ||
|
|
ecdc3be52e | ||
|
|
301bdf2186 | ||
|
|
1c1b67e000 | ||
|
|
662870baf4 | ||
|
|
bc85520f5e | ||
|
|
d3be7a3edf | ||
|
|
6cd0da821a | ||
|
|
1333c41811 | ||
|
|
55eceb4080 | ||
|
|
e95629f827 | ||
|
|
6332ee6edb | ||
|
|
901d56f898 | ||
|
|
010c3494fd | ||
|
|
5ebc345e95 | ||
|
|
b3a768a04b | ||
|
|
f414af4d82 | ||
|
|
b743ca8eb1 | ||
|
|
a3a5bffce4 | ||
|
|
7971f3cbd8 | ||
|
|
d1b80aa4d4 | ||
|
|
08d9f7d967 | ||
|
|
5f62b4a89d | ||
|
|
776502e6db | ||
|
|
39e0a1fb9e | ||
|
|
5ed02d2f0d | ||
|
|
72e864b013 | ||
|
|
5ab012163e | ||
|
|
1900686bc4 | ||
|
|
809a294f9d | ||
|
|
cf3f6ede72 | ||
|
|
b76a90304d | ||
|
|
7af5b24b03 | ||
|
|
1f81fb9284 | ||
|
|
4e105492ca | ||
|
|
abf7dd5fa8 | ||
|
|
6c877b6d44 | ||
|
|
86d2998dc0 | ||
|
|
201daf8ff3 | ||
|
|
1140f5f6cb | ||
|
|
0a91d60677 | ||
|
|
5cd8f5681e | ||
|
|
b2babd9502 | ||
|
|
10faaaf531 | ||
|
|
7642c5a50d | ||
|
|
42dba3170d | ||
|
|
5c90a742ba | ||
|
|
9e57ef074d | ||
|
|
9e9b1c3c98 | ||
|
|
13d5deddec | ||
|
|
8522760c70 | ||
|
|
5bc2282ac5 | ||
|
|
2944b2a8f6 | ||
|
|
264480b9bc | ||
|
|
7d52cc46dc | ||
|
|
37c9fd278c | ||
|
|
3d6fe0a565 | ||
|
|
da488f76d2 | ||
|
|
6d28de77d1 | ||
|
|
a8bd46c521 | ||
|
|
1ec3a74d4c | ||
|
|
076449a33d | ||
|
|
1b5cc2abf1 | ||
|
|
b176225910 | ||
|
|
082d1eea48 | ||
|
|
e99dfbae0d | ||
|
|
d6735bed4f | ||
|
|
b024d93fa0 | ||
|
|
dbe8554724 | ||
|
|
9f79e64678 | ||
|
|
f513cae66e | ||
|
|
37b807210e | ||
|
|
15e26ba929 | ||
|
|
db1795981f | ||
|
|
2a40baf509 | ||
|
|
2dbf72e452 | ||
|
|
67ae716c60 | ||
|
|
8dfb130d19 | ||
|
|
2a42fea32a | ||
|
|
f69edefddf | ||
|
|
6f3b5fc559 | ||
|
|
7275a34e1f | ||
|
|
687e2ecaaa | ||
|
|
64312aedae | ||
|
|
391876e557 | ||
|
|
cb95a7d418 | ||
|
|
830f806dee | ||
|
|
21c2316f6b | ||
|
|
930a1ae450 | ||
|
|
aec331b5a6 | ||
|
|
1db6c281b1 | ||
|
|
5b70ca81a7 | ||
|
|
d00df785a5 | ||
|
|
d0c6e7a285 | ||
|
|
058995a0b6 | ||
|
|
fd3be887b4 | ||
|
|
84802d9065 | ||
|
|
90d696d826 | ||
|
|
aeb9e2ad9f | ||
|
|
26ab1bfd4f | ||
|
|
23d44cb28b | ||
|
|
de4b352495 | ||
|
|
d635117194 | ||
|
|
c0412d368e | ||
|
|
7ec30f0796 | ||
|
|
9815a55221 | ||
|
|
7c108e5128 | ||
|
|
4873031c37 | ||
|
|
15d23870c1 | ||
|
|
2abbf7e762 | ||
|
|
1578aa7cb6 | ||
|
|
f2230751e7 | ||
|
|
8fc0dda26d | ||
|
|
0ab71badfa | ||
|
|
0f24d924f9 | ||
|
|
518a0de95f | ||
|
|
fa5648c0c3 | ||
|
|
bd620a764d | ||
|
|
cff42b5d27 | ||
|
|
25eef2a40e | ||
|
|
db276d5f1f | ||
|
|
ce0d906c35 | ||
|
|
520826abc0 | ||
|
|
5e1d6014d5 | ||
|
|
32af17317c | ||
|
|
3e7cc8a0a0 | ||
|
|
f717ce52fa | ||
|
|
d880f3c628 | ||
|
|
0a97717b35 | ||
|
|
029403ea10 | ||
|
|
e4ec65622f | ||
|
|
3ee3b97255 | ||
|
|
a3dd6ce891 | ||
|
|
0c97d7701e | ||
|
|
b852b6f55c | ||
|
|
d3b7b857a4 | ||
|
|
63ad3f9290 | ||
|
|
40cc30e054 | ||
|
|
23374e98ae | ||
|
|
40f544fffc | ||
|
|
4fc69c9a2c | ||
|
|
2e5a485804 | ||
|
|
2d10b5be90 | ||
|
|
b0d0bb7953 | ||
|
|
8c69b85280 | ||
|
|
9d6d1e4ff8 | ||
|
|
e71c72b4a2 | ||
|
|
bf4b29b3e3 | ||
|
|
8e0809ceba | ||
|
|
230af48899 | ||
|
|
9dc459192e | ||
|
|
8de2301c6b | ||
|
|
f66b343edd | ||
|
|
ff82d36e94 | ||
|
|
c3e937f5e0 | ||
|
|
25c5e823d9 | ||
|
|
528b8b1271 | ||
|
|
b88344a6c0 | ||
|
|
9e135cc81d | ||
|
|
72ef288357 | ||
|
|
426ac29ca5 | ||
|
|
ceb330e3e4 | ||
|
|
7ea8f741f2 | ||
|
|
443c9fba03 | ||
|
|
0227f79bd7 | ||
|
|
2812eaa13d | ||
|
|
cb293fcdb3 | ||
|
|
706428fe98 | ||
|
|
698f5f951e | ||
|
|
155c12f657 | ||
|
|
a36c731d15 | ||
|
|
6a793536dd | ||
|
|
27532a4237 | ||
|
|
467f69f50e | ||
|
|
32e724e744 | ||
|
|
5fb891c495 | ||
|
|
d56cefdc7a | ||
|
|
80c67d37c0 | ||
|
|
1e29d9463e | ||
|
|
75f6a53269 | ||
|
|
b5a8f3156c | ||
|
|
de245c08ce | ||
|
|
76a7f25083 | ||
|
|
d9a96fbb29 | ||
|
|
16617660c3 | ||
|
|
a83d9a075f | ||
|
|
eca3fb1e19 | ||
|
|
41bc799c3f | ||
|
|
44726c7411 | ||
|
|
8f7f9ec367 | ||
|
|
21de8f2284 | ||
|
|
15797a89e7 | ||
|
|
c340a1d47f | ||
|
|
71cec39bc4 | ||
|
|
882542318c | ||
|
|
7238ef4f55 | ||
|
|
1049d65621 | ||
|
|
552ae836e9 | ||
|
|
1852c0a88c | ||
|
|
d0d399bdfc | ||
|
|
3975fe0f02 | ||
|
|
0739cfc240 | ||
|
|
f31bf4f7c9 | ||
|
|
f413671915 | ||
|
|
e67a210e95 | ||
|
|
51dfa9a247 | ||
|
|
7c121b8ba6 | ||
|
|
ae92a5c25e | ||
|
|
fabd3b8421 | ||
|
|
94d754e63a | ||
|
|
f869542a47 | ||
|
|
2b616b688d | ||
|
|
0925ea6f9c | ||
|
|
87b5565679 | ||
|
|
adcecf969a | ||
|
|
f3831665d4 | ||
|
|
9db8d44654 | ||
|
|
e1075a3bbf | ||
|
|
3b6f499fc5 | ||
|
|
2c1fbe103b | ||
|
|
1543862f3b | ||
|
|
5b7b34a9f0 | ||
|
|
fb6271eecf | ||
|
|
031526b619 | ||
|
|
e42ca2dbf2 | ||
|
|
4f5816f42e | ||
|
|
555d0d3378 | ||
|
|
1495b756d3 | ||
|
|
7f78d00b97 | ||
|
|
bfd58b3cdf | ||
|
|
e260b9473a | ||
|
|
ccc56d446f | ||
|
|
31a4e38bc0 | ||
|
|
284366e6bb | ||
|
|
9c6dda9bd2 | ||
|
|
e5f6f8dfa7 | ||
|
|
0232117de5 | ||
|
|
96700fe3d1 | ||
|
|
367a4e17a2 | ||
|
|
eba0d7c1e0 | ||
|
|
341a4a0d60 | ||
|
|
d116424241 | ||
|
|
db881ee011 | ||
|
|
34bed44a9b | ||
|
|
d431aa4b59 | ||
|
|
2512bebc62 | ||
|
|
309dbd7585 | ||
|
|
a1f28caa8e | ||
|
|
4204393337 | ||
|
|
789e34702b | ||
|
|
47bc1bf88d | ||
|
|
9867227ccd | ||
|
|
26302d478e | ||
|
|
0decf94c9c | ||
|
|
0ae78efd43 | ||
|
|
b5af6b0bf9 | ||
|
|
3eabefd3d6 | ||
|
|
7ff6a6e0e7 | ||
|
|
94dc611024 | ||
|
|
0b28107432 | ||
|
|
fe717dad7f | ||
|
|
fb3816e2e5 | ||
|
|
535bf4c848 | ||
|
|
1fc60b0682 | ||
|
|
302f1ee8e3 | ||
|
|
42aec56b8e | ||
|
|
199c00c59b | ||
|
|
107bb14555 | ||
|
|
5820792013 | ||
|
|
0e20248494 | ||
|
|
c4f4b247bc | ||
|
|
0d66bc49c2 | ||
|
|
bdc78a826f | ||
|
|
6570062e61 | ||
|
|
820facb833 | ||
|
|
a933fcf7e2 | ||
|
|
2d3039c6a2 | ||
|
|
aca01044f4 | ||
|
|
dffd1b1d69 | ||
|
|
14fc64f2f1 | ||
|
|
04791d06d0 | ||
|
|
a485451328 | ||
|
|
c7d399c122 | ||
|
|
df155bed89 | ||
|
|
3ee3630d22 | ||
|
|
6b2911b8c8 | ||
|
|
d474200d7f | ||
|
|
cc6f6277f6 | ||
|
|
0521e988bc | ||
|
|
832ff39eb6 | ||
|
|
134798e82f | ||
|
|
b6f43966ea | ||
|
|
1dab26bcbc | ||
|
|
afa7be6fdc | ||
|
|
36290c20aa | ||
|
|
c33c7eb68e | ||
|
|
5da33afecd | ||
|
|
a49b49aaa9 | ||
|
|
225fd0d05b | ||
|
|
c43b4f9cf0 | ||
|
|
3581f4c87e | ||
|
|
7a4e0cc850 | ||
|
|
ba49da75de | ||
|
|
f329a5950e | ||
|
|
d95158003c | ||
|
|
1be6223a31 | ||
|
|
76178b423e | ||
|
|
195e537499 | ||
|
|
418abc2b0a | ||
|
|
277f0346f2 | ||
|
|
6148cbb122 | ||
|
|
3847bfc41a | ||
|
|
783424dd26 | ||
|
|
4c1861dd27 | ||
|
|
7f6486c77d | ||
|
|
1b2a50f9a3 | ||
|
|
5dadf92a62 | ||
|
|
76821addd7 | ||
|
|
a769c55c72 | ||
|
|
347ec91bfc | ||
|
|
4245767357 | ||
|
|
74d196ad50 | ||
|
|
3c4649748d | ||
|
|
22985900a8 | ||
|
|
86300a8e3c | ||
|
|
32ab2ae201 | ||
|
|
23e4a2e28e | ||
|
|
40515e62ac | ||
|
|
b56490650c | ||
|
|
b5751795b5 | ||
|
|
43d6151506 | ||
|
|
8ccfb606c0 | ||
|
|
3b74cd5676 | ||
|
|
26e766ee19 | ||
|
|
6f96dc8f23 | ||
|
|
1c3fdb73fb | ||
|
|
332be7edd6 | ||
|
|
76e0e935f0 | ||
|
|
7e6eb65950 | ||
|
|
b0a56a431b | ||
|
|
166316e0c5 | ||
|
|
4194e66d81 | ||
|
|
c9b9d86892 | ||
|
|
f2d00e6e42 | ||
|
|
acfc166a11 | ||
|
|
3255382132 | ||
|
|
25831bfb60 | ||
|
|
d011ca0626 | ||
|
|
5eadbe7ecd | ||
|
|
ea7e0c6204 | ||
|
|
2dcb126e6d | ||
|
|
438525e8ec | ||
|
|
eb66a403d9 | ||
|
|
26ac612474 | ||
|
|
2e28df3e8a | ||
|
|
43613e3b10 | ||
|
|
555dd2e726 | ||
|
|
3260f46543 | ||
|
|
f9de23402a | ||
|
|
9e155cf94a | ||
|
|
dcace43ce2 | ||
|
|
527e3d6cd0 | ||
|
|
befce5b887 | ||
|
|
9929c96650 | ||
|
|
c7d45c28cf | ||
|
|
87cc3fd714 | ||
|
|
282d58a6fe | ||
|
|
b4aec91d67 | ||
|
|
d2a149ee23 | ||
|
|
8a72f94b3d | ||
|
|
fc4ed1c50b | ||
|
|
ae1d0a18f3 | ||
|
|
9709ca331e | ||
|
|
b4a9641c31 | ||
|
|
cc68e6b6e6 | ||
|
|
60c47cfca1 | ||
|
|
720abd4e04 | ||
|
|
b4fe694d1b | ||
|
|
c117785554 | ||
|
|
a9d6a15924 | ||
|
|
e9723de6c3 | ||
|
|
b8c61b5236 | ||
|
|
da0cf01eee | ||
|
|
b77e1eb94b | ||
|
|
e40f266042 | ||
|
|
69fb15d3cb | ||
|
|
188956a4af | ||
|
|
c7dd4a7f2b | ||
|
|
111f1729c9 | ||
|
|
164372b46a | ||
|
|
1af3794fed | ||
|
|
885f4ded0c | ||
|
|
9bb018d8d9 | ||
|
|
58187e00e6 | ||
|
|
5110a8c636 | ||
|
|
ddbe883d47 | ||
|
|
945ac82b6a | ||
|
|
84148ad07a | ||
|
|
25553a28a1 | ||
|
|
c2f5846a8e | ||
|
|
3f98e9451a | ||
|
|
6c72194346 | ||
|
|
822dd24756 | ||
|
|
262ed38429 | ||
|
|
5ff66ce4dd | ||
|
|
ca73b8e0b8 | ||
|
|
2d49ace0e3 | ||
|
|
d52f22044e | ||
|
|
2bf052aac9 | ||
|
|
a79c9d5f4f | ||
|
|
6f9bcf1858 | ||
|
|
d1b00ba95d | ||
|
|
bb45bee7f8 | ||
|
|
246f0b21fd | ||
|
|
394443b6d1 | ||
|
|
fc1dd2daac | ||
|
|
ba1b6f321e | ||
|
|
06402cf1c6 | ||
|
|
dfc33389d8 | ||
|
|
4e83752655 | ||
|
|
7e28718681 | ||
|
|
bf452e922a | ||
|
|
4911a74cac | ||
|
|
a2bda5a4db | ||
|
|
800abc605f | ||
|
|
ac83b67632 | ||
|
|
00bc7dccb9 | ||
|
|
04aa9f0e61 | ||
|
|
353e97a4c1 | ||
|
|
7b28387bb4 | ||
|
|
1889fe23c5 | ||
|
|
9832fbe042 | ||
|
|
084070475d | ||
|
|
cb42ca8765 | ||
|
|
45d7e66488 | ||
|
|
93a1616933 | ||
|
|
9a87a2ff0d | ||
|
|
bdff05feaf | ||
|
|
937e3d0b94 | ||
|
|
8503aba583 | ||
|
|
bb8223d4ff | ||
|
|
af3c8f66f7 | ||
|
|
3097a1b17e | ||
|
|
54b80f74b2 | ||
|
|
9a78d28cd7 | ||
|
|
5df197e814 | ||
|
|
5fe09e9787 | ||
|
|
6be5360bdd | ||
|
|
2b9007958b | ||
|
|
2f9c126d34 | ||
|
|
1ed817932b | ||
|
|
0ccadb246f | ||
|
|
b67235a7e5 | ||
|
|
93853613bd | ||
|
|
1ecb4fedcc | ||
|
|
c8fdf3731a | ||
|
|
f8e766ffc0 | ||
|
|
050489dd80 | ||
|
|
2db966ba47 | ||
|
|
aa54d65f63 | ||
|
|
37dc17ae15 | ||
|
|
cd6b3d7dee | ||
|
|
aec0bc5029 | ||
|
|
e010e67717 | ||
|
|
44197d91c6 | ||
|
|
e3ee48b52e | ||
|
|
8ccf349458 | ||
|
|
2fce15db94 | ||
|
|
0cf50e8000 | ||
|
|
5b9630cf46 | ||
|
|
7dcbb409a9 | ||
|
|
286e057fae | ||
|
|
7d4fe341f1 | ||
|
|
76acb7bb58 | ||
|
|
5ef7cd7bdd | ||
|
|
ebb4628e66 | ||
|
|
0928060c75 | ||
|
|
d8f9a9a03c | ||
|
|
abfb8bbc34 | ||
|
|
82e01f7b17 | ||
|
|
a97609e920 | ||
|
|
f1e1bd41b9 | ||
|
|
57d35858d8 | ||
|
|
0b956c66c1 | ||
|
|
b1dfa1db61 | ||
|
|
cb579ecc62 | ||
|
|
ae235aa58c | ||
|
|
6302056182 | ||
|
|
5e20abd7f1 | ||
|
|
72a72dbc88 | ||
|
|
4766666913 | ||
|
|
fa6070c680 | ||
|
|
6267d11e51 | ||
|
|
822298ab66 | ||
|
|
2ad3ab7f0d | ||
|
|
f437fd6cd6 | ||
|
|
42b247756a | ||
|
|
fbbf2d5eb3 | ||
|
|
788a276616 | ||
|
|
196779ffb6 | ||
|
|
59a144baed | ||
|
|
ad825b80b0 | ||
|
|
45a0061660 | ||
|
|
8831c76fb4 | ||
|
|
66616e1cab | ||
|
|
fa281a0df0 | ||
|
|
d48a96599f | ||
|
|
7de7ef8e8c | ||
|
|
406a254523 | ||
|
|
eabd6f60ef | ||
|
|
e416d06aa9 | ||
|
|
65e073e6b8 | ||
|
|
45ac0d5dc6 | ||
|
|
c9ef034ab8 | ||
|
|
c89f38f4f8 | ||
|
|
858b57d77a | ||
|
|
9b87892036 | ||
|
|
ed69692f08 | ||
|
|
7119999df8 | ||
|
|
c16462a0ce | ||
|
|
272f96b405 | ||
|
|
3e519001a3 | ||
|
|
f442aad962 | ||
|
|
fa9b151c36 | ||
|
|
481bd6f57a | ||
|
|
f015227fc8 | ||
|
|
61ba16b779 | ||
|
|
f6e86bfcf8 | ||
|
|
498dd76730 | ||
|
|
ebd909dfe7 | ||
|
|
067ed1258b | ||
|
|
ef3c72a24f | ||
|
|
b257f476c9 | ||
|
|
d3af2be79a | ||
|
|
94aeb19245 | ||
|
|
e4ee392c27 | ||
|
|
cf48ad06ed | ||
|
|
63df85f7f9 | ||
|
|
b29611509e | ||
|
|
dd1cf0ec56 | ||
|
|
c04c73bbd7 | ||
|
|
0d287283d4 | ||
|
|
4ea5723b7f | ||
|
|
ea964124d6 | ||
|
|
75244853c1 | ||
|
|
c361c34b16 | ||
|
|
264b3a785b | ||
|
|
bb15e1d8ac | ||
|
|
68860ae866 | ||
|
|
61637f12c7 | ||
|
|
7538649e81 | ||
|
|
31efbe915e | ||
|
|
9e69627626 | ||
|
|
dd9da2853a | ||
|
|
b4f08fa8d5 | ||
|
|
670461c66f | ||
|
|
f6092b9128 | ||
|
|
a690cb36ff | ||
|
|
5ca8f4a3aa | ||
|
|
ba6e2f0a54 | ||
|
|
149f4e38a0 | ||
|
|
b5ee170726 | ||
|
|
04961880fe | ||
|
|
e22e8ffa0e | ||
|
|
d18d800947 | ||
|
|
3ca58ee65f | ||
|
|
21387b9a83 | ||
|
|
ccb0d491ed | ||
|
|
daa3200713 | ||
|
|
fec2d1f7ee | ||
|
|
eb8e95723c | ||
|
|
999bec19f1 | ||
|
|
dfb8de2349 | ||
|
|
59f1cdcc82 | ||
|
|
3eb8be6239 | ||
|
|
7dfc4a651d | ||
|
|
189d145393 | ||
|
|
26bec11d76 | ||
|
|
1e7071bff3 | ||
|
|
92390d1d59 | ||
|
|
b9b072119b | ||
|
|
b6d9fd8030 | ||
|
|
d383bc93c7 | ||
|
|
af88c68fca | ||
|
|
24537c4fdc | ||
|
|
130f495fb6 | ||
|
|
9d22a06969 | ||
|
|
e3783e0236 | ||
|
|
a5161eb7f1 | ||
|
|
82e448de7c | ||
|
|
680afe972e | ||
|
|
69ab2ce402 | ||
|
|
4374930065 | ||
|
|
9f3520cba5 | ||
|
|
d20cdc099d | ||
|
|
926e9ff3de | ||
|
|
70c277d8a1 | ||
|
|
0a5aac724a | ||
|
|
bb91d5495f | ||
|
|
995d94c124 | ||
|
|
ee7036f13d | ||
|
|
5a8a8dc292 | ||
|
|
7d84de6690 | ||
|
|
3520f9e9c2 | ||
|
|
b2df7981a9 | ||
|
|
9831e7bc3b | ||
|
|
90e37439e5 | ||
|
|
65f2490e89 | ||
|
|
c14a921e5a | ||
|
|
2bc8ffefce | ||
|
|
b88d8c85cb | ||
|
|
693f52d984 | ||
|
|
56a3bff42e | ||
|
|
bffeec1615 | ||
|
|
e4a9f115cb | ||
|
|
a717238f76 | ||
|
|
4a567ab97c | ||
|
|
90431b662b | ||
|
|
1c8f349a62 | ||
|
|
217004c70c | ||
|
|
a75608628e | ||
|
|
33130f39ee | ||
|
|
cae43e97cd | ||
|
|
cdfc0f6b71 | ||
|
|
bf6a18a414 | ||
|
|
16b66afa7a | ||
|
|
9e446210fb | ||
|
|
b0118d2d57 | ||
|
|
bc90309dd6 | ||
|
|
52c4093fb0 | ||
|
|
b47c12cbee | ||
|
|
fb14bc6016 | ||
|
|
cd6862b1a7 | ||
|
|
3d9160f2fa | ||
|
|
157a5d9902 | ||
|
|
f4972e2be2 | ||
|
|
85c8e6ba42 | ||
|
|
8e79bd8785 | ||
|
|
1ace7ce254 | ||
|
|
a00be5b60c | ||
|
|
aabe8d1d5e | ||
|
|
3da086438b | ||
|
|
c257c86387 | ||
|
|
ff3ae14c29 | ||
|
|
cd82a34392 | ||
|
|
baacd55910 | ||
|
|
511b7c4d92 | ||
|
|
f38851b7c6 | ||
|
|
432c5837f0 | ||
|
|
cc599f544a | ||
|
|
e886c85134 | ||
|
|
05eb716b85 | ||
|
|
61eb7b0a6a | ||
|
|
f0dade5856 | ||
|
|
8567f6b13c | ||
|
|
b740316918 | ||
|
|
2119d08543 | ||
|
|
599ff66522 | ||
|
|
6d2eb04ada | ||
|
|
0aea75edb7 | ||
|
|
2ca8231ab4 | ||
|
|
e00116551c | ||
|
|
4d55e05b07 | ||
|
|
9ff3f85432 | ||
|
|
65c584aeda | ||
|
|
2540a2dfd9 | ||
|
|
70e9187bcb | ||
|
|
5e2fa13471 | ||
|
|
4f8610f895 | ||
|
|
95f9e97af8 | ||
|
|
695b073080 | ||
|
|
3a28935bfe | ||
|
|
468ed1a9ce | ||
|
|
a6052d7900 | ||
|
|
e42836b07f | ||
|
|
16373919d4 | ||
|
|
92f9c908f6 | ||
|
|
480e1e17c8 | ||
|
|
274f5f2f1f | ||
|
|
02d4f9cbba | ||
|
|
d10daf0991 | ||
|
|
8c9656b799 | ||
|
|
396ea3d0ee | ||
|
|
3efee4a855 | ||
|
|
ece6759fa7 | ||
|
|
246d945f39 | ||
|
|
4a3bc486d0 | ||
|
|
996d041581 | ||
|
|
d48e4adcd4 | ||
|
|
7f84b7ab83 | ||
|
|
3e26bd6a17 | ||
|
|
e964c62907 | ||
|
|
fbb4965263 | ||
|
|
88139d95a7 | ||
|
|
5875b1988b | ||
|
|
2a2091595b | ||
|
|
d77883dd7a | ||
|
|
adea7dadec | ||
|
|
cf4ce2dc08 | ||
|
|
e74dfb2ba6 | ||
|
|
aaea9ff018 | ||
|
|
206b88eba2 | ||
|
|
8f5373f034 | ||
|
|
dfa0a16487 | ||
|
|
8b9f6f49ef | ||
|
|
bcac978810 | ||
|
|
d17a41f7f1 | ||
|
|
503f71f004 | ||
|
|
4543288ea7 | ||
|
|
9307105b3f | ||
|
|
567daf9946 | ||
|
|
558b22c36a | ||
|
|
f076dddfe3 | ||
|
|
af44730418 | ||
|
|
4ec1140cb4 | ||
|
|
2a5d20058f | ||
|
|
51f38e0a76 | ||
|
|
54eb42d658 | ||
|
|
a7a6f4cec6 | ||
|
|
3968a8e0dc | ||
|
|
9e8ff27a7f | ||
|
|
7dd3d2b040 | ||
|
|
13678cb8d5 | ||
|
|
890aa6f9ac | ||
|
|
646cf44b83 | ||
|
|
bf789ca97b | ||
|
|
9b90ff10f4 | ||
|
|
0cc719a823 | ||
|
|
4cd026dfe9 | ||
|
|
3120b49dba | ||
|
|
fb1999c474 | ||
|
|
2c37961f7b | ||
|
|
1abc863f82 | ||
|
|
c9be03c0bc | ||
|
|
fd89209233 | ||
|
|
2e362fbb64 | ||
|
|
11b687cdc2 | ||
|
|
747c920420 | ||
|
|
cac51737cb | ||
|
|
7789379914 | ||
|
|
08e2bfe9a2 | ||
|
|
56a854ec88 | ||
|
|
de4ff4e58d | ||
|
|
991c2afedb | ||
|
|
cded92662f | ||
|
|
2c3fa0fd8f | ||
|
|
ec08432f92 | ||
|
|
1bab4d6937 | ||
|
|
d1fed11d0d | ||
|
|
e96053e268 | ||
|
|
9b98cbb894 | ||
|
|
349578fb6e | ||
|
|
7c186e4fcc | ||
|
|
a4fcbb9f67 | ||
|
|
763b64cc57 | ||
|
|
d57e6c5bf2 | ||
|
|
80711cc00a | ||
|
|
8b61b9ebfe | ||
|
|
e00e778bce | ||
|
|
81e70925c4 | ||
|
|
ddd32bd600 | ||
|
|
2713573b9b | ||
|
|
cf2e8bbc0b | ||
|
|
bc56c1a0e1 | ||
|
|
bfbf7af411 | ||
|
|
c151221d12 | ||
|
|
b8489724ef | ||
|
|
7a2f556682 | ||
|
|
92d883db87 | ||
|
|
cb931d7af0 | ||
|
|
6b54b57cb9 | ||
|
|
1ca4348ca0 | ||
|
|
3ca7006e3a | ||
|
|
339d2a7bf3 | ||
|
|
0d3debf9b9 | ||
|
|
7f74a4f4b5 | ||
|
|
220718cb58 | ||
|
|
be2acbd3eb | ||
|
|
9249c74b7b | ||
|
|
2b87817ba2 | ||
|
|
883c0f9dfe | ||
|
|
3ffc58d442 | ||
|
|
1bb4b0156f | ||
|
|
92d2be3f5e | ||
|
|
a7cded21f7 | ||
|
|
74156b7ed8 | ||
|
|
821f320347 | ||
|
|
eee9274098 | ||
|
|
8dd1f89225 | ||
|
|
f2459ea904 | ||
|
|
e51f7bfbff | ||
|
|
e2215ced34 | ||
|
|
b14c8e82a0 | ||
|
|
e7d50d2614 | ||
|
|
bca92883d2 | ||
|
|
ed865e38de | ||
|
|
dec45109d3 | ||
|
|
48c267c5c1 | ||
|
|
c041d39cab | ||
|
|
52c18e77ae | ||
|
|
52a189cdd2 | ||
|
|
dca8a47da8 | ||
|
|
6be9317fd7 | ||
|
|
bee99ca8d0 | ||
|
|
48dc89cf13 | ||
|
|
fc7f609234 | ||
|
|
0bed9b3c2e | ||
|
|
31fa73518b | ||
|
|
c6fd11157a | ||
|
|
ca73a57de7 | ||
|
|
38a545af92 | ||
|
|
b91b340afd | ||
|
|
8e7b1c97df | ||
|
|
c9c55fe0c9 | ||
|
|
d553160d65 | ||
|
|
b8a4df2f50 | ||
|
|
36edbf6ea9 | ||
|
|
f966535ea9 | ||
|
|
07cc26a144 | ||
|
|
178c4d15b7 | ||
|
|
b0b68c695c | ||
|
|
219a3658d6 | ||
|
|
d2310fc2ea | ||
|
|
3fe0ccd934 | ||
|
|
f902ebadcc | ||
|
|
57323af167 | ||
|
|
20b0b5fc8e | ||
|
|
bb72b8cc93 | ||
|
|
fec5516da9 | ||
|
|
ec9a092751 | ||
|
|
f78f8b6b12 | ||
|
|
f97b79bc16 | ||
|
|
42c8a77755 | ||
|
|
c692cc6a70 | ||
|
|
2b8d8d4e9c | ||
|
|
2ae8032ace | ||
|
|
c4416584de | ||
|
|
86d8b49113 | ||
|
|
7a5d870f67 | ||
|
|
b43459232a | ||
|
|
e2b4e60c9e | ||
|
|
17543535e3 | ||
|
|
901ce23cd2 | ||
|
|
1b52d8065e | ||
|
|
c6db901051 | ||
|
|
39edb1ad37 | ||
|
|
a397aa188c | ||
|
|
dd08751f3f | ||
|
|
ef6a9184ba | ||
|
|
575fb6fc60 | ||
|
|
4147d6c67e | ||
|
|
115c17ab90 | ||
|
|
d892c7290c | ||
|
|
63d8a902d5 | ||
|
|
43152fcf19 | ||
|
|
1f135f1fa5 | ||
|
|
c71d378eab | ||
|
|
bb82bf762f | ||
|
|
6fa5689aaf | ||
|
|
d78bef72ea | ||
|
|
e410de9552 | ||
|
|
8dc262b415 | ||
|
|
7fa494815f | ||
|
|
929bb70e5a | ||
|
|
36fb262fa0 | ||
|
|
b8cc783583 | ||
|
|
67b3d383e4 | ||
|
|
9144ccac6b | ||
|
|
04020d5ae2 | ||
|
|
de4f1d09af | ||
|
|
d16f9efeec | ||
|
|
8ba5dfe447 | ||
|
|
27d7f5f190 | ||
|
|
c43c4c42c8 | ||
|
|
3759071449 | ||
|
|
613283f656 | ||
|
|
506b6b51ce | ||
|
|
c7eccfb714 | ||
|
|
85d59945a0 | ||
|
|
98be19b29f | ||
|
|
4c8b490c89 | ||
|
|
8dd1745149 | ||
|
|
66406d86c1 | ||
|
|
35832b07b9 | ||
|
|
357683cbb9 | ||
|
|
15bc6159f9 | ||
|
|
7cdafa76a5 | ||
|
|
e84b0c91f8 | ||
|
|
cecffee3d3 | ||
|
|
d039a40d7c | ||
|
|
90463d8613 | ||
|
|
90c965a6ba | ||
|
|
e961691645 | ||
|
|
6270d2408f | ||
|
|
7ef1842237 | ||
|
|
faf616cbea | ||
|
|
4a09e18d9a | ||
|
|
983aca515d | ||
|
|
eb184d3c68 | ||
|
|
187ecf511f | ||
|
|
0ab35a3ca3 | ||
|
|
8e208bc76d | ||
|
|
1b4d92007e | ||
|
|
4101d7664d | ||
|
|
e128c3094a | ||
|
|
95869eeb70 | ||
|
|
d977bbd61c | ||
|
|
a16a6211e2 | ||
|
|
a75013e43e | ||
|
|
1e157e95b6 | ||
|
|
04dbfcd0e6 | ||
|
|
73440e2287 | ||
|
|
ee4459691f | ||
|
|
379c6045b9 | ||
|
|
00d0ddb4b5 | ||
|
|
be08c01be6 | ||
|
|
fb6abe34df | ||
|
|
b0d107f916 | ||
|
|
6d1ff7c3f3 | ||
|
|
6f67132f4b | ||
|
|
859d21162c | ||
|
|
c739a7ea2f | ||
|
|
7e48875fd4 | ||
|
|
474e86306f | ||
|
|
b436a660f1 | ||
|
|
d36460e30b | ||
|
|
0e236f9d88 | ||
|
|
72eb61951b | ||
|
|
22b2503839 | ||
|
|
d7b5719dfd | ||
|
|
4322d195d3 | ||
|
|
4ecad65926 | ||
|
|
f12025b86e | ||
|
|
5cfea54b06 | ||
|
|
c24b75953a | ||
|
|
f3d52f4932 | ||
|
|
ea6d339b9c | ||
|
|
284a9999b3 | ||
|
|
b241872a00 | ||
|
|
b7034d3213 | ||
|
|
0a0ced3e8e | ||
|
|
e7449b4d56 | ||
|
|
fab34c9e49 | ||
|
|
7df08c2120 | ||
|
|
b94e0ef797 | ||
|
|
00fed4f995 | ||
|
|
e8a7802e94 | ||
|
|
bfbc1ebb13 | ||
|
|
a802bb2736 | ||
|
|
3c5838cafd | ||
|
|
9217e8336d | ||
|
|
13cfc2d7bc | ||
|
|
171cebed1c | ||
|
|
1dcef87e1c | ||
|
|
23fb602a33 | ||
|
|
a8a549e8fc | ||
|
|
44790e99ea | ||
|
|
a3f6717c59 | ||
|
|
9587480e29 | ||
|
|
c51dbae8b6 | ||
|
|
8619e8fc0b | ||
|
|
10dace6de6 | ||
|
|
f6e843b5e2 | ||
|
|
a7bad5df61 | ||
|
|
f50c9e855c | ||
|
|
3653666ffe | ||
|
|
2123e43490 | ||
|
|
19146d8012 | ||
|
|
987dd36401 | ||
|
|
6bb158786b | ||
|
|
f66d091717 | ||
|
|
0a3d911602 | ||
|
|
e8edb99bb0 | ||
|
|
917cd96a3d | ||
|
|
20ad6d239d | ||
|
|
eea3968bfb | ||
|
|
7ac8f6dd19 | ||
|
|
cafa78c3f3 | ||
|
|
e808f7655c | ||
|
|
4f28bf7ab4 | ||
|
|
9380b2b4e8 | ||
|
|
8caeddde15 | ||
|
|
b637398a9c | ||
|
|
2e5b19575f | ||
|
|
102a69996a | ||
|
|
37af48f3fb | ||
|
|
f38747aa28 | ||
|
|
88d05578a8 | ||
|
|
b24c8b3410 | ||
|
|
2c8dbb94fc | ||
|
|
3da2ec5112 | ||
|
|
c3545ef060 | ||
|
|
4308a7cf79 | ||
|
|
e629c90a71 | ||
|
|
e7f07f5bfc | ||
|
|
da7972c119 | ||
|
|
efc476e50b | ||
|
|
33f4e8cf73 | ||
|
|
643f300792 | ||
|
|
bd601ad2da | ||
|
|
9f1a7a1c20 | ||
|
|
bd721c1310 | ||
|
|
98138a02e3 | ||
|
|
f7004e7a7c | ||
|
|
1db25d4b20 | ||
|
|
507e198b70 | ||
|
|
5c721ee435 | ||
|
|
9a44f0c869 | ||
|
|
8c5f9b4501 | ||
|
|
713bf66a12 | ||
|
|
78e9f5bd1a | ||
|
|
f03abf2600 | ||
|
|
d5eee5b56c | ||
|
|
8899684092 | ||
|
|
8e30e4925c | ||
|
|
906c7a8ea1 | ||
|
|
324fc149b3 | ||
|
|
29b1f2afae | ||
|
|
87fa14b281 | ||
|
|
b6db86da50 | ||
|
|
043947fdcb | ||
|
|
713509527a | ||
|
|
ae7eedf523 | ||
|
|
0a1bd748d7 | ||
|
|
1b351b7743 | ||
|
|
e409bd298a | ||
|
|
caef289b9b | ||
|
|
84628bd9fc | ||
|
|
43582b6319 | ||
|
|
c14c4425a4 | ||
|
|
c47d6cffa8 | ||
|
|
f104fb0586 | ||
|
|
75e410e4b4 | ||
|
|
740316ae2b | ||
|
|
b141ec7ea7 | ||
|
|
50875d5759 | ||
|
|
61b5e5ad7e | ||
|
|
6403d18d15 | ||
|
|
77f04d913a | ||
|
|
c0a783198e | ||
|
|
d370f67f60 | ||
|
|
5f4199183c | ||
|
|
d097f8bf1e | ||
|
|
1e104bdd9e | ||
|
|
8143be29d9 | ||
|
|
1d8c9ac020 | ||
|
|
7fcc8be73c | ||
|
|
e5f9cfd5b6 | ||
|
|
edd487c1f4 | ||
|
|
71d84fecba | ||
|
|
d30e219d7b | ||
|
|
0cfda55b3a | ||
|
|
17d1ca82a6 | ||
|
|
81d2a67948 | ||
|
|
3bae3aa9aa | ||
|
|
7211e6b929 | ||
|
|
82af52a0bc | ||
|
|
e88d34ea19 | ||
|
|
e1d7d9511f | ||
|
|
22d7d2c1f6 | ||
|
|
2b10a0c513 | ||
|
|
6e59cfc66c | ||
|
|
51d8344515 | ||
|
|
535f285287 | ||
|
|
779fd78091 | ||
|
|
69a111ee35 | ||
|
|
7288e5a8fd | ||
|
|
ac57da8713 | ||
|
|
2000d02768 | ||
|
|
5ba1ebd525 | ||
|
|
92329a8dd0 | ||
|
|
21de073784 | ||
|
|
3d502a41c5 | ||
|
|
8570f9256d | ||
|
|
fe09c417ff | ||
|
|
ca891b0e70 | ||
|
|
af3ee35c50 | ||
|
|
ba0bc31525 | ||
|
|
3905cad68d | ||
|
|
30a029c19f | ||
|
|
7cac609c06 | ||
|
|
e1365f185c | ||
|
|
c2ac215d43 | ||
|
|
c47972d500 | ||
|
|
3c36030977 | ||
|
|
7b2836c63c | ||
|
|
38e2fc6812 | ||
|
|
b0037c75a3 | ||
|
|
d7f6cd944c | ||
|
|
0de928a674 | ||
|
|
5c542d60e5 | ||
|
|
b3a29188a2 | ||
|
|
8417589789 | ||
|
|
c982e022fe | ||
|
|
a4c3fd4493 | ||
|
|
7de35b4830 | ||
|
|
3841780fe6 | ||
|
|
2440d8e3d1 | ||
|
|
5012418ed2 | ||
|
|
a6ab4feca5 | ||
|
|
cd0471386d | ||
|
|
d6749d30ab | ||
|
|
37a4a4dcdf | ||
|
|
cebceb3ec3 | ||
|
|
426635871b | ||
|
|
701c90d18d | ||
|
|
d00a708177 | ||
|
|
1f32f96487 | ||
|
|
7642f8d702 | ||
|
|
e78bf240ca | ||
|
|
4fb44d98db | ||
|
|
113ee73609 | ||
|
|
64441b39ac | ||
|
|
b4e3cccf4b | ||
|
|
6a3ef2a2e4 | ||
|
|
1dd00c2ea9 | ||
|
|
5038e4396e | ||
|
|
bd025309fb | ||
|
|
1ae0dd574d | ||
|
|
7d5ce994ab | ||
|
|
78e0c3dcca | ||
|
|
edbb96bcd9 | ||
|
|
bdb1e839ed | ||
|
|
1880740561 | ||
|
|
503835d47e | ||
|
|
8d372bee67 | ||
|
|
f385af595a | ||
|
|
4cd6bafc15 | ||
|
|
dc700c41fb | ||
|
|
7cd9e8860d | ||
|
|
b6adbc926f | ||
|
|
c253464b2a | ||
|
|
6306cfff96 | ||
|
|
d86d88c7b7 | ||
|
|
5f606bb0b7 | ||
|
|
1daa97545b | ||
|
|
d0189b0719 | ||
|
|
222b92807e | ||
|
|
de90e5b753 | ||
|
|
ad4870a59b | ||
|
|
9a6c387b8e | ||
|
|
81b4a35076 | ||
|
|
411b3d0888 | ||
|
|
fc0dc4472b | ||
|
|
7824f9ee63 | ||
|
|
fb00bef05f | ||
|
|
d7bc6b1be7 | ||
|
|
79776ae8bc | ||
|
|
90b3f009af | ||
|
|
6f8deb83e3 | ||
|
|
da02a68e60 | ||
|
|
85fc8710dd | ||
|
|
a01f3e4efd | ||
|
|
cce54f3bb7 | ||
|
|
92037a480d | ||
|
|
cf6005ce2f | ||
|
|
a766ddbebc | ||
|
|
01acb08c83 | ||
|
|
023c259034 | ||
|
|
dfe4d70198 | ||
|
|
4d939cb778 | ||
|
|
660a809ec8 | ||
|
|
26825ed60f | ||
|
|
8bd8975e0a | ||
|
|
799d4f9465 | ||
|
|
47797bcf4a | ||
|
|
2847921e5a | ||
|
|
8402de601f | ||
|
|
4dec75c589 | ||
|
|
ac15b227da | ||
|
|
a1dc7a52e9 | ||
|
|
6ba3e25d33 | ||
|
|
51a2fa47c9 | ||
|
|
09bd6dba84 | ||
|
|
925bc3b3dd | ||
|
|
382bf1e94c | ||
|
|
575a7531c5 | ||
|
|
dce0c0b47e | ||
|
|
dc8230bf2e | ||
|
|
17428d58d9 | ||
|
|
6771bd84c6 | ||
|
|
ac10b3a5c7 | ||
|
|
56f2513aba | ||
|
|
9858a009da | ||
|
|
73b818cf78 | ||
|
|
4f8ffaee5b | ||
|
|
2cd40c7552 | ||
|
|
c9fd69ceb7 | ||
|
|
e4fbf70568 | ||
|
|
cf93d6bb65 | ||
|
|
228890aa19 | ||
|
|
ad8512e246 | ||
|
|
4480abc646 | ||
|
|
94243ac605 | ||
|
|
e8942c2968 | ||
|
|
8e03395b53 | ||
|
|
4f3de8646a | ||
|
|
6802f5a802 | ||
|
|
3a1ddce13f | ||
|
|
6c18857109 | ||
|
|
508b1e76c2 | ||
|
|
51d3268eed | ||
|
|
a0c90d4ba3 | ||
|
|
2c27240da6 | ||
|
|
787f5f06df | ||
|
|
7894389f1d | ||
|
|
da5f6315be | ||
|
|
42d1ab8a87 | ||
|
|
cf51892782 | ||
|
|
cdd4319991 | ||
|
|
3287eef0f1 | ||
|
|
c4a261f2d2 | ||
|
|
1867db3c4b | ||
|
|
9e23d52193 | ||
|
|
e29be737f7 | ||
|
|
3ac4122ec8 | ||
|
|
d56a79e016 | ||
|
|
77ace76e32 | ||
|
|
3270605b4f | ||
|
|
36e10539e0 | ||
|
|
37ba649930 | ||
|
|
586e72e797 | ||
|
|
38bd0d6bbb | ||
|
|
da0da4c75e | ||
|
|
bfe16bb254 | ||
|
|
2ada88a266 | ||
|
|
5b51ce9840 | ||
|
|
26793c8428 | ||
|
|
8719adef1e | ||
|
|
cd7bcb79e5 | ||
|
|
005419ab9a | ||
|
|
d28d2c57e4 | ||
|
|
64970772c7 | ||
|
|
6019b7bda4 | ||
|
|
5c792eb869 | ||
|
|
c6126db2a2 | ||
|
|
030833f942 | ||
|
|
daf67d9cf7 | ||
|
|
301ed25019 | ||
|
|
a7dbfc4954 | ||
|
|
af5e38e5ee | ||
|
|
102a28aef4 | ||
|
|
d3d8fdff13 | ||
|
|
9cb6f95420 | ||
|
|
89f334e67b | ||
|
|
b8b3d17570 | ||
|
|
053083f600 | ||
|
|
cf46564c67 | ||
|
|
59b038b8c4 | ||
|
|
fb6dfcd3fc | ||
|
|
1711ac9a88 | ||
|
|
e14c5bbd25 | ||
|
|
cf0f0d77be | ||
|
|
be7e7ac274 | ||
|
|
844bef9fda | ||
|
|
d56d41a8c2 | ||
|
|
b722c618bd | ||
|
|
720fae8720 | ||
|
|
8744b40dc5 | ||
|
|
d053bc562f | ||
|
|
cade1800f4 | ||
|
|
450a0180f8 | ||
|
|
ea363a8764 | ||
|
|
bbc8049832 | ||
|
|
66acd60406 | ||
|
|
6fd8a5a084 | ||
|
|
5927332a5f | ||
|
|
44a4b11d36 | ||
|
|
b8db47e528 | ||
|
|
f7652bd2ef | ||
|
|
e9f6509cb0 | ||
|
|
3c57e2e2b9 | ||
|
|
753ae51dd5 | ||
|
|
638178556f | ||
|
|
b44ed70112 | ||
|
|
3e494cc551 | ||
|
|
fa55896722 | ||
|
|
67a51be9ee | ||
|
|
2149bbb8ea | ||
|
|
d92a93f1d5 | ||
|
|
991fad02d7 | ||
|
|
7497e43fb9 | ||
|
|
1336de12a0 | ||
|
|
0f78bd3785 | ||
|
|
90b567c721 | ||
|
|
8176f1141e | ||
|
|
515827c745 | ||
|
|
1a2701561b | ||
|
|
c7d3ee0612 | ||
|
|
4be3cb4b0d | ||
|
|
db759bef46 | ||
|
|
3d47a8e9c0 | ||
|
|
91fe80334b | ||
|
|
7125d19af1 | ||
|
|
873e41dcfb | ||
|
|
420f858d9b | ||
|
|
e6f74751d4 | ||
|
|
5a4713950c | ||
|
|
c6691564a5 | ||
|
|
8acb44b202 | ||
|
|
72770e5809 | ||
|
|
968721a515 | ||
|
|
1de009a80d | ||
|
|
74b6a78a9b | ||
|
|
32fc6d4b7f | ||
|
|
d05b49496c | ||
|
|
52e5f467b0 | ||
|
|
4e0cf380be | ||
|
|
ebe9499e97 | ||
|
|
1cb3ab82c2 | ||
|
|
e0a954caa2 | ||
|
|
ecce3243de | ||
|
|
5e6532959b | ||
|
|
d8b7cfb36b | ||
|
|
b2837563c4 | ||
|
|
957948f906 | ||
|
|
7befafe7b7 | ||
|
|
436ce63e30 | ||
|
|
0268beb9c2 | ||
|
|
6a42e477aa | ||
|
|
22bc3dac2d | ||
|
|
4db4329ce3 | ||
|
|
924073424f | ||
|
|
9e828eccf6 | ||
|
|
3a8c99d43c | ||
|
|
acb17dc575 | ||
|
|
58987989da | ||
|
|
86e8ee334f | ||
|
|
998f2f9421 | ||
|
|
8694e7a6bf | ||
|
|
b46a6ed094 | ||
|
|
d0f53cb14a | ||
|
|
96d497a5cd | ||
|
|
a8785570df | ||
|
|
aa36e04250 | ||
|
|
821b7ed9af | ||
|
|
9270f80af2 | ||
|
|
eb8710df81 | ||
|
|
095099a085 | ||
|
|
ad424cac18 | ||
|
|
4e11806d00 | ||
|
|
f45082b764 | ||
|
|
cdca715afc | ||
|
|
d0a08a55d1 | ||
|
|
c5f3e76b21 | ||
|
|
f58ff68f3c | ||
|
|
a098aa0a89 | ||
|
|
7b3fc206f7 | ||
|
|
8f5d2a7f00 | ||
|
|
44c585e8c8 | ||
|
|
640f45f57d | ||
|
|
0ba8bace0d | ||
|
|
4202fb8cdc | ||
|
|
5f8b8835e1 | ||
|
|
78edcfe5cf | ||
|
|
2ca5e0c8b8 | ||
|
|
7ca1d99412 | ||
|
|
118bcbd6a6 | ||
|
|
987b442796 | ||
|
|
8ea77ccd04 | ||
|
|
004c2920f5 | ||
|
|
f02616acd1 | ||
|
|
69f9a484ca | ||
|
|
dde5367560 | ||
|
|
66da57f375 | ||
|
|
d328db543e | ||
|
|
c2c46f2843 | ||
|
|
96da48ae82 | ||
|
|
eb9eda1f6d | ||
|
|
f16558c126 | ||
|
|
1abf0fc134 | ||
|
|
b0ba1b2ecc | ||
|
|
a70717f2f7 | ||
|
|
5dec73f27c | ||
|
|
92ac87fa3f | ||
|
|
267239e3f2 | ||
|
|
52b863fe36 | ||
|
|
79337a4568 | ||
|
|
84750e2605 | ||
|
|
dfa1a3ad90 | ||
|
|
c1f9445e9d | ||
|
|
191db46c4f | ||
|
|
bc67bf6826 | ||
|
|
df534d30bf | ||
|
|
ce99dbe40c | ||
|
|
affcca8034 | ||
|
|
a6f31a577a | ||
|
|
9b814f4ed8 | ||
|
|
3091440162 | ||
|
|
3b2573afed | ||
|
|
1b64747c2b | ||
|
|
863212915c | ||
|
|
8ef82ebdd7 | ||
|
|
78aad924c5 | ||
|
|
24fda89665 | ||
|
|
59cb9ba344 | ||
|
|
d511eb19ef | ||
|
|
d3e9f51d6b | ||
|
|
e3499e5a70 | ||
|
|
026425407e | ||
|
|
18884111a6 | ||
|
|
3e5b152718 | ||
|
|
8e9637f6d4 | ||
|
|
d11ad39048 | ||
|
|
cb44d45eeb | ||
|
|
c15ffca48c | ||
|
|
902c11d074 | ||
|
|
35250677b9 | ||
|
|
1f3a1a0a95 | ||
|
|
38330b735c | ||
|
|
bda3c4ab7a | ||
|
|
d8d01ac353 | ||
|
|
51d935f419 | ||
|
|
c96f83b076 | ||
|
|
2fe4edb6df | ||
|
|
7308f5993c | ||
|
|
1e4f8be74b | ||
|
|
22ac12dc36 | ||
|
|
866296fefd | ||
|
|
9d574397bc | ||
|
|
b6e53b1a0c | ||
|
|
a46894f395 | ||
|
|
bee48dae7e | ||
|
|
e12f7b67e5 | ||
|
|
c7ceeb1833 | ||
|
|
12f6ed621e | ||
|
|
d7daada42e | ||
|
|
6c6849d8d7 | ||
|
|
e82336f355 | ||
|
|
1151b615a0 | ||
|
|
0cf891b9d9 | ||
|
|
aeb8fd6fda | ||
|
|
615f807909 | ||
|
|
985255afed | ||
|
|
9bec394d7f | ||
|
|
8f72e0ab83 | ||
|
|
6799a3bd35 | ||
|
|
588c7a81fc | ||
|
|
ce32ac19dd | ||
|
|
16aa0e4dba | ||
|
|
81cb765b7a | ||
|
|
d5523615ef | ||
|
|
ff5d899a92 | ||
|
|
d9f2c2b968 | ||
|
|
2f6adbd07c | ||
|
|
f0992d56c1 | ||
|
|
67bcf42125 | ||
|
|
935ddd12ec | ||
|
|
5a772f5410 | ||
|
|
698a32f364 | ||
|
|
bdea2acf67 | ||
|
|
377a11b160 | ||
|
|
9519c8edbd | ||
|
|
64fd207533 | ||
|
|
96e04f1c54 | ||
|
|
348c4b4431 | ||
|
|
bfbff723ac | ||
|
|
03dba4d7d0 | ||
|
|
febd7cbca8 | ||
|
|
e2b7b228c5 | ||
|
|
8b58d96aea | ||
|
|
0a2e01a616 | ||
|
|
a8908238d5 | ||
|
|
569138ac80 | ||
|
|
cf3faa1170 | ||
|
|
ae50374d55 | ||
|
|
d2705f033d | ||
|
|
5d12e2291c | ||
|
|
cd46d84dcb | ||
|
|
a3b0b8b3d0 | ||
|
|
4c60a70c6f | ||
|
|
a75b3a53aa | ||
|
|
94a79b57e9 | ||
|
|
dbe90eb3f5 | ||
|
|
3891348c26 | ||
|
|
84106d6282 | ||
|
|
37395931bf | ||
|
|
88e487be8e | ||
|
|
fd4c0e795a | ||
|
|
c79eb43347 | ||
|
|
860e74bffa | ||
|
|
4c759083be | ||
|
|
d3bb079be4 | ||
|
|
ed374684a6 | ||
|
|
169a46c38c | ||
|
|
1dbea434a3 | ||
|
|
a5b4d7a244 | ||
|
|
7ebb58b1fa | ||
|
|
ac5b3110f2 | ||
|
|
48259b4ffe | ||
|
|
041426fecb | ||
|
|
2caf7efdc6 | ||
|
|
b00e038b33 | ||
|
|
36503f0417 | ||
|
|
0daddf9896 | ||
|
|
f3364e1327 | ||
|
|
cf54115077 | ||
|
|
12a94c50b8 | ||
|
|
0dd12cf0a6 | ||
|
|
f92c336ae4 | ||
|
|
477c9ef577 | ||
|
|
e146a476bd | ||
|
|
45e74126da | ||
|
|
f32a39e79f | ||
|
|
489b144085 | ||
|
|
e7d311d23c | ||
|
|
4cc2dea2fe | ||
|
|
1e2cae7087 | ||
|
|
2b259f3704 | ||
|
|
0df5221784 | ||
|
|
4c78d35680 | ||
|
|
cdef8472e3 | ||
|
|
f9c933bf3b | ||
|
|
cc995ecef8 | ||
|
|
922a3631ae | ||
|
|
0903078618 | ||
|
|
8c759cb65a | ||
|
|
bd45c67528 | ||
|
|
562a206508 | ||
|
|
dd584e929f | ||
|
|
1828a2a81c | ||
|
|
a6746f77f0 | ||
|
|
184ff7a3b3 | ||
|
|
9db872db56 | ||
|
|
f1a1b89d13 | ||
|
|
14e0e96596 | ||
|
|
793c878c66 | ||
|
|
14887d5e88 | ||
|
|
366006273d | ||
|
|
6a69a726f2 | ||
|
|
e9cd4d95a7 | ||
|
|
d7e1dc1f95 | ||
|
|
19c8b4fe2d | ||
|
|
8b73a7375a | ||
|
|
974798f79c | ||
|
|
43c5de074f | ||
|
|
461cc1d5a8 | ||
|
|
3d6df07335 | ||
|
|
7689587879 | ||
|
|
e248b989e1 | ||
|
|
9920424a31 | ||
|
|
17be0a2c12 | ||
|
|
26fa38d052 | ||
|
|
34a4382920 | ||
|
|
e7c9b5a4f0 | ||
|
|
8c31904838 | ||
|
|
d522b608d3 | ||
|
|
3e7303c15c | ||
|
|
6e342983f9 | ||
|
|
a6d7ed3824 | ||
|
|
e003ec39fb | ||
|
|
62abc63f7a | ||
|
|
0955480f5b | ||
|
|
bf76affd06 | ||
|
|
b4d6525899 | ||
|
|
ba3555a66f | ||
|
|
d8be286831 | ||
|
|
65f5bc531c | ||
|
|
3ba4702181 | ||
|
|
ad9c42e832 | ||
|
|
0368d3be59 | ||
|
|
598549b5fb | ||
|
|
49086a3ae0 | ||
|
|
4676a7aa62 | ||
|
|
7d25b234d5 | ||
|
|
c6578870f0 | ||
|
|
4e8030bd81 | ||
|
|
094e130544 | ||
|
|
879fd5a13d | ||
|
|
c2bb49aca0 | ||
|
|
9ed14b6e8c | ||
|
|
4484721a9f | ||
|
|
4963a5797b | ||
|
|
13f5798ed4 | ||
|
|
db8e1dec3e | ||
|
|
c9bdecdb69 | ||
|
|
adb7726974 | ||
|
|
d6883d0c1c | ||
|
|
b2409ac708 | ||
|
|
cf189663a7 | ||
|
|
f0d36fd769 | ||
|
|
213e3e998a | ||
|
|
bef9c68f81 | ||
|
|
099d2fd03d | ||
|
|
9f71a6ab18 | ||
|
|
e088f7a552 | ||
|
|
2e6ce0481c | ||
|
|
23d39e5366 | ||
|
|
279664a578 | ||
|
|
2a3d128f3c | ||
|
|
9667365d9e | ||
|
|
d4ef26e0f3 | ||
|
|
a053e81797 | ||
|
|
1494bfe855 | ||
|
|
f1a4ba4e76 | ||
|
|
385c526414 | ||
|
|
5e95e02429 | ||
|
|
3081802b1c | ||
|
|
1663601dcb | ||
|
|
1a513c7bbf | ||
|
|
92cbdde429 | ||
|
|
0f6b1e4ae1 | ||
|
|
f915201a27 | ||
|
|
d1f76042e1 | ||
|
|
845aa733b7 | ||
|
|
a0e318827d | ||
|
|
39720a11dc | ||
|
|
da33bf3438 | ||
|
|
eda6f134a9 | ||
|
|
46e1c8ef73 | ||
|
|
f247139f1c | ||
|
|
566985cf72 | ||
|
|
70b4cdf520 | ||
|
|
081f211231 | ||
|
|
9cd8acab43 | ||
|
|
8b79a9708b | ||
|
|
969acbd47f | ||
|
|
31012671c5 | ||
|
|
e362b3b6aa | ||
|
|
d2ced93e58 | ||
|
|
958cd35e21 | ||
|
|
73e898773b | ||
|
|
46eae410c3 | ||
|
|
73a9e1c316 | ||
|
|
03862d4b6c | ||
|
|
557a2f08f7 | ||
|
|
ae90aa4ccc | ||
|
|
6eff2e6e74 | ||
|
|
955bb51f11 | ||
|
|
b583def913 | ||
|
|
dd85da053f | ||
|
|
ba6a01408d | ||
|
|
81d880fb4e | ||
|
|
bdbce67473 | ||
|
|
6079effae3 | ||
|
|
41aa1ee318 | ||
|
|
8d2fe315db | ||
|
|
22c3ac5be3 | ||
|
|
a517f0df1d | ||
|
|
c14f16bdf1 | ||
|
|
9c9854b6bf | ||
|
|
d280e16723 | ||
|
|
b93a9cb8bc | ||
|
|
8601052179 | ||
|
|
eaa20ff4bf | ||
|
|
e4c6e4bc48 | ||
|
|
c52597205e | ||
|
|
eee9de8271 | ||
|
|
c73033c0b4 | ||
|
|
aecfa3ff0f | ||
|
|
18f575bee4 | ||
|
|
522e752582 | ||
|
|
854ed8cfa9 | ||
|
|
4642205768 | ||
|
|
40dbfbe092 | ||
|
|
7882519c0e | ||
|
|
0234017ca1 | ||
|
|
6c315e5a9c | ||
|
|
ef0f91d8d0 | ||
|
|
9552784e72 | ||
|
|
ac20d7f302 | ||
|
|
f068327307 | ||
|
|
1bc698ae78 | ||
|
|
3f6691dcd5 | ||
|
|
31981b9080 | ||
|
|
167d29c39f | ||
|
|
28b78c2b27 | ||
|
|
b3d691fff6 | ||
|
|
8e5f2d91e8 | ||
|
|
cfa7f60e5f | ||
|
|
e0fcaa6103 | ||
|
|
1b2134d7a8 | ||
|
|
f922268af7 | ||
|
|
841a9f8082 | ||
|
|
4865ddb377 | ||
|
|
a556732e4f | ||
|
|
0ea31cb088 | ||
|
|
06fe7323eb | ||
|
|
d8d9259c36 | ||
|
|
261260b232 | ||
|
|
5b88894638 | ||
|
|
ddadaa828a | ||
|
|
a3cd10d83b | ||
|
|
b626c7620e | ||
|
|
5d90d8930e | ||
|
|
b01309c3bf | ||
|
|
2d1511b5dd | ||
|
|
e561304645 | ||
|
|
961d5591bd | ||
|
|
eca3f12fed | ||
|
|
a2c8796e04 | ||
|
|
ad301fd087 | ||
|
|
02b08939cd | ||
|
|
9b0d583f1b | ||
|
|
4a0a07f158 | ||
|
|
9c864c9759 | ||
|
|
f1dd1bd6bd | ||
|
|
85b1c309d1 | ||
|
|
6fe43b7b5c | ||
|
|
62fc986d96 | ||
|
|
03710f1fd2 | ||
|
|
2283c7a926 | ||
|
|
fb19ca8bf4 | ||
|
|
4ebfc1516c | ||
|
|
cc713e6c89 | ||
|
|
1be65adf02 | ||
|
|
25427ee60d | ||
|
|
c8eefbaa2e | ||
|
|
b339f426f2 | ||
|
|
9fd26fa574 | ||
|
|
be90bf0188 | ||
|
|
adcdaba199 | ||
|
|
17907589cc | ||
|
|
f333df181f | ||
|
|
61a01cb163 | ||
|
|
4ce557a829 | ||
|
|
4d10c9de95 | ||
|
|
5b84acebbc | ||
|
|
fc845dc936 | ||
|
|
7beae93441 | ||
|
|
c8f1297adb | ||
|
|
053a1d34e5 | ||
|
|
110a75ba0b | ||
|
|
826a31e57d | ||
|
|
23d7c3d0fe | ||
|
|
4d4a20e05e | ||
|
|
c03d4f115f | ||
|
|
ed90b638a9 | ||
|
|
c5252e06a7 | ||
|
|
8af445e72b | ||
|
|
94a0199955 | ||
|
|
44739c5198 | ||
|
|
5f871bc01f | ||
|
|
b382dd6fc0 | ||
|
|
2e84f82ed6 | ||
|
|
1f5971f15a | ||
|
|
694466a196 | ||
|
|
03311d3776 | ||
|
|
ae0eba866a | ||
|
|
05f92b74e7 | ||
|
|
41b6f3ffa7 | ||
|
|
c895b76864 | ||
|
|
906737bedb | ||
|
|
7138e891be | ||
|
|
53abe36b83 | ||
|
|
efbb7a034c | ||
|
|
d7dac57a07 | ||
|
|
05bc81bf4e | ||
|
|
59ce88f044 | ||
|
|
f8bc0bd2b5 | ||
|
|
7ebb184c8a | ||
|
|
bd44205b4e | ||
|
|
cf94cb1092 | ||
|
|
02d92e32c7 | ||
|
|
68087cdea5 | ||
|
|
7f92607b85 | ||
|
|
3be4b69b44 | ||
|
|
bb9afcb304 | ||
|
|
e9a05890a5 | ||
|
|
613809c2af | ||
|
|
7b969bb8c2 | ||
|
|
7aef551292 | ||
|
|
447b811fa0 | ||
|
|
5151aa677f | ||
|
|
a5ff34d423 | ||
|
|
435040814d | ||
|
|
9987416a4a | ||
|
|
31e33e0a8b | ||
|
|
03cfae45f8 | ||
|
|
4f83325e3c | ||
|
|
cd1765a0f3 | ||
|
|
5c744ad9aa | ||
|
|
b211d8b085 | ||
|
|
f8eece362f | ||
|
|
d4ea30e081 | ||
|
|
83416ee2e0 | ||
|
|
fa981a389f | ||
|
|
25915b5521 | ||
|
|
ed0dcb5c3d | ||
|
|
55817f31f9 | ||
|
|
a5b19bbc83 | ||
|
|
f6b44e03ac | ||
|
|
6d2ef4e0bf | ||
|
|
4d714cf9a4 | ||
|
|
930ded6767 | ||
|
|
4cdb18907f | ||
|
|
93bccb96b6 | ||
|
|
38bc618ee5 | ||
|
|
00b0193a43 | ||
|
|
e2db37d28a | ||
|
|
f9bce54104 | ||
|
|
7ee14724fc | ||
|
|
5988c2ac78 | ||
|
|
4eb0dbb5a4 | ||
|
|
8c5b3fe23e | ||
|
|
e35ad7551b | ||
|
|
6c943a7158 | ||
|
|
2da14e5b2a | ||
|
|
97f8eea302 | ||
|
|
04d5932252 | ||
|
|
84e38f765d | ||
|
|
b33c5798ee | ||
|
|
81012e60ff | ||
|
|
6180c2f948 | ||
|
|
52f0ae9350 | ||
|
|
fa0936da3c | ||
|
|
8a30c6347e | ||
|
|
09bcf34050 | ||
|
|
795c515999 | ||
|
|
00dbdc2267 | ||
|
|
32286888e5 | ||
|
|
565d8d8f04 | ||
|
|
0a5a0bef48 | ||
|
|
6e0e5c102e | ||
|
|
d31271fee3 | ||
|
|
be8a9ae73b | ||
|
|
afaa001738 | ||
|
|
22fbb0e35b | ||
|
|
026a53f3ff | ||
|
|
e17203ca1b | ||
|
|
599c7919ce | ||
|
|
778b601cd5 | ||
|
|
3170fa2208 | ||
|
|
07216db864 | ||
|
|
fec870f264 | ||
|
|
4518f089cc | ||
|
|
2c5eba335f | ||
|
|
fb19f1ecbc | ||
|
|
91dd03ba67 | ||
|
|
86092541ed | ||
|
|
e879fe5843 | ||
|
|
0ca7699fe5 | ||
|
|
7f6adfa331 | ||
|
|
5f0b102671 | ||
|
|
70a59daa6f | ||
|
|
d28eb6ae21 | ||
|
|
34865f797f | ||
|
|
eca980dfca | ||
|
|
742c792ec7 | ||
|
|
24a5f7a38e | ||
|
|
554949102b | ||
|
|
0f3b95802d | ||
|
|
868910fddf | ||
|
|
436542eff8 | ||
|
|
f4c05c67a2 | ||
|
|
6f7f67df5a | ||
|
|
50b6163e73 | ||
|
|
9b062f33c5 | ||
|
|
ea15c2245e | ||
|
|
beb539abaf | ||
|
|
6dd1d45a02 | ||
|
|
26ae6d3691 | ||
|
|
90ea01aa46 | ||
|
|
6c52105ac7 | ||
|
|
f97bc9dba8 | ||
|
|
3332375d7c | ||
|
|
fe6b1c13c4 | ||
|
|
5608425a12 | ||
|
|
f784b01d20 | ||
|
|
2648eba5bf | ||
|
|
255347ab77 | ||
|
|
52c36ef6a4 | ||
|
|
ed2e083d13 | ||
|
|
80f7c5ed9d | ||
|
|
8d33cbeaca | ||
|
|
b0b8bc7385 | ||
|
|
edbc8b28d5 | ||
|
|
da9bab16e1 | ||
|
|
75098d8b3e | ||
|
|
65bb7fd533 | ||
|
|
0259e78b2f | ||
|
|
99b8888a1b | ||
|
|
689f4ef606 | ||
|
|
b0c40e1e37 | ||
|
|
e54819e7e5 | ||
|
|
7eb029dcb6 | ||
|
|
3da70c3e8b | ||
|
|
f8c80283e4 | ||
|
|
72a6681ac1 | ||
|
|
1ab555b590 | ||
|
|
4602ec7688 | ||
|
|
5c39d8d12e | ||
|
|
97284fcf87 | ||
|
|
c8b1654e0a | ||
|
|
0400d0e0f0 | ||
|
|
4040f6bec6 | ||
|
|
a4a3aa045b | ||
|
|
a5a18903c7 | ||
|
|
6990986d9f | ||
|
|
06ded0098c | ||
|
|
f1fbea30f1 | ||
|
|
04f5bdb843 | ||
|
|
d29283ff21 | ||
|
|
35779dad8b | ||
|
|
ee0d6420a0 | ||
|
|
f66d847032 | ||
|
|
aba4dc7c50 | ||
|
|
99d0c5e2c6 | ||
|
|
fa55b94528 | ||
|
|
7fb46cf982 | ||
|
|
523752b263 | ||
|
|
7df4b8e8cc | ||
|
|
7a4ed5a337 | ||
|
|
ec37085e39 | ||
|
|
61e1e2729d | ||
|
|
ae8281f835 | ||
|
|
2efa68dd60 | ||
|
|
d2c92781c8 | ||
|
|
fa35293618 | ||
|
|
20ccca0aec | ||
|
|
10e216da6b | ||
|
|
6491353a57 | ||
|
|
1906523489 | ||
|
|
24beaa0d18 | ||
|
|
e1deb48121 | ||
|
|
b3891bacaa | ||
|
|
7939904ee3 | ||
|
|
7dcd69a2df | ||
|
|
9f44f989e5 | ||
|
|
002b2d0134 | ||
|
|
8b10ec93c2 | ||
|
|
cf9ecd1564 | ||
|
|
f31147248b | ||
|
|
2f9c540660 | ||
|
|
09489feff9 | ||
|
|
0d17a69ee4 | ||
|
|
c5755a4ec4 | ||
|
|
20bc3719a4 | ||
|
|
7dc41ab205 | ||
|
|
acc21e3b43 | ||
|
|
41a6726beb | ||
|
|
2f8ba75970 | ||
|
|
eb08129226 | ||
|
|
816823b115 | ||
|
|
b6059939b4 | ||
|
|
b8e23b2d7e | ||
|
|
a06846fa74 | ||
|
|
33f72e40da | ||
|
|
e8b2d80037 | ||
|
|
853463b7cd | ||
|
|
518e1a6405 | ||
|
|
afd376ddbc | ||
|
|
1ce325ee8a | ||
|
|
1e947a34a8 | ||
|
|
fe1e5aeebf | ||
|
|
8386b9a0b4 | ||
|
|
40323e3afe | ||
|
|
18868a5bd6 | ||
|
|
754682577c | ||
|
|
603dee7661 | ||
|
|
2a27cc46e2 | ||
|
|
a9a06a1e4e | ||
|
|
5f73725b8f | ||
|
|
324983024a | ||
|
|
7cb63b1da0 | ||
|
|
31603380c1 | ||
|
|
5a3d3b0324 | ||
|
|
78006855ee | ||
|
|
71520f6709 | ||
|
|
3f5a09229d | ||
|
|
5609771993 | ||
|
|
79b01cdc3c | ||
|
|
73f99b5e22 | ||
|
|
7d6f8eb495 | ||
|
|
eac5340b03 | ||
|
|
aef0243b73 | ||
|
|
736053e24e | ||
|
|
36b196dd93 | ||
|
|
549dcd32ca | ||
|
|
a59f56d852 | ||
|
|
2c14181051 | ||
|
|
c2b9e06a4a | ||
|
|
964978d45b | ||
|
|
599490bb6e | ||
|
|
a841e1fb2e | ||
|
|
296fe4b62e | ||
|
|
cb4c736fab | ||
|
|
118f02fd11 | ||
|
|
990d0f6e3e | ||
|
|
84624666ce | ||
|
|
42474e551f | ||
|
|
061e055d1b | ||
|
|
12f2caa8d6 | ||
|
|
8bd716c056 | ||
|
|
b890b5f0dc | ||
|
|
cd95abb2a1 | ||
|
|
c3df9e6270 | ||
|
|
6463fbee32 | ||
|
|
e43cdc6674 | ||
|
|
59216a9ae1 | ||
|
|
47a620bd36 | ||
|
|
37dbf4d8ec | ||
|
|
1270f2d577 | ||
|
|
80a067806d | ||
|
|
f20065f546 | ||
|
|
43d50e270a | ||
|
|
c27117e99e | ||
|
|
9c84f13425 | ||
|
|
b2cf7a16f2 | ||
|
|
28556790d6 | ||
|
|
41c9bb63a0 | ||
|
|
c2b2fafc9c | ||
|
|
5b88ba6d1d | ||
|
|
d036021a78 | ||
|
|
7d5e2466f0 | ||
|
|
d3f35955d6 | ||
|
|
fb338c0728 | ||
|
|
5462d1e9f8 | ||
|
|
2ce8f1ee5d | ||
|
|
3f0258e215 | ||
|
|
e72a8d999f | ||
|
|
fed16fd14e | ||
|
|
5dbc45ecb9 | ||
|
|
2f411dfc9c | ||
|
|
d6cff870e5 | ||
|
|
e1cd45c57e | ||
|
|
7572b6f66b | ||
|
|
e489b08bc1 | ||
|
|
094bdb29b6 | ||
|
|
712e05479b | ||
|
|
7c6c9eed36 | ||
|
|
63eee28a82 | ||
|
|
0777eaad10 | ||
|
|
9e6866c160 | ||
|
|
974dd8ce57 | ||
|
|
957d08f4c6 | ||
|
|
156b499f93 | ||
|
|
f31100326b | ||
|
|
9b7b1d6a61 | ||
|
|
7101ad81c4 | ||
|
|
8643263227 | ||
|
|
409c1b7584 | ||
|
|
eab132ed32 | ||
|
|
f45b5da71a | ||
|
|
f57b606f72 | ||
|
|
66bad2b6f8 | ||
|
|
44f9bc5f0e | ||
|
|
5c7e3c6bab | ||
|
|
46ec504743 | ||
|
|
737151ba09 | ||
|
|
2eef39d64a | ||
|
|
821f76bcd6 | ||
|
|
37ec058572 | ||
|
|
cadda12371 | ||
|
|
a643b56555 | ||
|
|
aa34df7a4c | ||
|
|
f7404085de | ||
|
|
33036e7599 | ||
|
|
f6e5b67f0d | ||
|
|
9547ac353d | ||
|
|
48339b19d4 | ||
|
|
0f8d464706 | ||
|
|
d6be7b4cae | ||
|
|
70aa01b261 | ||
|
|
11c7ffad4e | ||
|
|
1973424e05 | ||
|
|
16d97d3c63 | ||
|
|
3e6728fedb | ||
|
|
3e9aea072d | ||
|
|
fcfb73c755 | ||
|
|
12ce3282ff | ||
|
|
9f3e66fff0 | ||
|
|
624993fc89 | ||
|
|
ba8a00764a | ||
|
|
49f79a331c | ||
|
|
3dec4a6651 | ||
|
|
ac0a853030 | ||
|
|
e8ae4e76a3 | ||
|
|
c73b098f30 | ||
|
|
4292e26135 | ||
|
|
02fb2550d0 | ||
|
|
37bd525638 | ||
|
|
ea0f37f5b9 | ||
|
|
d09d7521d6 | ||
|
|
20d03cb817 | ||
|
|
97b3c3db7b | ||
|
|
b97b6dc144 | ||
|
|
b07bbab069 | ||
|
|
c8d5218c65 | ||
|
|
80a657965e | ||
|
|
b3324d22f5 | ||
|
|
295663f6a6 | ||
|
|
47caa2c3a0 | ||
|
|
4ddc422cfa | ||
|
|
856c8aa611 | ||
|
|
6f600f74af | ||
|
|
be8db602b8 | ||
|
|
7871e868a9 | ||
|
|
44467971f2 | ||
|
|
108fc4a0d8 | ||
|
|
31b7cdff9b | ||
|
|
0465298507 | ||
|
|
65ac8d4b2b | ||
|
|
dd59e3a831 | ||
|
|
1e98d56bb6 | ||
|
|
d31e4c7815 | ||
|
|
4af1f62aab | ||
|
|
bc403440ba | ||
|
|
38d8dfe5ab | ||
|
|
bee93f4743 | ||
|
|
9888510158 | ||
|
|
5fd4ed91d8 | ||
|
|
2a949cd8f1 | ||
|
|
312cbc86e9 | ||
|
|
85ded6e500 | ||
|
|
ce5a81d83c | ||
|
|
eb92c0bbf5 | ||
|
|
5453ae81a6 | ||
|
|
ff84f2b2f7 | ||
|
|
6df64d0d31 | ||
|
|
e9ac20a149 | ||
|
|
83753a5f81 | ||
|
|
7a228cac43 | ||
|
|
3161f5fa47 | ||
|
|
442741d246 | ||
|
|
5784092c1b | ||
|
|
d6ad089c60 | ||
|
|
89ff8b3fcb | ||
|
|
5773f141b8 | ||
|
|
446b4b084c | ||
|
|
f8da8f6929 | ||
|
|
f7de055f67 | ||
|
|
07d09aea85 | ||
|
|
f63ceed1ae | ||
|
|
b93d72296c | ||
|
|
d590e01a58 | ||
|
|
1bc15a8507 | ||
|
|
adeb9bccb1 | ||
|
|
5cf26af9f0 | ||
|
|
04c9646e05 | ||
|
|
67bf1a93e4 | ||
|
|
c263f11170 | ||
|
|
bb4c646714 | ||
|
|
b44ffffed8 | ||
|
|
bd521f858e | ||
|
|
f66fcfbe6d | ||
|
|
2bdaf53ecf | ||
|
|
46e7db6d94 | ||
|
|
10fc9fe268 | ||
|
|
73c75635b1 | ||
|
|
cc7d745ce6 | ||
|
|
7e1920dc4b | ||
|
|
a93f05c047 | ||
|
|
00238247cd | ||
|
|
b33e28835d | ||
|
|
044d830b64 | ||
|
|
38c84bb1f6 | ||
|
|
b50e066dee | ||
|
|
f55f803531 | ||
|
|
757e8eb57c | ||
|
|
a696afaeb8 | ||
|
|
8ca298b299 | ||
|
|
cde497c94e | ||
|
|
090e29effd | ||
|
|
94cf6424f5 | ||
|
|
b8013a57e2 | ||
|
|
1b23210902 | ||
|
|
0acca2e313 | ||
|
|
4bb30deca6 | ||
|
|
31bf615fe8 | ||
|
|
0d77027f60 | ||
|
|
bbf46358fa | ||
|
|
1cf793233f | ||
|
|
39b7b3ad53 | ||
|
|
7acc537c7a | ||
|
|
97c1a2245b | ||
|
|
8e9269fdf9 | ||
|
|
d9b2037b50 | ||
|
|
95827c3ada | ||
|
|
4e2bbc04fa | ||
|
|
61eff6e7e8 | ||
|
|
1d4d5f0c93 | ||
|
|
00f1b483eb | ||
|
|
939de6b177 | ||
|
|
c3d48acb4c | ||
|
|
ad4bc206ab | ||
|
|
8cfa5ba39e | ||
|
|
c2e6d1c6bf | ||
|
|
392bda7d8c | ||
|
|
5a658b7080 | ||
|
|
a6adb314ec | ||
|
|
5714578783 | ||
|
|
539125ff47 | ||
|
|
10cfcdab8c | ||
|
|
3f71d3b250 | ||
|
|
1b50fbab22 | ||
|
|
303fc65a6a | ||
|
|
445b6ee13f | ||
|
|
8afaac1e30 | ||
|
|
0327f9428e | ||
|
|
a5de66bbd5 | ||
|
|
d47157eec3 | ||
|
|
f4b47ed399 | ||
|
|
8b2145bd88 | ||
|
|
de454e8b78 | ||
|
|
6cd770b4c7 | ||
|
|
355525c248 | ||
|
|
53237c297f | ||
|
|
47d4e7381f | ||
|
|
5dac6690d7 | ||
|
|
2d8885cb0c | ||
|
|
b89f7180db | ||
|
|
4fdf85bbdb | ||
|
|
2ebb837a15 | ||
|
|
728d57d955 | ||
|
|
e53a2e7b43 | ||
|
|
e682fd07cb | ||
|
|
849aa64678 | ||
|
|
bddd22cfab | ||
|
|
cbb12e1b7c | ||
|
|
cc87ba4962 | ||
|
|
19310470b6 | ||
|
|
02fcccc8c7 | ||
|
|
fb2e556726 | ||
|
|
9f230ae339 | ||
|
|
3f0eb0a046 | ||
|
|
7d6d9eddc4 | ||
|
|
cf87da0ef3 | ||
|
|
0775acedc0 | ||
|
|
7b21c1bcbe | ||
|
|
9c295d1884 | ||
|
|
8f1cee2e61 | ||
|
|
caa9cc32d7 | ||
|
|
b750f827c5 | ||
|
|
aef53a8753 | ||
|
|
5d147163e5 | ||
|
|
75fe1a19eb | ||
|
|
5149078f6a | ||
|
|
4d95248f16 | ||
|
|
5c9405fffc | ||
|
|
368f52ade6 | ||
|
|
6457314794 | ||
|
|
84f4e3eedc | ||
|
|
8cc2ba4770 | ||
|
|
b003ed3f03 | ||
|
|
330da137db | ||
|
|
9e5d45d0de | ||
|
|
f40398bf42 | ||
|
|
b5c15d97fa | ||
|
|
783a21d88d | ||
|
|
6ddcba8917 | ||
|
|
91598cbbbf | ||
|
|
772c80aa85 | ||
|
|
62e7c861bd | ||
|
|
9d5b6eac55 | ||
|
|
72c5de6eae | ||
|
|
a28345d858 | ||
|
|
05b532b9eb | ||
|
|
0b0d18f182 | ||
|
|
1d833419aa | ||
|
|
c1b0877956 | ||
|
|
46b66c76ef | ||
|
|
d00b4335b5 | ||
|
|
7a129e6de1 | ||
|
|
e17e2a636b | ||
|
|
17c20276a9 | ||
|
|
dc9dedf220 | ||
|
|
3ac772badc | ||
|
|
22fc58d93b | ||
|
|
ccd3152b24 | ||
|
|
7d929dcde6 | ||
|
|
45e0cbdb25 | ||
|
|
dc9d48850f | ||
|
|
3a874bc8c7 | ||
|
|
8453cd82e9 | ||
|
|
9092549f07 | ||
|
|
a94b5ba0c0 | ||
|
|
5d1efd84a4 | ||
|
|
f62e56b7ec | ||
|
|
2ac90bbb96 | ||
|
|
f85f2d5d22 | ||
|
|
8af953e20d | ||
|
|
66132a912a | ||
|
|
a94269ceb9 | ||
|
|
b852cbdc80 | ||
|
|
350caee808 | ||
|
|
476ac263fb | ||
|
|
51a4f61a8f | ||
|
|
7d05236514 | ||
|
|
465b43be6a | ||
|
|
006edacd55 | ||
|
|
a9666a9f6e | ||
|
|
7de492caa7 | ||
|
|
93ee4716cc | ||
|
|
267f5159a3 | ||
|
|
8a60d4cf2f | ||
|
|
6489444158 | ||
|
|
59a66a3ea5 | ||
|
|
e17550e23e | ||
|
|
0f8d6daf99 | ||
|
|
08925a72c6 | ||
|
|
1101299168 | ||
|
|
22be8e2e9d | ||
|
|
6db2240f8a | ||
|
|
96422de031 | ||
|
|
54eac18eea | ||
|
|
f2043dc181 | ||
|
|
e416ec9279 | ||
|
|
5eb4ffb1cc | ||
|
|
284e748449 | ||
|
|
3111718eb1 | ||
|
|
fd8d17c5e5 | ||
|
|
109bb62209 | ||
|
|
cc661b26fa | ||
|
|
ea69957ed1 | ||
|
|
700f641e29 | ||
|
|
83f4eeb3b5 | ||
|
|
d1f4cdebf3 | ||
|
|
d95ba43fd1 | ||
|
|
8fae964ee8 | ||
|
|
baf49b88f4 | ||
|
|
7dc07f6d21 | ||
|
|
6472d35d91 | ||
|
|
95c87919a8 | ||
|
|
077b4d5c89 | ||
|
|
3577da05ac | ||
|
|
b8e8028eb9 | ||
|
|
a2105de402 | ||
|
|
d049e0a149 | ||
|
|
7463be862f | ||
|
|
a899666e68 | ||
|
|
10a52f8cf9 | ||
|
|
bc6652f443 | ||
|
|
72d04a0120 | ||
|
|
6dbed30008 | ||
|
|
c5eac298e6 | ||
|
|
bc18eda336 | ||
|
|
3cefb14297 | ||
|
|
4bc401278e | ||
|
|
56167f84ad | ||
|
|
d7e3765efe | ||
|
|
3d51d1e345 | ||
|
|
db4ecce20b | ||
|
|
95518f1948 | ||
|
|
bd23942893 | ||
|
|
c8610b8ad2 | ||
|
|
d0440122b9 | ||
|
|
d4beb2f79b | ||
|
|
9be995bb08 | ||
|
|
8d4636bbab | ||
|
|
f59c6e7a7c | ||
|
|
c24ab1b21d | ||
|
|
6a01658355 | ||
|
|
f1e2439e66 | ||
|
|
c1d47290b1 | ||
|
|
4d6116ed40 | ||
|
|
4d89ed701d | ||
|
|
18ba394901 | ||
|
|
3a83753611 | ||
|
|
e80594d61d | ||
|
|
c436b586d2 | ||
|
|
83c6f72eb0 | ||
|
|
e26299b998 | ||
|
|
f84e2c2ac7 | ||
|
|
4e8c94fd2d | ||
|
|
8f3fd37d47 | ||
|
|
a839809eb8 | ||
|
|
7960e9b309 | ||
|
|
88ceba59cf | ||
|
|
f368bbec32 | ||
|
|
021c4ba68a | ||
|
|
4875544888 | ||
|
|
849bdc52f6 | ||
|
|
54f4658dae | ||
|
|
63bb05b2d4 | ||
|
|
916ad0a58e | ||
|
|
dbc67e077d | ||
|
|
15055fa509 | ||
|
|
8ee704e123 | ||
|
|
0d552cd880 | ||
|
|
e968917dbc | ||
|
|
d8240bb683 | ||
|
|
b481c13829 | ||
|
|
60ce5c67de | ||
|
|
421f932053 | ||
|
|
542d6361f2 | ||
|
|
81bafa00ac | ||
|
|
84d0c17c4b | ||
|
|
77c0ba990d | ||
|
|
be7e2bed6f | ||
|
|
1d4487b6cd | ||
|
|
a7bfd0af41 | ||
|
|
55ef547a85 | ||
|
|
19129c8786 | ||
|
|
b5737ce9c1 | ||
|
|
f921d9a1f8 | ||
|
|
9609b48f2f | ||
|
|
ff8145b745 | ||
|
|
530e8b39e5 | ||
|
|
5926d396f9 | ||
|
|
50aeee288b | ||
|
|
72e001b0d5 | ||
|
|
f04c9d101e | ||
|
|
7cf16766c4 | ||
|
|
0e200e0c34 | ||
|
|
771a544d0f | ||
|
|
fba707f6a8 | ||
|
|
4e28e2cb59 | ||
|
|
2ecc53ba56 | ||
|
|
5c3c8b7b8a | ||
|
|
3eb1fe0eb2 | ||
|
|
aec998acc1 | ||
|
|
6a52a1dc63 | ||
|
|
91e758f66f | ||
|
|
441416b241 | ||
|
|
e541d8697e | ||
|
|
445825df44 | ||
|
|
b93c47fa60 | ||
|
|
4b817208aa | ||
|
|
90b831600f | ||
|
|
b3dd368920 | ||
|
|
c8db90b644 | ||
|
|
7ed65529df | ||
|
|
a8b59f5f59 | ||
|
|
eb966ec041 | ||
|
|
7fea0c3244 | ||
|
|
588789cb77 | ||
|
|
3640f977c8 | ||
|
|
28f12a4874 | ||
|
|
93378406c3 | ||
|
|
602d04af82 | ||
|
|
dcfbf2b154 | ||
|
|
bd13336256 | ||
|
|
815940913b | ||
|
|
f7191c0381 | ||
|
|
5c6d755750 | ||
|
|
3c545d488d | ||
|
|
bd0f84605f | ||
|
|
07d11c845c | ||
|
|
6e9a69be5c | ||
|
|
2e9bd477d9 | ||
|
|
392df6ba72 | ||
|
|
c66cffd6a6 | ||
|
|
b3b3e3ea20 | ||
|
|
b058fb8db4 | ||
|
|
9f0f6181a1 | ||
|
|
067a88b3e7 | ||
|
|
251d5f4135 | ||
|
|
f702e1a80d | ||
|
|
44e574f440 | ||
|
|
e1527fcbb9 | ||
|
|
9e583f9ff0 | ||
|
|
9ba7e5d567 | ||
|
|
02b6d53544 | ||
|
|
611816c8e3 | ||
|
|
0511a62ca1 | ||
|
|
31e34d6f19 | ||
|
|
5360fe49d4 | ||
|
|
bf94febb11 | ||
|
|
dbd3bd50df | ||
|
|
c1a1fb8d87 | ||
|
|
b10568e917 | ||
|
|
0e1ad39ede | ||
|
|
123bd0bb92 | ||
|
|
c8ce06d110 | ||
|
|
b0cfcb1999 | ||
|
|
6a8ed1192f | ||
|
|
0862859f93 | ||
|
|
3ad336a1eb | ||
|
|
a17f83cedd | ||
|
|
2c6850f6e4 | ||
|
|
5da47636cf | ||
|
|
944b857825 | ||
|
|
e04b965659 | ||
|
|
17d2fb80f2 | ||
|
|
34c8f33c3c | ||
|
|
07d74ee692 | ||
|
|
d28158bc74 | ||
|
|
14b7ec2a80 | ||
|
|
8c9fb956ff | ||
|
|
db632ae847 | ||
|
|
f27b31b581 | ||
|
|
8c44147a45 | ||
|
|
3bef4284e3 | ||
|
|
ec05215a5e | ||
|
|
5229b2959e | ||
|
|
8769234e28 | ||
|
|
bbdd1915eb | ||
|
|
5903e8256f | ||
|
|
c879351063 | ||
|
|
de8a244500 | ||
|
|
1bb7e36a65 | ||
|
|
3066a142b8 | ||
|
|
793a01f7ca | ||
|
|
ccf047b1ab | ||
|
|
40c8fdbf64 | ||
|
|
dc01c907f1 | ||
|
|
801df94446 | ||
|
|
0197d89976 | ||
|
|
ce725252cc | ||
|
|
e16a67242e | ||
|
|
4c678a5010 | ||
|
|
73f07b2939 | ||
|
|
b58efa3df0 | ||
|
|
9f885407f5 | ||
|
|
3754088a44 | ||
|
|
c4f084a991 | ||
|
|
4c73df4ba6 | ||
|
|
4aa53aa5a5 | ||
|
|
7483d3b229 | ||
|
|
8b6cc708e7 | ||
|
|
200960899e | ||
|
|
599a456c81 | ||
|
|
4b46502d22 | ||
|
|
7233c55428 | ||
|
|
a58c5cce78 | ||
|
|
0b23bf65b3 | ||
|
|
bc0a3f8a47 | ||
|
|
ef59fd4b6f | ||
|
|
9b2a0102be | ||
|
|
04b4ef6d85 | ||
|
|
9e8aadb750 | ||
|
|
36e7c2467e | ||
|
|
f7ce83ea34 | ||
|
|
0ae0f40628 | ||
|
|
81182bb125 | ||
|
|
2424df0d18 | ||
|
|
af9aa7d201 | ||
|
|
4cd3a614de | ||
|
|
1e5420e6a7 | ||
|
|
660de0b4e5 | ||
|
|
b73aaecd22 | ||
|
|
e9d07eadaa | ||
|
|
6f0e944c7e | ||
|
|
cd8d2c141e | ||
|
|
c831d62bc3 | ||
|
|
14ac66ff4e | ||
|
|
75bf758042 | ||
|
|
1539e703e9 | ||
|
|
f43bf03768 | ||
|
|
495f7f190f | ||
|
|
3acc521741 | ||
|
|
16216b9eb9 | ||
|
|
dfdb22f584 | ||
|
|
b7fb9e182b | ||
|
|
8574bf9d98 | ||
|
|
1a80439825 | ||
|
|
0b264176bc | ||
|
|
bde70a27f0 | ||
|
|
7d2f5f0799 | ||
|
|
28bc07da2f | ||
|
|
7610ab7a8d | ||
|
|
8517cc8211 | ||
|
|
51db653b1a | ||
|
|
8aa8ae239a | ||
|
|
dc4e4395a9 | ||
|
|
623694ab73 | ||
|
|
374457df70 | ||
|
|
7885dddef2 | ||
|
|
024ec86dc5 | ||
|
|
73d6cc1e54 | ||
|
|
f632ef0de8 | ||
|
|
8fdf84068d | ||
|
|
c58ad64a28 | ||
|
|
131625bb53 | ||
|
|
cbf3ae4db4 | ||
|
|
9ac7acf8b3 | ||
|
|
9dadb6da4c | ||
|
|
b6bbbeb9d3 | ||
|
|
517e9f92ba | ||
|
|
29c9e5cb17 | ||
|
|
52b60fd6a6 | ||
|
|
7ec09c80a5 | ||
|
|
b0bfe341df | ||
|
|
d6337f7500 | ||
|
|
70cf6546ca | ||
|
|
0cdab52418 | ||
|
|
625e04d208 | ||
|
|
6da657d3e2 | ||
|
|
777a95d23c | ||
|
|
06caace827 | ||
|
|
0a0a766c0d | ||
|
|
344c9e9238 | ||
|
|
89b2b066ef | ||
|
|
894e084c7f | ||
|
|
2ba064b2a5 | ||
|
|
dfe065ef82 | ||
|
|
7bd4b78470 | ||
|
|
d7991a247d | ||
|
|
2f9eacdf66 | ||
|
|
2178fd6ee9 | ||
|
|
7019ddb165 | ||
|
|
9f13763637 | ||
|
|
beeba27f46 | ||
|
|
79ac85e048 | ||
|
|
315d4f225a | ||
|
|
85489458d8 | ||
|
|
bfc7f56c4d | ||
|
|
23c5ddce83 | ||
|
|
7685f9b73d | ||
|
|
3bb9d220bb | ||
|
|
664fad96fa | ||
|
|
669a610e36 | ||
|
|
7e0d9cb48c | ||
|
|
7cbc9d21b5 | ||
|
|
62cb8358cc | ||
|
|
55b26751ae | ||
|
|
c2892d7887 | ||
|
|
6c8bf090fe | ||
|
|
ada5fd53e7 | ||
|
|
2f30451067 | ||
|
|
6b5c2be701 | ||
|
|
13bc378069 | ||
|
|
1ba70706c2 | ||
|
|
8431d0bd5c | ||
|
|
852f758be3 | ||
|
|
b455f432d5 | ||
|
|
6760744249 | ||
|
|
306cea60a1 | ||
|
|
ba2e07c4b9 | ||
|
|
9b796531b2 | ||
|
|
11c7d586d9 | ||
|
|
39cd83b171 | ||
|
|
2fdbc88d8c | ||
|
|
cc0f1be5d2 | ||
|
|
08d7a1c123 | ||
|
|
1f70a735c7 | ||
|
|
6713fcfeb1 | ||
|
|
c3107d213a | ||
|
|
adf5c8c278 | ||
|
|
5f86a8a15b | ||
|
|
042c756be8 | ||
|
|
1952505e52 | ||
|
|
c4086b9127 | ||
|
|
0ada09891c | ||
|
|
2d586406da | ||
|
|
651b4d2461 | ||
|
|
01b2468fea | ||
|
|
371c4e0051 | ||
|
|
69099fcdd7 | ||
|
|
28e714db1e | ||
|
|
57e50d0c33 | ||
|
|
a0fd02e0c0 | ||
|
|
c925b3d218 | ||
|
|
5da4386f31 | ||
|
|
4104dec87f | ||
|
|
d40a555531 | ||
|
|
95df91a03b | ||
|
|
3a8caa15b9 | ||
|
|
a5a25f02e3 | ||
|
|
bfd7be543a | ||
|
|
778e790e82 | ||
|
|
17eeb22971 | ||
|
|
1617658bfe | ||
|
|
991fe31569 | ||
|
|
4bcfff780a | ||
|
|
12f9ad8f7f | ||
|
|
6f843fcb27 | ||
|
|
e0f17e1778 | ||
|
|
4a5a9b73b1 | ||
|
|
7652336c84 | ||
|
|
94113827a7 | ||
|
|
cc10ee0134 | ||
|
|
5ad0fdf39c | ||
|
|
7201a8d634 | ||
|
|
3fde7365f9 | ||
|
|
f6a5bc9b40 | ||
|
|
9a5917a331 | ||
|
|
94c0324e8a | ||
|
|
d3b5594092 | ||
|
|
742d580eae | ||
|
|
d4a3cadd09 | ||
|
|
ec0feb68f4 | ||
|
|
bfb27c49a2 | ||
|
|
cb7b7f1dca | ||
|
|
38c032b79e | ||
|
|
2b7f2d4744 | ||
|
|
5ca8bc3f2a | ||
|
|
1ccc8eec0a | ||
|
|
9c5afda83a | ||
|
|
05b86a71fd | ||
|
|
d94d3d4bc5 | ||
|
|
e0c0f29fc6 | ||
|
|
119826cb9b | ||
|
|
6ab95ed4ef | ||
|
|
4f1eb64ac6 | ||
|
|
3e3dc3a6ab | ||
|
|
3f8dc76f84 | ||
|
|
8a6945ff3b | ||
|
|
f60579fd21 | ||
|
|
e6111c0d48 | ||
|
|
136a00a301 | ||
|
|
b2f5bee20d | ||
|
|
fa075f6800 | ||
|
|
277f395595 | ||
|
|
e2061464a5 | ||
|
|
04c4451f7d | ||
|
|
fcf5cd4655 | ||
|
|
3816f0b68b | ||
|
|
ccab1844ce | ||
|
|
5a6be54970 | ||
|
|
ce6b5105c6 | ||
|
|
de7da8b26e | ||
|
|
24932d6ba3 | ||
|
|
d5fd5954d1 | ||
|
|
977075763d | ||
|
|
757172934e | ||
|
|
1a2543ddde | ||
|
|
1a520f8782 | ||
|
|
b56c1b956c | ||
|
|
1a279d14c4 | ||
|
|
0d8e763a5f | ||
|
|
bf6d3649a4 | ||
|
|
7c9db7edeb | ||
|
|
65fd705d9a | ||
|
|
311e54451b | ||
|
|
8b759bc5d9 | ||
|
|
9a0aac4745 | ||
|
|
cb6607a169 | ||
|
|
8caa4e9cb6 | ||
|
|
d6338d7b11 | ||
|
|
f96a5ec774 | ||
|
|
1be8e7e216 | ||
|
|
cf9cf9d7bb | ||
|
|
6ba1795ded | ||
|
|
ced0cc1bac | ||
|
|
3c49f22266 | ||
|
|
13ae99edec | ||
|
|
0f82730a78 | ||
|
|
8608c45309 | ||
|
|
90516217e0 | ||
|
|
ff083daf31 | ||
|
|
7f6a554e1b | ||
|
|
eb99271120 | ||
|
|
04aa22b510 | ||
|
|
13e5c695c3 | ||
|
|
1cd56decab | ||
|
|
585f8f4683 | ||
|
|
12de47c923 | ||
|
|
afde7940d8 | ||
|
|
1070d8d3fa | ||
|
|
dcc7ba8f93 | ||
|
|
01dd41bdbf | ||
|
|
7d5b20314c | ||
|
|
29e048af7b | ||
|
|
f3b84f1365 | ||
|
|
5751d5c1b0 | ||
|
|
3d2336aac1 | ||
|
|
afe5f19464 | ||
|
|
4091a3c238 | ||
|
|
c38f0d751b | ||
|
|
3623afa721 | ||
|
|
f411e07fb4 | ||
|
|
9bfe27dd5e | ||
|
|
6a096fbb27 | ||
|
|
c4201d9a2a | ||
|
|
58e9817a6d | ||
|
|
48d5584491 | ||
|
|
6404071a01 | ||
|
|
735205492e | ||
|
|
5786f1d057 | ||
|
|
87c6f3c757 | ||
|
|
a6feb77e52 | ||
|
|
0e99c948d6 | ||
|
|
0f5e0f640b | ||
|
|
3d2c6388de | ||
|
|
13b3b2fd23 | ||
|
|
ad8e614ae8 | ||
|
|
9a6d709082 | ||
|
|
48c0360877 | ||
|
|
6eafab8286 | ||
|
|
d230be3e1c | ||
|
|
daa77d40a3 | ||
|
|
c901512db0 | ||
|
|
6ae743684f | ||
|
|
789c00dde1 | ||
|
|
90da471084 | ||
|
|
2d55056015 | ||
|
|
ffab9bb893 | ||
|
|
1192d04391 | ||
|
|
f18dced2f3 | ||
|
|
31ea032054 | ||
|
|
89543e927a | ||
|
|
a52386e6ad | ||
|
|
ecdc0a3800 | ||
|
|
46d66dded8 | ||
|
|
a69dcfc49d | ||
|
|
601005f837 | ||
|
|
de6f32e486 | ||
|
|
fbe866198d | ||
|
|
70546cd2ec | ||
|
|
a7c99cbbd2 | ||
|
|
40780ccec7 | ||
|
|
7078c91f7d | ||
|
|
0e2168392c | ||
|
|
380006c9d8 | ||
|
|
4127882e5f | ||
|
|
d603a8a9be | ||
|
|
5f17d30973 | ||
|
|
8f92077454 | ||
|
|
8755a9bcda | ||
|
|
6ace46eece | ||
|
|
37cab07295 | ||
|
|
4a1ecc7b72 | ||
|
|
e46078286d | ||
|
|
cfeb88f649 | ||
|
|
7ce197e0c8 | ||
|
|
f93b1167f1 | ||
|
|
152ca63529 | ||
|
|
806221bc3f | ||
|
|
2e8d5311a5 | ||
|
|
23b5fd1c12 | ||
|
|
7a8ba7d47d | ||
|
|
1a509cf3e0 | ||
|
|
9848f9613c | ||
|
|
4264c2a173 | ||
|
|
93cefb88f5 | ||
|
|
7132e1fee1 | ||
|
|
e70e1b8ad7 | ||
|
|
77d8a8e43d | ||
|
|
0b75a7d0d3 | ||
|
|
1f4a15ee6b | ||
|
|
f6772eaf59 | ||
|
|
bab4f9963f | ||
|
|
1dbcac4f53 | ||
|
|
7ac5abe7f8 | ||
|
|
157e6b2a33 | ||
|
|
8d20a13776 | ||
|
|
a385ea7c52 | ||
|
|
c58a3c41d8 | ||
|
|
0a7df86f3f | ||
|
|
213bc75ae1 | ||
|
|
f8df7ebb7c | ||
|
|
60503c31fb | ||
|
|
77220e24dd | ||
|
|
3c25e11c5f | ||
|
|
be2ffc31b2 | ||
|
|
8a2256e0d8 | ||
|
|
adfb24ce02 | ||
|
|
e6d50f94ee | ||
|
|
520798bfa6 | ||
|
|
e539a36ae7 | ||
|
|
bfab2d405b | ||
|
|
df38f00cf2 | ||
|
|
a30ce1c44d | ||
|
|
eee2450c9e | ||
|
|
baf4a241a2 | ||
|
|
e2242f5d99 | ||
|
|
30df67721d | ||
|
|
4a20f43fbf | ||
|
|
c59e792178 | ||
|
|
e6a99c1d33 | ||
|
|
3548628c2c | ||
|
|
bb84157a21 | ||
|
|
eb10aa8c97 | ||
|
|
e06d269b82 | ||
|
|
07428922c3 | ||
|
|
0f7e22d8b7 | ||
|
|
ba4c3e3852 | ||
|
|
b8de36b340 | ||
|
|
bbe3e8093c | ||
|
|
26096bc136 | ||
|
|
caae57d960 | ||
|
|
f91384596c | ||
|
|
cb38976162 | ||
|
|
3460f9d9cc | ||
|
|
6eacf8ed7e | ||
|
|
20bebe98b1 | ||
|
|
91d885eae4 | ||
|
|
ea3358ecb2 | ||
|
|
4c5c4d1700 | ||
|
|
e3fabe92bd | ||
|
|
142740f080 | ||
|
|
09e51c2399 | ||
|
|
0892eb271d | ||
|
|
536be76ecb | ||
|
|
6bfdf0eb4d | ||
|
|
8320ed5a92 | ||
|
|
43677685bb | ||
|
|
61e0aa9845 | ||
|
|
34eee005a8 | ||
|
|
6fa136da0c | ||
|
|
9b3e6270d5 | ||
|
|
b5abc6c724 | ||
|
|
71edc3a084 | ||
|
|
f74a45a33e | ||
|
|
0a1d04495d | ||
|
|
49dee560fd | ||
|
|
dfb3dfb74d | ||
|
|
05521bfd3a | ||
|
|
6c997f573a | ||
|
|
c4689c3bcc | ||
|
|
c0dd98b6d7 | ||
|
|
83452d73bc | ||
|
|
e5417d12ca | ||
|
|
6e19e6f0a0 | ||
|
|
071281c13a | ||
|
|
56cf1c818b | ||
|
|
61101987f9 | ||
|
|
a057e50684 | ||
|
|
5f3dc660c8 | ||
|
|
5553964d52 | ||
|
|
51ead2f6bd | ||
|
|
d433b25627 | ||
|
|
bd7671c07e | ||
|
|
847178b7be | ||
|
|
90808ac67e | ||
|
|
a899ea8b4d | ||
|
|
7b83b99ac9 | ||
|
|
7aab7678e9 | ||
|
|
195af002cf | ||
|
|
38db8d2bfd | ||
|
|
44a9fed8a9 | ||
|
|
cfc346abad | ||
|
|
befeb55349 | ||
|
|
b460d0f533 | ||
|
|
c11acb6308 | ||
|
|
d76103eb76 | ||
|
|
779f984a30 | ||
|
|
9c55017191 | ||
|
|
c6f575d8d3 | ||
|
|
2c0c22dbf3 | ||
|
|
73a99a7dea | ||
|
|
3c81337630 | ||
|
|
3f41ba6bdf | ||
|
|
2812f61957 | ||
|
|
f23cee17eb | ||
|
|
746a8badac | ||
|
|
f24fcfca69 | ||
|
|
d60506a75d | ||
|
|
77dee439e6 | ||
|
|
d7790a04c5 | ||
|
|
2c0b07387b | ||
|
|
06f2f9adbb | ||
|
|
37d5b9109f | ||
|
|
76e269ee21 | ||
|
|
3103939197 | ||
|
|
3f01c87223 | ||
|
|
e4cda4bb99 | ||
|
|
f333f867c5 | ||
|
|
75c46f7a0e | ||
|
|
5c6cb41124 | ||
|
|
94f7c03871 | ||
|
|
96d5c03a6d | ||
|
|
3a03bc41a7 | ||
|
|
331844ff73 | ||
|
|
2bc38e3784 | ||
|
|
d580dedfc8 | ||
|
|
aa0f4c9985 | ||
|
|
aa242d897d | ||
|
|
d56ab6c971 | ||
|
|
2f7be3475d | ||
|
|
2544d2e068 | ||
|
|
a09f64aee5 | ||
|
|
f7114fc2aa | ||
|
|
7092f337ef | ||
|
|
8e71c3ae17 | ||
|
|
a9c211d66c | ||
|
|
a1c2c04510 | ||
|
|
0902b628f8 | ||
|
|
517a85f9e9 | ||
|
|
94941a7732 | ||
|
|
f3aa8d368e | ||
|
|
9518c5f2e4 | ||
|
|
e44173ff09 | ||
|
|
fa1106d3cf | ||
|
|
c24d574f90 | ||
|
|
8ed35652bc | ||
|
|
9bdcfc8a45 | ||
|
|
89b76b514c | ||
|
|
dd433d8af0 | ||
|
|
c105f3b970 | ||
|
|
94471c0d1c | ||
|
|
849e04ab83 | ||
|
|
67833c5513 | ||
|
|
b0306867b4 | ||
|
|
d5025fdbcc | ||
|
|
e6cf1dc98d | ||
|
|
0266370218 | ||
|
|
aeb3f2b018 | ||
|
|
bb8d5ac13f | ||
|
|
d02bf37167 | ||
|
|
99dbd9e649 | ||
|
|
0d63dad8c2 | ||
|
|
6ce465664f | ||
|
|
b934634159 | ||
|
|
ef904e01ec | ||
|
|
25b77db4cd | ||
|
|
88c0a9e30a | ||
|
|
75c219d6c6 | ||
|
|
82e7328903 | ||
|
|
d6b366c77f | ||
|
|
42a7c84a33 | ||
|
|
1f4c1f2af5 | ||
|
|
e665e4dc57 | ||
|
|
9551519a35 | ||
|
|
df51b80e07 | ||
|
|
0df6826c91 | ||
|
|
af61962314 | ||
|
|
f5ed710c0b | ||
|
|
e5ae07b3e8 | ||
|
|
f1535e1f71 | ||
|
|
a6316b40d1 | ||
|
|
c2746a55e3 | ||
|
|
e9c782bf9e | ||
|
|
ad6c154eb6 | ||
|
|
b747b10642 | ||
|
|
2005a2abd4 | ||
|
|
c5818ff5e4 | ||
|
|
b5e02e6ff9 | ||
|
|
205f62e732 | ||
|
|
fdc8b5eb54 | ||
|
|
36abe8e808 | ||
|
|
fcf0e08e01 | ||
|
|
0edcf97e3f | ||
|
|
0707b26303 | ||
|
|
09662a4bcd | ||
|
|
cb06961b82 | ||
|
|
824fb4adae | ||
|
|
a91d993c6d | ||
|
|
e16bab8dd9 | ||
|
|
068c5851ef | ||
|
|
af48dcd884 | ||
|
|
058806c241 | ||
|
|
48f6e33bf2 | ||
|
|
6a3ef42d37 | ||
|
|
f10a9d7f61 | ||
|
|
c315c04b9a | ||
|
|
f7893d4e4b | ||
|
|
2e2f7fa6c3 | ||
|
|
7aff64f877 | ||
|
|
0d05bc2676 | ||
|
|
131b350ee7 | ||
|
|
06651dbc4c | ||
|
|
0296247d82 | ||
|
|
79e767ba79 | ||
|
|
f771dee852 | ||
|
|
c4d8ef5954 | ||
|
|
5d6b97a63e | ||
|
|
c277ebb43e | ||
|
|
c9cd7b087a | ||
|
|
da7ff52a2f | ||
|
|
84e4a4bb52 | ||
|
|
34c9c5a9b1 | ||
|
|
e348e66f14 | ||
|
|
1e83614f8b | ||
|
|
c53647cd18 | ||
|
|
faa4e7753c | ||
|
|
220757be06 | ||
|
|
7f1013123a | ||
|
|
b1a7fe0f80 | ||
|
|
153e6b56ba | ||
|
|
35998df05c | ||
|
|
5176a8cb9e | ||
|
|
4892b648ae | ||
|
|
b4506c2b9b | ||
|
|
4373163869 | ||
|
|
4b8cde7b3b | ||
|
|
b7543c8a45 | ||
|
|
b5232886d9 | ||
|
|
aefd81228e | ||
|
|
03516e11f7 | ||
|
|
455a17cdb2 | ||
|
|
564ad09b98 | ||
|
|
135f6b0050 | ||
|
|
d5e79ff36c | ||
|
|
7a7f34746e | ||
|
|
6b4bbe625b | ||
|
|
28c0b2737b | ||
|
|
7684fb83d6 | ||
|
|
4d22608724 | ||
|
|
b7a42d61c4 | ||
|
|
bdaef7e541 | ||
|
|
854501385e | ||
|
|
7b875ed378 | ||
|
|
c930d6ddc0 | ||
|
|
aab2e4555a | ||
|
|
938eefae9b | ||
|
|
eccc5e6d61 | ||
|
|
bc96ca48b6 | ||
|
|
e5dd88cdce | ||
|
|
51acd4952b | ||
|
|
88e0da765c | ||
|
|
3ba708b98d | ||
|
|
dfb6216271 | ||
|
|
70387e6976 | ||
|
|
55fd781c77 | ||
|
|
36a0a240f9 | ||
|
|
ed0b507fb5 | ||
|
|
3a3948e74f | ||
|
|
c01dd232c5 | ||
|
|
825cc096c0 | ||
|
|
bcd574036e | ||
|
|
634fe64dca | ||
|
|
e33a0bf940 | ||
|
|
fb91d9b2d4 | ||
|
|
3d89588eb1 | ||
|
|
ac010cd7b2 | ||
|
|
d0c94ba565 | ||
|
|
adbeb4ae54 | ||
|
|
c7e1b47c59 | ||
|
|
b25e22bca4 | ||
|
|
6cb6a8ee98 | ||
|
|
223bd969fd | ||
|
|
ae46eeabef | ||
|
|
79c83a96a0 | ||
|
|
db33eb5b1f | ||
|
|
bc45f8f1d8 | ||
|
|
7875a96137 | ||
|
|
4875f5e275 | ||
|
|
7f9da22626 | ||
|
|
78098e612d | ||
|
|
e19ab9a0d5 | ||
|
|
ace45516d9 | ||
|
|
fe57bfce1b | ||
|
|
453cc0cc05 | ||
|
|
39009c482d | ||
|
|
6b942be1cd | ||
|
|
77aa2b6ba9 | ||
|
|
074d53fa17 | ||
|
|
a839ec4832 | ||
|
|
5119799256 | ||
|
|
176e18e4c0 | ||
|
|
b697df35c6 | ||
|
|
5236625485 | ||
|
|
f36073f5cd | ||
|
|
595fd9377c | ||
|
|
76f4c49e22 | ||
|
|
8c0592cdb7 | ||
|
|
0c73ecf6a8 | ||
|
|
c365fd9d74 | ||
|
|
aa8c587ac8 | ||
|
|
e9d9760e16 | ||
|
|
560f72a320 | ||
|
|
3425f2bf34 | ||
|
|
e28dbb3b93 | ||
|
|
1b3ed80d37 | ||
|
|
89a2e15cfb | ||
|
|
99b1282e98 | ||
|
|
ed753b590c | ||
|
|
bda095b0ec | ||
|
|
9d7f1d230c | ||
|
|
bdf0458780 | ||
|
|
7f973ad131 | ||
|
|
1f42070104 | ||
|
|
98e4ac6b27 | ||
|
|
8d318e7206 | ||
|
|
362156c8ab | ||
|
|
3ff23ade8b | ||
|
|
d9050dd8b9 | ||
|
|
bcee2c37d7 | ||
|
|
b8fcab29ac | ||
|
|
8ddae6bba0 | ||
|
|
fc9255cdc4 | ||
|
|
f725506df0 | ||
|
|
aa27b85538 | ||
|
|
afe75f8a89 | ||
|
|
b725d66ee3 | ||
|
|
fe3fb622ee | ||
|
|
e8bd114c01 | ||
|
|
b694bcf62a | ||
|
|
b0f933c926 | ||
|
|
2d12bc01de | ||
|
|
17b4ff7a1f | ||
|
|
6aff9f91d5 | ||
|
|
cac8fd93e4 | ||
|
|
f046abefbc | ||
|
|
b34e060b17 | ||
|
|
907be77ef4 | ||
|
|
373d12be64 | ||
|
|
bf45d55b4a | ||
|
|
2525429070 | ||
|
|
2513bcf2c6 | ||
|
|
bbffb6d901 | ||
|
|
3b7f5a1397 | ||
|
|
600e949628 | ||
|
|
235c123ad0 | ||
|
|
dcea584a9a | ||
|
|
d583adb958 | ||
|
|
0d96a0fb7c | ||
|
|
fb6b2cbfa2 | ||
|
|
eb65eafbe0 | ||
|
|
13f18492ad | ||
|
|
3d04541ee3 | ||
|
|
6ded0cce12 | ||
|
|
1ecbaf2c7f | ||
|
|
b0828a6280 | ||
|
|
d2ffb3ca9d | ||
|
|
606cd18dc4 | ||
|
|
8a713b2bbb | ||
|
|
c68f31a11c | ||
|
|
3107943af8 | ||
|
|
bf9360f374 | ||
|
|
f66c28a1bc | ||
|
|
5d6e214e0e | ||
|
|
ee8596d175 | ||
|
|
3c900814be | ||
|
|
52df963be9 | ||
|
|
8c513c2aad | ||
|
|
1e3834dc3d | ||
|
|
386b10a004 | ||
|
|
f697f3d7ad | ||
|
|
8d3ff16037 | ||
|
|
b10ab358da | ||
|
|
2cc6edd868 | ||
|
|
cac974b8e1 | ||
|
|
2c02e27197 | ||
|
|
85c0002a78 | ||
|
|
bd65bf2175 | ||
|
|
d70332f2a2 | ||
|
|
35b54e2f88 | ||
|
|
a3e1af72ab | ||
|
|
1313a44ba3 | ||
|
|
edbe8131ab | ||
|
|
ff55a305cd | ||
|
|
10c22efbb5 | ||
|
|
118bbfbcf7 | ||
|
|
e7709d8463 | ||
|
|
d70e421db3 | ||
|
|
0028c3c640 | ||
|
|
2594cb23c4 | ||
|
|
d975f6e23a | ||
|
|
5e46975c63 | ||
|
|
16f41fc4b4 | ||
|
|
1263f5e046 | ||
|
|
96713ef383 | ||
|
|
26a8686a54 | ||
|
|
57421d2392 | ||
|
|
63d92381ee | ||
|
|
2716f4cbe9 | ||
|
|
6ef4582ebd | ||
|
|
649ebb8a4e | ||
|
|
b1acf6088f | ||
|
|
78f5d80c5b | ||
|
|
5896b1eb71 | ||
|
|
559891ac43 | ||
|
|
1fbe1d1855 | ||
|
|
71473fd5c4 | ||
|
|
c7beacf3b9 | ||
|
|
3dc55ff8b5 | ||
|
|
b6789e0011 | ||
|
|
2f2bebe506 | ||
|
|
503b8cbf34 | ||
|
|
916356afad | ||
|
|
41a84160ec | ||
|
|
55f071e4a0 | ||
|
|
0afe0f8fbd | ||
|
|
427b5bd126 | ||
|
|
20f6378a3e | ||
|
|
36e0a1eb23 | ||
|
|
ac9a567e1f | ||
|
|
33cd52cddd | ||
|
|
d543ba82ac | ||
|
|
5a98993df9 | ||
|
|
aee9c4a193 | ||
|
|
0262f89bb0 | ||
|
|
a8c530a3a9 | ||
|
|
7dc1240c18 | ||
|
|
3b4bccd0a7 | ||
|
|
39a80f8dc7 | ||
|
|
ce446dac92 | ||
|
|
b1c9dbd0a5 | ||
|
|
a5c57d7fb0 | ||
|
|
0a349e5298 | ||
|
|
dc7d7150cd | ||
|
|
7c4aa4441f | ||
|
|
62a795bd3b | ||
|
|
c583ab4f1a | ||
|
|
45a2970307 | ||
|
|
56a74bc54c | ||
|
|
5a4b719995 | ||
|
|
34a4a89bc9 | ||
|
|
02989f65ff | ||
|
|
1da539ef05 | ||
|
|
38d6fbd3d3 | ||
|
|
39682a4cf1 | ||
|
|
993a5805cd | ||
|
|
09cf528cc6 | ||
|
|
18ab2b3ab5 | ||
|
|
655fbf91e2 | ||
|
|
980794ea43 | ||
|
|
c1cab30daf | ||
|
|
b50e798d55 | ||
|
|
230e3ef842 | ||
|
|
2635a3edd0 | ||
|
|
47f24ac151 | ||
|
|
42397a01bf | ||
|
|
7730a00dbb | ||
|
|
3a4f4c8c34 | ||
|
|
a0d88b0cbe | ||
|
|
bb0419837b | ||
|
|
35098c474c | ||
|
|
0ca6535345 | ||
|
|
ec6a243e3e | ||
|
|
2cd8ee4a13 | ||
|
|
432755e05d | ||
|
|
51a7c2adc5 | ||
|
|
5c1f793887 | ||
|
|
a20358b61b | ||
|
|
e5dc473ced | ||
|
|
e57a518b34 | ||
|
|
341d9d1697 | ||
|
|
9cee424383 | ||
|
|
37cb51cfd6 | ||
|
|
533f86c035 | ||
|
|
9947c51af7 | ||
|
|
409303d0f5 | ||
|
|
84b7bfb989 | ||
|
|
04d17e4839 | ||
|
|
10a1275a52 | ||
|
|
5464cbc2ed | ||
|
|
3b3f8e6f43 | ||
|
|
2d4d7bf937 | ||
|
|
652651668f | ||
|
|
e57d5d86f3 | ||
|
|
4f7dc5be34 | ||
|
|
b2c656940b | ||
|
|
f8266d9811 | ||
|
|
5c03550a8a | ||
|
|
ed5491a480 | ||
|
|
e8371f403b | ||
|
|
373cffb261 | ||
|
|
2bf22766eb | ||
|
|
83530fcaf1 | ||
|
|
6a41123209 | ||
|
|
c895c5c16e | ||
|
|
9ab4b3f3f4 | ||
|
|
b93dd47a01 | ||
|
|
69a826f896 | ||
|
|
60c7ec5aca | ||
|
|
888eacb574 | ||
|
|
4def582ab1 | ||
|
|
ee6f25cc47 | ||
|
|
f5d6383f50 | ||
|
|
00f00b8198 | ||
|
|
3d1f883465 | ||
|
|
8613a89931 | ||
|
|
dd1485a66a | ||
|
|
4198954d46 | ||
|
|
e56caa8959 | ||
|
|
de7c72d5a7 | ||
|
|
18a4a43f8a | ||
|
|
70c73d2e0e | ||
|
|
2049e8b8df | ||
|
|
41da889a09 | ||
|
|
0a1bbca321 | ||
|
|
7e01d113d8 | ||
|
|
6e49cc54ac | ||
|
|
487a95eb79 | ||
|
|
696e438df7 | ||
|
|
a4e093159e | ||
|
|
23986579bb | ||
|
|
0fc099926f | ||
|
|
06b9b66272 | ||
|
|
fec8343f45 | ||
|
|
2d8f2593f0 | ||
|
|
ab0a03a420 | ||
|
|
3ef30a42be | ||
|
|
034687163f | ||
|
|
190db80c28 | ||
|
|
579f355852 | ||
|
|
d9104433a8 | ||
|
|
c6059f9bf6 | ||
|
|
fd06ff08c7 | ||
|
|
afd990bd71 | ||
|
|
8333c4b48d | ||
|
|
30c4f501fc | ||
|
|
3b96eef2ad | ||
|
|
a769ab6cff | ||
|
|
ef1f835e57 | ||
|
|
329b2ba275 | ||
|
|
98383ef19b | ||
|
|
8bb70fb1b0 | ||
|
|
72cca365e5 | ||
|
|
dfc99faea8 | ||
|
|
71886c162b | ||
|
|
df1f516f6b | ||
|
|
2e55189d59 | ||
|
|
6ade40ce85 | ||
|
|
94c5f0d7a8 | ||
|
|
69a2ac8de1 | ||
|
|
b1028086a3 | ||
|
|
385b3570b2 | ||
|
|
77edd12030 | ||
|
|
217fca31e4 | ||
|
|
5e1d20fc72 | ||
|
|
db60309ce8 | ||
|
|
8bfae2fa74 | ||
|
|
2788dd1ada | ||
|
|
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 | ||
|
|
a7092ac503 | ||
|
|
fb59f1f0a0 | ||
|
|
b1961033b3 | ||
|
|
863498f762 | ||
|
|
bdc44a4070 | ||
|
|
6451522f89 | ||
|
|
5ca1e9268c | ||
|
|
451a6841c9 | ||
|
|
3e3f46a683 | ||
|
|
2b0eaafea6 | ||
|
|
0cc1007543 | ||
|
|
8ca86181e4 | ||
|
|
036bd07e72 | ||
|
|
cb0452964e | ||
|
|
8d66d38fd2 | ||
|
|
21fe2c5f8f | ||
|
|
c9025917b2 | ||
|
|
680923bdd5 | ||
|
|
cde360f7ec | ||
|
|
adcd7fb170 | ||
|
|
f105436b41 | ||
|
|
47738c751c | ||
|
|
0b3f2da6ef | ||
|
|
8f36878dde | ||
|
|
e610a1ffe4 | ||
|
|
b5213794a8 | ||
|
|
447f15cfa4 | ||
|
|
3d0d027216 | ||
|
|
b58a17a99e | ||
|
|
adaf2e15cd | ||
|
|
9cd0a7982a | ||
|
|
607a66b983 | ||
|
|
38b2adcaad | ||
|
|
d7879d8853 | ||
|
|
1042ac141a | ||
|
|
81aab35231 | ||
|
|
1c5742c7d4 | ||
|
|
4d646e67f3 | ||
|
|
59fbc51283 | ||
|
|
71af63dfc7 | ||
|
|
0cae048ada | ||
|
|
71021da261 | ||
|
|
1d897e491a | ||
|
|
57c0b408e5 | ||
|
|
43e0186efe | ||
|
|
8831d74cbc | ||
|
|
9a9d2cb964 | ||
|
|
2fc2a0cbdb | ||
|
|
40c041c9e7 | ||
|
|
b00c1dd055 | ||
|
|
761245049f | ||
|
|
30e142edd3 | ||
|
|
b7d84c002d | ||
|
|
551afe0cd7 | ||
|
|
5d8bfc2930 | ||
|
|
5d947cc8e1 | ||
|
|
7bf92db4c9 | ||
|
|
593c1d6b05 | ||
|
|
30e326b8b8 | ||
|
|
bed52d0a4a | ||
|
|
8048bb85fb | ||
|
|
d9d2ad4382 | ||
|
|
3379e7cc48 | ||
|
|
339be2b7a4 | ||
|
|
a8a61665f4 | ||
|
|
65154e48cb | ||
|
|
19f6fd2295 |
17
.devcontainer/Dockerfile
Normal file
17
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.148.1/containers/python-3/.devcontainer/base.Dockerfile
|
||||
|
||||
# [Choice] Python version: 3, 3.9, 3.8, 3.7, 3.6
|
||||
ARG VARIANT="3"
|
||||
FROM mcr.microsoft.com/devcontainers/python:0-${VARIANT}
|
||||
|
||||
# [Optional] If your pip requirements rarely change, uncomment this section to add them to the image.
|
||||
# COPY requirements.txt /tmp/pip-tmp/
|
||||
# RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \
|
||||
# && rm -rf /tmp/pip-tmp
|
||||
|
||||
# [Optional] Uncomment this section to install additional OS packages.
|
||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||
|
||||
# [Optional] Uncomment this line to install global node packages.
|
||||
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
|
||||
60
.devcontainer/devcontainer.json
Normal file
60
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "Python 3",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"context": "..",
|
||||
"args": {
|
||||
// Update 'VARIANT' to pick a Python version: 3, 3.6, 3.7, 3.8, 3.9
|
||||
"VARIANT": "3"
|
||||
}
|
||||
},
|
||||
|
||||
// To give the container access to a device serial port, you can uncomment one of the following lines.
|
||||
// Note: If running on Windows, you will have to do some additional steps:
|
||||
// https://stackoverflow.com/questions/68527888/how-can-i-use-a-usb-com-port-inside-of-a-vscode-development-container
|
||||
//
|
||||
// You can explicitly just forward the port you want to connect to. Replace `/dev/ttyACM0` with the serial port for
|
||||
// your device. This will only work if the device is plugged in from the start without reconnecting. Adding the
|
||||
// `dialout` group is needed if read/write permisions for the port are limitted to the dialout user.
|
||||
// "runArgs": ["--device=/dev/ttyACM0", "--group-add", "dialout"],
|
||||
//
|
||||
// Alternatively, you can give more comprehensive access to the host system. This will expose all the host devices to
|
||||
// the container. Adding the `dialout` group is needed if read/write permisions for the port are limitted to the
|
||||
// dialout user. This could allow the container to modify unrelated serial devices, which would be a similar level of
|
||||
// risk to running the build directly on the host.
|
||||
// "runArgs": ["--privileged", "-v", "/dev/bus/usb:/dev/bus/usb", "--group-add", "dialout"],
|
||||
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/bash",
|
||||
"python.pythonPath": "/usr/local/bin/python",
|
||||
"python.linting.enabled": true,
|
||||
"python.linting.pylintEnabled": true,
|
||||
"python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
|
||||
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
|
||||
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
|
||||
"python.linting.banditPath": "/usr/local/py-utils/bin/bandit",
|
||||
"python.linting.flake8Path": "/usr/local/py-utils/bin/flake8",
|
||||
"python.linting.mypyPath": "/usr/local/py-utils/bin/mypy",
|
||||
"python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle",
|
||||
"python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle",
|
||||
"python.linting.pylintPath": "/usr/local/py-utils/bin/pylint"
|
||||
},
|
||||
"extensions": [
|
||||
"ms-python.python",
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "bash -i -c 'nvm install && npm ci'",
|
||||
|
||||
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "vscode"
|
||||
}
|
||||
|
||||
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
github: [Aircoookie,blazoncek,DedeHai,lost-hope,willmmiles]
|
||||
custom: ['https://paypal.me/Aircoookie','https://paypal.me/blazoncek']
|
||||
thanks_dev: u/gh/netmindz
|
||||
86
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
86
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
name: Bug Report
|
||||
description: File a bug report
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please quickly search existing issues first before submitting a bug.
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: A clear and concise description of what the bug is.
|
||||
placeholder: Tell us what the problem is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: how-to-reproduce
|
||||
attributes:
|
||||
label: To Reproduce Bug
|
||||
description: Steps to reproduce the behavior, if consistently possible.
|
||||
placeholder: Tell us how to make the bug appear.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
placeholder: Tell us what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: install_format
|
||||
attributes:
|
||||
label: Install Method
|
||||
description: How did you install WLED?
|
||||
options:
|
||||
- Binary from WLED.me
|
||||
- Self-Compiled
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: What version of WLED?
|
||||
description: You can find this in by going to Config -> Security & Updates -> Scroll to Bottom. Copy and paste the entire line after "Server message"
|
||||
placeholder: "e.g. WLED 0.13.1 (build 2203150)"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: Board
|
||||
attributes:
|
||||
label: Which microcontroller/board are you seeing the problem on?
|
||||
multiple: true
|
||||
options:
|
||||
- ESP8266
|
||||
- ESP32
|
||||
- ESP32-S3
|
||||
- ESP32-S2
|
||||
- ESP32-C3
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log/trace output
|
||||
description: Please copy and paste any relevant log output if you have it. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Links? References? Anything that will give us more context about the issue you are encountering!
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Code of Conduct
|
||||
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/wled-dev/WLED/blob/main/CODE_OF_CONDUCT.md)
|
||||
options:
|
||||
- label: I agree to follow this project's Code of Conduct
|
||||
required: true
|
||||
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: WLED Discord community
|
||||
url: https://discord.gg/KuqP7NE
|
||||
about: Please ask and answer questions and discuss setup issues here!
|
||||
- name: WLED community forum
|
||||
url: https://wled.discourse.group/
|
||||
about: For issues and ideas that might need longer discussion.
|
||||
- name: kno.wled.ge base
|
||||
url: https://kno.wled.ge/basics/faq/
|
||||
about: Take a look at the frequently asked questions and documentation, perhaps your question is already answered!
|
||||
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an improvement idea for WLED!
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
||||
Thank you for your ideas for making WLED better!
|
||||
172
.github/copilot-instructions.md
vendored
Normal file
172
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
# WLED - ESP32/ESP8266 LED Controller Firmware
|
||||
|
||||
WLED is a fast and feature-rich implementation of an ESP32 and ESP8266 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs and SPI-based chipsets. The project consists of C++ firmware for microcontrollers and a modern web interface.
|
||||
|
||||
Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.
|
||||
|
||||
## Working Effectively
|
||||
|
||||
### Initial Setup
|
||||
- Install Node.js 20+ (specified in `.nvmrc`): Check your version with `node --version`
|
||||
- Install dependencies: `npm ci` (takes ~5 seconds)
|
||||
- Install PlatformIO for hardware builds: `pip install -r requirements.txt` (takes ~60 seconds)
|
||||
|
||||
### Build and Test Workflow
|
||||
- **ALWAYS build web UI first**: `npm run build` -- takes 3 seconds. NEVER CANCEL.
|
||||
- **Run tests**: `npm test` -- takes 40 seconds. NEVER CANCEL. Set timeout to 2+ minutes.
|
||||
- **Development mode**: `npm run dev` -- monitors file changes and auto-rebuilds web UI
|
||||
- **Hardware firmware build**: `pio run -e [environment]` -- takes 15+ minutes. NEVER CANCEL. Set timeout to 30+ minutes.
|
||||
|
||||
### Build Process Details
|
||||
The build has two main phases:
|
||||
1. **Web UI Generation** (`npm run build`):
|
||||
- Processes files in `wled00/data/` (HTML, CSS, JS)
|
||||
- Minifies and compresses web content
|
||||
- Generates `wled00/html_*.h` files with embedded web content
|
||||
- **CRITICAL**: Must be done before any hardware build
|
||||
|
||||
2. **Hardware Compilation** (`pio run`):
|
||||
- Compiles C++ firmware for various ESP32/ESP8266 targets
|
||||
- Common environments: `nodemcuv2`, `esp32dev`, `esp8266_2m`
|
||||
- List all targets: `pio run --list-targets`
|
||||
|
||||
## Before Finishing Work
|
||||
|
||||
**CRITICAL: You MUST complete ALL of these steps before marking your work as complete:**
|
||||
|
||||
1. **Run the test suite**: `npm test` -- Set timeout to 2+ minutes. NEVER CANCEL.
|
||||
- All tests MUST pass
|
||||
- If tests fail, fix the issue before proceeding
|
||||
|
||||
2. **Build at least one hardware environment**: `pio run -e esp32dev` -- Set timeout to 30+ minutes. NEVER CANCEL.
|
||||
- Choose `esp32dev` as it's a common, representative environment
|
||||
- See "Hardware Compilation" section above for the full list of common environments
|
||||
- The build MUST complete successfully without errors
|
||||
- If the build fails, fix the issue before proceeding
|
||||
- **DO NOT skip this step** - it validates that firmware compiles with your changes
|
||||
|
||||
3. **For web UI changes only**: Manually test the interface
|
||||
- See "Manual Testing Scenarios" section below
|
||||
- Verify the UI loads and functions correctly
|
||||
|
||||
**If any of these validation steps fail, you MUST fix the issues before finishing. Do NOT mark work as complete with failing builds or tests.**
|
||||
|
||||
## Validation and Testing
|
||||
|
||||
### Web UI Testing
|
||||
- **ALWAYS validate web UI changes manually**:
|
||||
- Start local server: `cd wled00/data && python3 -m http.server 8080`
|
||||
- Open `http://localhost:8080/index.htm` in browser
|
||||
- Test basic functionality: color picker, effects, settings pages
|
||||
- **Check for JavaScript errors** in browser console
|
||||
|
||||
### Code Validation
|
||||
- **No automated linting configured** - follow existing code style in files you edit
|
||||
- **Code style**: Use tabs for web files (.html/.css/.js), spaces (2 per level) for C++ files
|
||||
- **C++ formatting available**: `clang-format` is installed but not in CI
|
||||
- **Always run tests before finishing**: `npm test`
|
||||
- **MANDATORY: Always run a hardware build before finishing** (see "Before Finishing Work" section below)
|
||||
|
||||
### Manual Testing Scenarios
|
||||
After making changes to web UI, always test:
|
||||
- **Load main interface**: Verify index.htm loads without errors
|
||||
- **Navigation**: Test switching between main page and settings pages
|
||||
- **Color controls**: Verify color picker and brightness controls work
|
||||
- **Effects**: Test effect selection and parameter changes
|
||||
- **Settings**: Test form submission and validation
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Repository Structure
|
||||
```
|
||||
wled00/ # Main firmware source (C++)
|
||||
├── data/ # Web interface files
|
||||
│ ├── index.htm # Main UI
|
||||
│ ├── settings*.htm # Settings pages
|
||||
│ └── *.js/*.css # Frontend resources
|
||||
├── *.cpp/*.h # Firmware source files
|
||||
└── html_*.h # Generated embedded web files (DO NOT EDIT)
|
||||
tools/ # Build tools (Node.js)
|
||||
├── cdata.js # Web UI build script
|
||||
└── cdata-test.js # Test suite
|
||||
platformio.ini # Hardware build configuration
|
||||
package.json # Node.js dependencies and scripts
|
||||
.github/workflows/ # CI/CD pipelines
|
||||
```
|
||||
|
||||
### Key Files and Their Purpose
|
||||
- `wled00/data/index.htm` - Main web interface
|
||||
- `wled00/data/settings*.htm` - Configuration pages
|
||||
- `tools/cdata.js` - Converts web files to C++ headers
|
||||
- `wled00/wled.h` - Main firmware configuration
|
||||
- `platformio.ini` - Hardware build targets and settings
|
||||
|
||||
### Development Workflow
|
||||
1. **For web UI changes**:
|
||||
- Edit files in `wled00/data/`
|
||||
- Run `npm run build` to regenerate headers
|
||||
- Test with local HTTP server
|
||||
- Run `npm test` to validate build system
|
||||
|
||||
2. **For firmware changes**:
|
||||
- Edit files in `wled00/` (but NOT `html_*.h` files)
|
||||
- Ensure web UI is built first (`npm run build`)
|
||||
- Build firmware: `pio run -e [target]`
|
||||
- Flash to device: `pio run -e [target] --target upload`
|
||||
|
||||
3. **For both web and firmware**:
|
||||
- Always build web UI first
|
||||
- Test web interface manually
|
||||
- Build and test firmware if making firmware changes
|
||||
|
||||
## Build Timing and Timeouts
|
||||
|
||||
**IMPORTANT: Use these timeout values when running builds:**
|
||||
|
||||
- **Web UI build** (`npm run build`): 3 seconds typical - Set timeout to 30 seconds minimum
|
||||
- **Test suite** (`npm test`): 40 seconds typical - Set timeout to 120 seconds (2 minutes) minimum
|
||||
- **Hardware builds** (`pio run -e [target]`): 15-20 minutes typical for first build - Set timeout to 1800 seconds (30 minutes) minimum
|
||||
- Subsequent builds are faster due to caching
|
||||
- First builds download toolchains and dependencies which takes significant time
|
||||
- **NEVER CANCEL long-running builds** - PlatformIO downloads and compilation require patience
|
||||
|
||||
**When validating your changes before finishing, you MUST wait for the hardware build to complete successfully. Set the timeout appropriately and be patient.**
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
- **Build fails with missing html_*.h**: Run `npm run build` first
|
||||
- **Web UI looks broken**: Check browser console for JavaScript errors
|
||||
- **PlatformIO network errors**: Try again, downloads can be flaky
|
||||
- **Node.js version issues**: Ensure Node.js 20+ is installed (check `.nvmrc`)
|
||||
|
||||
### When Things Go Wrong
|
||||
- **Clear generated files**: `rm -f wled00/html_*.h` then rebuild
|
||||
- **Force web UI rebuild**: `npm run build -- --force` or `npm run build -- -f`
|
||||
- **Clean PlatformIO cache**: `pio run --target clean`
|
||||
- **Reinstall dependencies**: `rm -rf node_modules && npm install`
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **DO NOT edit `wled00/html_*.h` files** - they are auto-generated
|
||||
- **Always commit both source files AND generated html_*.h files**
|
||||
- **Web UI must be built before firmware compilation**
|
||||
- **Test web interface manually after any web UI changes**
|
||||
- **Use VS Code with PlatformIO extension for best development experience**
|
||||
- **Hardware builds require appropriate ESP32/ESP8266 development board**
|
||||
|
||||
## CI/CD Pipeline
|
||||
|
||||
**The GitHub Actions CI workflow will:**
|
||||
1. Installs Node.js and Python dependencies
|
||||
2. Runs `npm test` to validate build system (MUST pass)
|
||||
3. Builds web UI with `npm run build` (automatically run by PlatformIO)
|
||||
4. Compiles firmware for ALL hardware targets listed in `default_envs` (MUST succeed for all)
|
||||
5. Uploads build artifacts
|
||||
|
||||
**To ensure CI success, you MUST locally:**
|
||||
- Run `npm test` and ensure it passes
|
||||
- Run `pio run -e esp32dev` (or another common environment from "Hardware Compilation" section) and ensure it completes successfully
|
||||
- If either fails locally, it WILL fail in CI
|
||||
|
||||
**Match this workflow in your local development to ensure CI success. Do not mark work complete until you have validated builds locally.**
|
||||
85
.github/workflows/build.yml
vendored
Normal file
85
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
name: WLED Build
|
||||
|
||||
# Only included into other workflows
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
|
||||
get_default_envs:
|
||||
name: Gather Environments
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: Install PlatformIO
|
||||
run: pip install -r requirements.txt
|
||||
- name: Get default environments
|
||||
id: envs
|
||||
run: |
|
||||
echo "environments=$(pio project config --json-output | jq -cr '.[0][1][0][1]')" >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
environments: ${{ steps.envs.outputs.environments }}
|
||||
|
||||
|
||||
build:
|
||||
name: Build Environments
|
||||
runs-on: ubuntu-latest
|
||||
needs: get_default_envs
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
- run: |
|
||||
npm ci
|
||||
VERSION=`date +%y%m%d0`
|
||||
sed -i -r -e "s/define VERSION .+/define VERSION $VERSION/" wled00/wled.h
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.platformio/.cache
|
||||
~/.buildcache
|
||||
build_output
|
||||
key: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-${{ hashFiles('wled00/**', 'usermods/**') }}
|
||||
restore-keys: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: Install PlatformIO
|
||||
run: pip install -r requirements.txt
|
||||
|
||||
- name: Build firmware
|
||||
run: pio run -e ${{ matrix.environment }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: firmware-${{ matrix.environment }}
|
||||
path: |
|
||||
build_output/release/*.bin
|
||||
build_output/release/*_ESP02*.bin.gz
|
||||
|
||||
|
||||
testCdata:
|
||||
name: Test cdata.js
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- run: npm test
|
||||
49
.github/workflows/nightly.yml
vendored
Normal file
49
.github/workflows/nightly.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
name: Deploy Nightly
|
||||
on:
|
||||
# This can be used to automatically publish nightlies at UTC nighttime
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # run at 2 AM UTC
|
||||
# This can be used to allow manually triggering nightlies from the web interface
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
wled_build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
nightly:
|
||||
name: Deploy nightly
|
||||
runs-on: ubuntu-latest
|
||||
needs: wled_build
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
- name: Show Files
|
||||
run: ls -la
|
||||
- name: "✏️ Generate release changelog"
|
||||
id: changelog
|
||||
uses: janheinrichmerker/action-github-changelog-generator@v2.3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
sinceTag: v0.15.0
|
||||
# Exclude issues that were closed without resolution from changelog
|
||||
exclude-labels: 'stale,wontfix,duplicate,invalid'
|
||||
- name: Update Nightly Release
|
||||
uses: andelf/nightly-release@main
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: nightly
|
||||
name: 'Nightly Release $$'
|
||||
prerelease: true
|
||||
body: ${{ steps.changelog.outputs.changelog }}
|
||||
files: |
|
||||
*.bin
|
||||
*.bin.gz
|
||||
- name: Repository Dispatch
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
repository: wled/WLED-WebInstaller
|
||||
event-type: release-nightly
|
||||
token: ${{ secrets.PAT_PUBLIC }}
|
||||
38
.github/workflows/pr-merge.yaml
vendored
Normal file
38
.github/workflows/pr-merge.yaml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: Notify Discord on PR Merge
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
|
||||
jobs:
|
||||
notify:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.pull_request.merged == true
|
||||
steps:
|
||||
- name: Get User Permission
|
||||
id: checkAccess
|
||||
uses: actions-cool/check-user-permission@v2
|
||||
with:
|
||||
require: write
|
||||
username: ${{ github.triggering_actor }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Check User Permission
|
||||
if: steps.checkAccess.outputs.require-result == 'false'
|
||||
run: |
|
||||
echo "${{ github.triggering_actor }} does not have permissions on this repo."
|
||||
echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}"
|
||||
echo "Job originally triggered by ${{ github.actor }}"
|
||||
exit 1
|
||||
- name: Send Discord notification
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
ACTOR: ${{ github.actor }}
|
||||
run: |
|
||||
jq -n \
|
||||
--arg content "Pull Request #${PR_NUMBER} \"${PR_TITLE}\" merged by ${ACTOR}
|
||||
${PR_URL} . It will be included in the next nightly builds, please test" \
|
||||
'{content: $content}' \
|
||||
| curl -H "Content-Type: application/json" -d @- ${{ secrets.DISCORD_WEBHOOK_BETA_TESTERS }}
|
||||
38
.github/workflows/release.yml
vendored
Normal file
38
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: WLED Release CI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
|
||||
wled_build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: wled_build
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
merge-multiple: true
|
||||
- name: "✏️ Generate release changelog"
|
||||
id: changelog
|
||||
uses: janheinrichmerker/action-github-changelog-generator@v2.3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
sinceTag: v0.15.0
|
||||
maxIssues: 500
|
||||
# Exclude issues that were closed without resolution from changelog
|
||||
exclude-labels: 'stale,wontfix,duplicate,invalid'
|
||||
- name: Create draft release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
body: ${{ steps.changelog.outputs.changelog }}
|
||||
draft: True
|
||||
files: |
|
||||
*.bin
|
||||
*.bin.gz
|
||||
|
||||
30
.github/workflows/stale.yml
vendored
Normal file
30
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 12 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
days-before-stale: 120
|
||||
days-before-close: 7
|
||||
stale-issue-label: 'stale'
|
||||
stale-pr-label: 'stale'
|
||||
exempt-issue-labels: 'pinned,keep,enhancement,confirmed'
|
||||
exempt-pr-labels: 'pinned,keep,enhancement,confirmed'
|
||||
exempt-all-milestones: true
|
||||
operations-per-run: 1000
|
||||
stale-issue-message: >
|
||||
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! ✨
|
||||
stale-pr-message: >
|
||||
Hey! This pull request 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 contributing to WLED! ❤️
|
||||
13
.github/workflows/test.yaml
vendored
Normal file
13
.github/workflows/test.yaml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
dispatch:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Repository Dispatch
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
repository: wled/WLED-WebInstaller
|
||||
event-type: release-nightly
|
||||
token: ${{ secrets.PAT_PUBLIC }}
|
||||
74
.github/workflows/usermods.yml
vendored
Normal file
74
.github/workflows/usermods.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
name: Usermod CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- usermods/**
|
||||
- .github/workflows/usermods.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- usermods/**
|
||||
|
||||
jobs:
|
||||
|
||||
get_usermod_envs:
|
||||
name: Gather Usermods
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: Install PlatformIO
|
||||
run: pip install -r requirements.txt
|
||||
- name: Get default environments
|
||||
id: envs
|
||||
run: |
|
||||
echo "usermods=$(find usermods/ -name library.json | xargs dirname | xargs -n 1 basename | jq -R | grep -v PWM_fan | grep -v BME68X_v2| grep -v pixels_dice_tray | jq --slurp -c)" >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
usermods: ${{ steps.envs.outputs.usermods }}
|
||||
|
||||
|
||||
build:
|
||||
name: Build Enviornments
|
||||
runs-on: ubuntu-latest
|
||||
needs: get_usermod_envs
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
usermod: ${{ fromJSON(needs.get_usermod_envs.outputs.usermods) }}
|
||||
environment: [usermods_esp32, usermods_esp32c3, usermods_esp32s2, usermods_esp32s3]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.platformio/.cache
|
||||
~/.buildcache
|
||||
build_output
|
||||
key: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-${{ hashFiles('wled00/**', 'usermods/**') }}
|
||||
restore-keys: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
- name: Install PlatformIO
|
||||
run: pip install -r requirements.txt
|
||||
- name: Add usermods environment
|
||||
run: |
|
||||
cp -v usermods/platformio_override.usermods.ini platformio_override.ini
|
||||
echo >> platformio_override.ini
|
||||
echo "custom_usermods = ${{ matrix.usermod }}" >> platformio_override.ini
|
||||
cat platformio_override.ini
|
||||
|
||||
- name: Build firmware
|
||||
run: pio run -e ${{ matrix.environment }}
|
||||
11
.github/workflows/wled-ci.yml
vendored
Normal file
11
.github/workflows/wled-ci.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
name: WLED CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
wled_build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
24
.gitignore
vendored
24
.gitignore
vendored
@@ -1,7 +1,27 @@
|
||||
.cache
|
||||
.clang-format
|
||||
.direnv
|
||||
.DS_Store
|
||||
.idea
|
||||
.pio
|
||||
.pioenvs
|
||||
.piolibdeps
|
||||
.vscode
|
||||
!.vscode/extensions.json
|
||||
/wled00/Release
|
||||
compile_commands.json
|
||||
__pycache__/
|
||||
|
||||
esp01-update.sh
|
||||
platformio_override.ini
|
||||
replace_fs.py
|
||||
wled-update.sh
|
||||
|
||||
/build_output/
|
||||
/node_modules/
|
||||
/logs/
|
||||
|
||||
/wled00/extLibs
|
||||
/wled00/LittleFS
|
||||
/wled00/my_config.h
|
||||
/wled00/Release
|
||||
/wled00/wled00.ino.cpp
|
||||
/wled00/html_*.h
|
||||
|
||||
3
.gitpod.Dockerfile
vendored
Normal file
3
.gitpod.Dockerfile
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM gitpod/workspace-full
|
||||
|
||||
USER gitpod
|
||||
11
.gitpod.yml
Normal file
11
.gitpod.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
tasks:
|
||||
- command: pip3 install -U platformio && platformio run
|
||||
|
||||
image:
|
||||
file: .gitpod.Dockerfile
|
||||
|
||||
vscode:
|
||||
extensions:
|
||||
- Atishay-Jain.All-Autocomplete
|
||||
- esbenp.prettier-vscode
|
||||
- shardulm94.trailing-spaces
|
||||
35
.travis.yml
35
.travis.yml
@@ -1,35 +0,0 @@
|
||||
# Continuous Integration (CI) is the practice, in software
|
||||
# engineering, of merging all developer working copies with a shared mainline
|
||||
# several times a day < https://docs.platformio.org/page/ci/index.html >
|
||||
#
|
||||
# Documentation:
|
||||
#
|
||||
# * Travis CI Embedded Builds with PlatformIO
|
||||
# < https://docs.travis-ci.com/user/integration/platformio/ >
|
||||
#
|
||||
# * PlatformIO integration with Travis CI
|
||||
# < https://docs.platformio.org/page/ci/travis.html >
|
||||
#
|
||||
# * User Guide for `platformio ci` command
|
||||
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
|
||||
#
|
||||
#
|
||||
# Please choose one of the following templates (proposed below) and uncomment
|
||||
# it (remove "# " before each line) or use own configuration according to the
|
||||
# Travis CI documentation (see above).
|
||||
#
|
||||
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
sudo: false
|
||||
cache:
|
||||
directories:
|
||||
- "~/.platformio"
|
||||
env:
|
||||
- PLATFORMIO_CI_SRC=wled00
|
||||
install:
|
||||
- pip install -U platformio
|
||||
- platformio update
|
||||
script:
|
||||
- platformio ci --project-conf=./platformio.ini
|
||||
Binary file not shown.
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -3,5 +3,8 @@
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
||||
|
||||
42
.vscode/tasks.json
vendored
Normal file
42
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build: HTML and binary",
|
||||
"dependsOn": [
|
||||
"Build: HTML only",
|
||||
"Build: binary only"
|
||||
],
|
||||
"dependsOrder": "sequence",
|
||||
"problemMatcher": [
|
||||
"$platformio"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "PlatformIO",
|
||||
"label": "Build: binary only",
|
||||
"task": "Build",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$platformio"
|
||||
],
|
||||
"presentation": {
|
||||
"panel": "shared"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "build",
|
||||
"group": "build",
|
||||
"problemMatcher": [],
|
||||
"label": "Build: HTML only",
|
||||
"detail": "npm run build",
|
||||
"presentation": {
|
||||
"panel": "shared"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
1628
CHANGELOG.md
Normal file
1628
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
76
CODE_OF_CONDUCT.md
Normal file
76
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at dev.aircoookie@gmail.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
108
CONTRIBUTING.md
Normal file
108
CONTRIBUTING.md
Normal file
@@ -0,0 +1,108 @@
|
||||
## Thank you for making WLED better!
|
||||
|
||||
Here are a few suggestions to make it easier for you to contribute!
|
||||
|
||||
### Describe your PR
|
||||
|
||||
Please add a description of your proposed code changes. It does not need to be an exhaustive essay, however a PR with no description or just a few words might not get accepted, simply because very basic information is missing.
|
||||
|
||||
A good description helps us to review and understand your proposed changes. For example, you could say a few words about
|
||||
* what you try to achieve (new feature, fixing a bug, refactoring, security enhancements, etc.)
|
||||
* how your code works (short technical summary - focus on important aspects that might not be obvious when reading the code)
|
||||
* testing you performed, known limitations, open ends you possibly could not solve.
|
||||
* any areas where you like to get help from an experienced maintainer (yes WLED has become big 😉)
|
||||
|
||||
### Target branch for pull requests
|
||||
|
||||
Please make all PRs against the `main` branch.
|
||||
|
||||
### Updating your code
|
||||
While the PR is open - and under review by maintainers - you may be asked to modify your PR source code.
|
||||
You can simply update your own branch, and push changes in response to reviewer recommendations.
|
||||
Github will pick up the changes so your PR stays up-to-date.
|
||||
|
||||
> [!CAUTION]
|
||||
> Do not use "force-push" while your PR is open!
|
||||
> It has many subtle and unexpected consequences on our github reposistory.
|
||||
> For example, we regularly lost review comments when the PR author force-pushes code changes. So, pretty please, do not force-push.
|
||||
|
||||
|
||||
You can find a collection of very useful tips and tricks here: https://github.com/wled-dev/WLED/wiki/How-to-properly-submit-a-PR
|
||||
|
||||
|
||||
### Code style
|
||||
|
||||
When in doubt, it is easiest to replicate the code style you find in the files you want to edit :)
|
||||
Below are the guidelines we use in the WLED repository.
|
||||
|
||||
#### Indentation
|
||||
|
||||
We use tabs for Indentation in Web files (.html/.css/.js) and spaces (2 per indentation level) for all other files.
|
||||
You are all set if you have enabled `Editor: Detect Indentation` in VS Code.
|
||||
|
||||
#### Blocks
|
||||
|
||||
Whether the opening bracket of e.g. an `if` block is in the same line as the condition or in a separate line is up to your discretion. If there is only one statement, leaving out block brackets is acceptable.
|
||||
|
||||
Good:
|
||||
```cpp
|
||||
if (a == b) {
|
||||
doStuff(a);
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
if (a == b) doStuff(a);
|
||||
```
|
||||
|
||||
Acceptable - however the first variant is usually easier to read:
|
||||
```cpp
|
||||
if (a == b)
|
||||
{
|
||||
doStuff(a);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
There should always be a space between a keyword and its condition and between the condition and brace.
|
||||
Within the condition, no space should be between the parenthesis and variables.
|
||||
Spaces between variables and operators are up to the authors discretion.
|
||||
There should be no space between function names and their argument parenthesis.
|
||||
|
||||
Good:
|
||||
```cpp
|
||||
if (a == b) {
|
||||
doStuff(a);
|
||||
}
|
||||
```
|
||||
|
||||
Not good:
|
||||
```cpp
|
||||
if( a==b ){
|
||||
doStuff ( a);
|
||||
}
|
||||
```
|
||||
|
||||
#### Comments
|
||||
|
||||
Comments should have a space between the delimiting characters (e.g. `//`) and the comment text.
|
||||
Note: This is a recent change, the majority of the codebase still has comments without spaces.
|
||||
|
||||
Good:
|
||||
```
|
||||
// This is a comment.
|
||||
|
||||
/* This is a CSS inline comment */
|
||||
|
||||
/*
|
||||
* This is a comment
|
||||
* wrapping over multiple lines,
|
||||
* used in WLED for file headers and function explanations
|
||||
*/
|
||||
|
||||
<!-- This is an HTML comment -->
|
||||
```
|
||||
|
||||
There is no hard character limit for a comment within a line,
|
||||
though as a rule of thumb consider wrapping after 120 characters.
|
||||
Inline comments are OK if they describe that line only and are not exceedingly wide.
|
||||
307
LICENSE
307
LICENSE
@@ -1,21 +1,294 @@
|
||||
MIT License
|
||||
Copyright (c) 2016-present Christian Schwinne and individual WLED contributors
|
||||
Licensed under the EUPL v. 1.2 or later
|
||||
|
||||
Copyright (c) 2016 Christian Schwinne
|
||||
EUROPEAN UNION PUBLIC LICENCE v. 1.2
|
||||
EUPL © the European Union 2007, 2016
|
||||
|
||||
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:
|
||||
This European Union Public Licence (the ‘EUPL’) applies to the Work (as
|
||||
defined below) which is provided under the terms of this Licence. Any use of
|
||||
the Work, other than as authorised under this Licence is prohibited (to the
|
||||
extent such use is covered by a right of the copyright holder of the Work).
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
The Work is provided under the terms of this Licence when the Licensor (as
|
||||
defined below) has placed the following notice immediately following the
|
||||
copyright notice for the Work:
|
||||
|
||||
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.
|
||||
Licensed under the EUPL
|
||||
|
||||
or has expressed by any other means his willingness to license under the EUPL.
|
||||
|
||||
1. Definitions
|
||||
|
||||
In this Licence, the following terms have the following meaning:
|
||||
|
||||
- ‘The Licence’: this Licence.
|
||||
|
||||
- ‘The Original Work’: the work or software distributed or communicated by the
|
||||
Licensor under this Licence, available as Source Code and also as Executable
|
||||
Code as the case may be.
|
||||
|
||||
- ‘Derivative Works’: the works or software that could be created by the
|
||||
Licensee, based upon the Original Work or modifications thereof. This
|
||||
Licence does not define the extent of modification or dependence on the
|
||||
Original Work required in order to classify a work as a Derivative Work;
|
||||
this extent is determined by copyright law applicable in the country
|
||||
mentioned in Article 15.
|
||||
|
||||
- ‘The Work’: the Original Work or its Derivative Works.
|
||||
|
||||
- ‘The Source Code’: the human-readable form of the Work which is the most
|
||||
convenient for people to study and modify.
|
||||
|
||||
- ‘The Executable Code’: any code which has generally been compiled and which
|
||||
is meant to be interpreted by a computer as a program.
|
||||
|
||||
- ‘The Licensor’: the natural or legal person that distributes or communicates
|
||||
the Work under the Licence.
|
||||
|
||||
- ‘Contributor(s)’: any natural or legal person who modifies the Work under
|
||||
the Licence, or otherwise contributes to the creation of a Derivative Work.
|
||||
|
||||
- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
|
||||
the Work under the terms of the Licence.
|
||||
|
||||
- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
|
||||
renting, distributing, communicating, transmitting, or otherwise making
|
||||
available, online or offline, copies of the Work or providing access to its
|
||||
essential functionalities at the disposal of any other natural or legal
|
||||
person.
|
||||
|
||||
2. Scope of the rights granted by the Licence
|
||||
|
||||
The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
|
||||
sublicensable licence to do the following, for the duration of copyright
|
||||
vested in the Original Work:
|
||||
|
||||
- use the Work in any circumstance and for all usage,
|
||||
- reproduce the Work,
|
||||
- modify the Work, and make Derivative Works based upon the Work,
|
||||
- communicate to the public, including the right to make available or display
|
||||
the Work or copies thereof to the public and perform publicly, as the case
|
||||
may be, the Work,
|
||||
- distribute the Work or copies thereof,
|
||||
- lend and rent the Work or copies thereof,
|
||||
- sublicense rights in the Work or copies thereof.
|
||||
|
||||
Those rights can be exercised on any media, supports and formats, whether now
|
||||
known or later invented, as far as the applicable law permits so.
|
||||
|
||||
In the countries where moral rights apply, the Licensor waives his right to
|
||||
exercise his moral right to the extent allowed by law in order to make
|
||||
effective the licence of the economic rights here above listed.
|
||||
|
||||
The Licensor grants to the Licensee royalty-free, non-exclusive usage rights
|
||||
to any patents held by the Licensor, to the extent necessary to make use of
|
||||
the rights granted on the Work under this Licence.
|
||||
|
||||
3. Communication of the Source Code
|
||||
|
||||
The Licensor may provide the Work either in its Source Code form, or as
|
||||
Executable Code. If the Work is provided as Executable Code, the Licensor
|
||||
provides in addition a machine-readable copy of the Source Code of the Work
|
||||
along with each copy of the Work that the Licensor distributes or indicates,
|
||||
in a notice following the copyright notice attached to the Work, a repository
|
||||
where the Source Code is easily and freely accessible for as long as the
|
||||
Licensor continues to distribute or communicate the Work.
|
||||
|
||||
4. Limitations on copyright
|
||||
|
||||
Nothing in this Licence is intended to deprive the Licensee of the benefits
|
||||
from any exception or limitation to the exclusive rights of the rights owners
|
||||
in the Work, of the exhaustion of those rights or of other applicable
|
||||
limitations thereto.
|
||||
|
||||
5. Obligations of the Licensee
|
||||
|
||||
The grant of the rights mentioned above is subject to some restrictions and
|
||||
obligations imposed on the Licensee. Those obligations are the following:
|
||||
|
||||
Attribution right: The Licensee shall keep intact all copyright, patent or
|
||||
trademarks notices and all notices that refer to the Licence and to the
|
||||
disclaimer of warranties. The Licensee must include a copy of such notices and
|
||||
a copy of the Licence with every copy of the Work he/she distributes or
|
||||
communicates. The Licensee must cause any Derivative Work to carry prominent
|
||||
notices stating that the Work has been modified and the date of modification.
|
||||
|
||||
Copyleft clause: If the Licensee distributes or communicates copies of the
|
||||
Original Works or Derivative Works, this Distribution or Communication will be
|
||||
done under the terms of this Licence or of a later version of this Licence
|
||||
unless the Original Work is expressly distributed only under this version of
|
||||
the Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
|
||||
(becoming Licensor) cannot offer or impose any additional terms or conditions
|
||||
on the Work or Derivative Work that alter or restrict the terms of the
|
||||
Licence.
|
||||
|
||||
Compatibility clause: If the Licensee Distributes or Communicates Derivative
|
||||
Works or copies thereof based upon both the Work and another work licensed
|
||||
under a Compatible Licence, this Distribution or Communication can be done
|
||||
under the terms of this Compatible Licence. For the sake of this clause,
|
||||
‘Compatible Licence’ refers to the licences listed in the appendix attached to
|
||||
this Licence. Should the Licensee's obligations under the Compatible Licence
|
||||
conflict with his/her obligations under this Licence, the obligations of the
|
||||
Compatible Licence shall prevail.
|
||||
|
||||
Provision of Source Code: When distributing or communicating copies of the
|
||||
Work, the Licensee will provide a machine-readable copy of the Source Code or
|
||||
indicate a repository where this Source will be easily and freely available
|
||||
for as long as the Licensee continues to distribute or communicate the Work.
|
||||
|
||||
Legal Protection: This Licence does not grant permission to use the trade
|
||||
names, trademarks, service marks, or names of the Licensor, except as required
|
||||
for reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the copyright notice.
|
||||
|
||||
6. Chain of Authorship
|
||||
|
||||
The original Licensor warrants that the copyright in the Original Work granted
|
||||
hereunder is owned by him/her or licensed to him/her and that he/she has the
|
||||
power and authority to grant the Licence.
|
||||
|
||||
Each Contributor warrants that the copyright in the modifications he/she
|
||||
brings to the Work are owned by him/her or licensed to him/her and that he/she
|
||||
has the power and authority to grant the Licence.
|
||||
|
||||
Each time You accept the Licence, the original Licensor and subsequent
|
||||
Contributors grant You a licence to their contributions to the Work, under the
|
||||
terms of this Licence.
|
||||
|
||||
7. Disclaimer of Warranty
|
||||
|
||||
The Work is a work in progress, which is continuously improved by numerous
|
||||
Contributors. It is not a finished work and may therefore contain defects or
|
||||
‘bugs’ inherent to this type of development.
|
||||
|
||||
For the above reason, the Work is provided under the Licence on an ‘as is’
|
||||
basis and without warranties of any kind concerning the Work, including
|
||||
without limitation merchantability, fitness for a particular purpose, absence
|
||||
of defects or errors, accuracy, non-infringement of intellectual property
|
||||
rights other than copyright as stated in Article 6 of this Licence.
|
||||
|
||||
This disclaimer of warranty is an essential part of the Licence and a
|
||||
condition for the grant of any rights to the Work.
|
||||
|
||||
8. Disclaimer of Liability
|
||||
|
||||
Except in the cases of wilful misconduct or damages directly caused to natural
|
||||
persons, the Licensor will in no event be liable for any direct or indirect,
|
||||
material or moral, damages of any kind, arising out of the Licence or of the
|
||||
use of the Work, including without limitation, damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, loss of data or any commercial
|
||||
damage, even if the Licensor has been advised of the possibility of such
|
||||
damage. However, the Licensor will be liable under statutory product liability
|
||||
laws as far such laws apply to the Work.
|
||||
|
||||
9. Additional agreements
|
||||
|
||||
While distributing the Work, You may choose to conclude an additional
|
||||
agreement, defining obligations or services consistent with this Licence.
|
||||
However, if accepting obligations, You may act only on your own behalf and on
|
||||
your sole responsibility, not on behalf of the original Licensor or any other
|
||||
Contributor, and only if You agree to indemnify, defend, and hold each
|
||||
Contributor harmless for any liability incurred by, or claims asserted against
|
||||
such Contributor by the fact You have accepted any warranty or additional
|
||||
liability.
|
||||
|
||||
10. Acceptance of the Licence
|
||||
|
||||
The provisions of this Licence can be accepted by clicking on an icon ‘I
|
||||
agree’ placed under the bottom of a window displaying the text of this Licence
|
||||
or by affirming consent in any other similar way, in accordance with the rules
|
||||
of applicable law. Clicking on that icon indicates your clear and irrevocable
|
||||
acceptance of this Licence and all of its terms and conditions.
|
||||
|
||||
Similarly, you irrevocably accept this Licence and all of its terms and
|
||||
conditions by exercising any rights granted to You by Article 2 of this
|
||||
Licence, such as the use of the Work, the creation by You of a Derivative Work
|
||||
or the Distribution or Communication by You of the Work or copies thereof.
|
||||
|
||||
11. Information to the public
|
||||
|
||||
In case of any Distribution or Communication of the Work by means of
|
||||
electronic communication by You (for example, by offering to download the Work
|
||||
from a remote location) the distribution channel or media (for example, a
|
||||
website) must at least provide to the public the information requested by the
|
||||
applicable law regarding the Licensor, the Licence and the way it may be
|
||||
accessible, concluded, stored and reproduced by the Licensee.
|
||||
|
||||
12. Termination of the Licence
|
||||
|
||||
The Licence and the rights granted hereunder will terminate automatically upon
|
||||
any breach by the Licensee of the terms of the Licence.
|
||||
|
||||
Such a termination will not terminate the licences of any person who has
|
||||
received the Work from the Licensee under the Licence, provided such persons
|
||||
remain in full compliance with the Licence.
|
||||
|
||||
13. Miscellaneous
|
||||
|
||||
Without prejudice of Article 9 above, the Licence represents the complete
|
||||
agreement between the Parties as to the Work.
|
||||
|
||||
If any provision of the Licence is invalid or unenforceable under applicable
|
||||
law, this will not affect the validity or enforceability of the Licence as a
|
||||
whole. Such provision will be construed or reformed so as necessary to make it
|
||||
valid and enforceable.
|
||||
|
||||
The European Commission may publish other linguistic versions or new versions
|
||||
of this Licence or updated versions of the Appendix, so far this is required
|
||||
and reasonable, without reducing the scope of the rights granted by the
|
||||
Licence. New versions of the Licence will be published with a unique version
|
||||
number.
|
||||
|
||||
All linguistic versions of this Licence, approved by the European Commission,
|
||||
have identical value. Parties can take advantage of the linguistic version of
|
||||
their choice.
|
||||
|
||||
14. Jurisdiction
|
||||
|
||||
Without prejudice to specific agreement between parties,
|
||||
|
||||
- any litigation resulting from the interpretation of this License, arising
|
||||
between the European Union institutions, bodies, offices or agencies, as a
|
||||
Licensor, and any Licensee, will be subject to the jurisdiction of the Court
|
||||
of Justice of the European Union, as laid down in article 272 of the Treaty
|
||||
on the Functioning of the European Union,
|
||||
|
||||
- any litigation arising between other parties and resulting from the
|
||||
interpretation of this License, will be subject to the exclusive
|
||||
jurisdiction of the competent court where the Licensor resides or conducts
|
||||
its primary business.
|
||||
|
||||
15. Applicable Law
|
||||
|
||||
Without prejudice to specific agreement between parties,
|
||||
|
||||
- this Licence shall be governed by the law of the European Union Member State
|
||||
where the Licensor has his seat, resides or has his registered office,
|
||||
|
||||
- this licence shall be governed by Belgian law if the Licensor has no seat,
|
||||
residence or registered office inside a European Union Member State.
|
||||
|
||||
Appendix
|
||||
|
||||
‘Compatible Licences’ according to Article 5 EUPL are:
|
||||
|
||||
- GNU General Public License (GPL) v. 2, v. 3
|
||||
- GNU Affero General Public License (AGPL) v. 3
|
||||
- Open Software License (OSL) v. 2.1, v. 3.0
|
||||
- Eclipse Public License (EPL) v. 1.0
|
||||
- CeCILL v. 2.0, v. 2.1
|
||||
- Mozilla Public Licence (MPL) v. 2
|
||||
- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
|
||||
- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
|
||||
works other than software
|
||||
- European Union Public Licence (EUPL) v. 1.1, v. 1.2
|
||||
- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
|
||||
Reciprocity (LiLiQ-R+).
|
||||
|
||||
The European Commission may update this Appendix to later versions of the
|
||||
above licences without producing a new version of the EUPL, as long as they
|
||||
provide the rights granted in Article 2 of this Licence and protect the
|
||||
covered Source Code from exclusive appropriation.
|
||||
|
||||
All other changes or additions to this Appendix require the production of a
|
||||
new EUPL version.
|
||||
47
boards/lilygo-t7-s3.json
Normal file
47
boards/lilygo-t7-s3.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino":{
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_opi",
|
||||
"partitions": "default_16MB.csv"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DARDUINO_TTGO_T7_S3",
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_USB_MODE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [
|
||||
[
|
||||
"0X303A",
|
||||
"0x1001"
|
||||
]
|
||||
],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "esp32s3"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi",
|
||||
"bluetooth"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "LILYGO T3-S3",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 16777216,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://www.aliexpress.us/item/3256804591247074.html",
|
||||
"vendor": "LILYGO"
|
||||
}
|
||||
47
boards/lolin_s3_mini.json
Normal file
47
boards/lolin_s3_mini.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"memory_type": "qio_qspi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_LOLIN_S3_MINI",
|
||||
"-DARDUINO_USB_MODE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [
|
||||
[
|
||||
"0x303A",
|
||||
"0x8167"
|
||||
]
|
||||
],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "lolin_s3_mini"
|
||||
},
|
||||
"connectivity": [
|
||||
"bluetooth",
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "WEMOS LOLIN S3 Mini",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://www.wemos.cc/en/latest/s3/index.html",
|
||||
"vendor": "WEMOS"
|
||||
}
|
||||
|
||||
5
images/Readme.md
Normal file
5
images/Readme.md
Normal file
@@ -0,0 +1,5 @@
|
||||
### Additional Logos
|
||||
|
||||
Additional awesome logos for WLED can be found here [Aircoookie/Akemi](https://github.com/Aircoookie/Akemi).
|
||||
|
||||
<img src="https://github.com/Aircoookie/Akemi/blob/master/akemi/001_cheerful.png">
|
||||
BIN
images/macbook-pro-space-gray-on-the-wooden-table.jpg
Normal file
BIN
images/macbook-pro-space-gray-on-the-wooden-table.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 489 KiB |
BIN
images/walking-with-iphone-x.jpg
Normal file
BIN
images/walking-with-iphone-x.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 500 KiB |
BIN
images/wled_logo_akemi.png
Normal file
BIN
images/wled_logo_akemi.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
images/wled_logo_old.png
Normal file
BIN
images/wled_logo_old.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
504
lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp
Normal file
504
lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp
Normal file
@@ -0,0 +1,504 @@
|
||||
/* esp8266_waveform imported from platform source code
|
||||
Modified for WLED to work around a fault in the NMI handling,
|
||||
which can result in the system locking up and hard WDT crashes.
|
||||
|
||||
Imported from https://github.com/esp8266/Arduino/blob/7e0d20e2b9034994f573a236364e0aef17fd66de/cores/esp8266/core_esp8266_waveform_phase.cpp
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
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.
|
||||
Copyright (c) 2020 Dirk O. Kaar.
|
||||
|
||||
The core idea is to have a programmable waveform generator with a unique
|
||||
high and low period (defined in microseconds or CPU clock cycles). 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 clock 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 "ccy" or "ccys" is used, it means ESP.getCycleCount()
|
||||
clock cycle time, or an interval measured in clock cycles, but not TIMER1
|
||||
cycles (which may be 2 CPU clock cycles @ 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 "core_esp8266_waveform.h"
|
||||
#include <Arduino.h>
|
||||
#include "debug.h"
|
||||
#include "ets_sys.h"
|
||||
#include <atomic>
|
||||
|
||||
|
||||
// ----- @willmmiles begin patch -----
|
||||
// Linker magic
|
||||
extern "C" void usePWMFixedNMI(void) {};
|
||||
|
||||
// NMI crash workaround
|
||||
// Sometimes the NMI fails to return, stalling the CPU. When this happens,
|
||||
// the next NMI gets a return address /inside the NMI handler function/.
|
||||
// We work around this by caching the last NMI return address, and restoring
|
||||
// the epc3 and eps3 registers to the previous values if the observed epc3
|
||||
// happens to be pointing to the _NMILevelVector function.
|
||||
extern "C" void _NMILevelVector();
|
||||
extern "C" void _UserExceptionVector_1(); // the next function after _NMILevelVector
|
||||
static inline IRAM_ATTR void nmiCrashWorkaround() {
|
||||
static uintptr_t epc3_backup, eps3_backup;
|
||||
|
||||
uintptr_t epc3, eps3;
|
||||
__asm__ __volatile__("rsr %0,epc3; rsr %1,eps3":"=a"(epc3),"=a" (eps3));
|
||||
if ((epc3 < (uintptr_t) &_NMILevelVector) || (epc3 >= (uintptr_t) &_UserExceptionVector_1)) {
|
||||
// Address is good; save backup
|
||||
epc3_backup = epc3;
|
||||
eps3_backup = eps3;
|
||||
} else {
|
||||
// Address is inside the NMI handler -- restore from backup
|
||||
__asm__ __volatile__("wsr %0,epc3; wsr %1,eps3"::"a"(epc3_backup),"a"(eps3_backup));
|
||||
}
|
||||
}
|
||||
// ----- @willmmiles end patch -----
|
||||
|
||||
|
||||
// No-op calls to override the PWM implementation
|
||||
extern "C" void _setPWMFreq_weak(uint32_t freq) { (void) freq; }
|
||||
extern "C" IRAM_ATTR bool _stopPWM_weak(int pin) { (void) pin; return false; }
|
||||
extern "C" bool _setPWM_weak(int pin, uint32_t val, uint32_t range) { (void) pin; (void) val; (void) range; return false; }
|
||||
|
||||
|
||||
// Timer is 80MHz fixed. 160MHz CPU frequency need scaling.
|
||||
constexpr bool ISCPUFREQ160MHZ = clockCyclesPerMicrosecond() == 160;
|
||||
// Maximum delay between IRQs, Timer1, <= 2^23 / 80MHz
|
||||
constexpr int32_t MAXIRQTICKSCCYS = microsecondsToClockCycles(10000);
|
||||
// Maximum servicing time for any single IRQ
|
||||
constexpr uint32_t ISRTIMEOUTCCYS = microsecondsToClockCycles(18);
|
||||
// The latency between in-ISR rearming of the timer and the earliest firing
|
||||
constexpr int32_t IRQLATENCYCCYS = microsecondsToClockCycles(2);
|
||||
// The SDK and hardware take some time to actually get to our NMI code
|
||||
constexpr int32_t DELTAIRQCCYS = ISCPUFREQ160MHZ ?
|
||||
microsecondsToClockCycles(2) >> 1 : microsecondsToClockCycles(2);
|
||||
|
||||
// for INFINITE, the NMI proceeds on the waveform without expiry deadline.
|
||||
// for EXPIRES, the NMI expires the waveform automatically on the expiry ccy.
|
||||
// for UPDATEEXPIRY, the NMI recomputes the exact expiry ccy and transitions to EXPIRES.
|
||||
// for UPDATEPHASE, the NMI recomputes the target timings
|
||||
// for INIT, the NMI initializes nextPeriodCcy, and if expiryCcy != 0 includes UPDATEEXPIRY.
|
||||
enum class WaveformMode : uint8_t {INFINITE = 0, EXPIRES = 1, UPDATEEXPIRY = 2, UPDATEPHASE = 3, INIT = 4};
|
||||
|
||||
// Waveform generator can create tones, PWM, and servos
|
||||
typedef struct {
|
||||
uint32_t nextPeriodCcy; // ESP clock cycle when a period begins.
|
||||
uint32_t endDutyCcy; // ESP clock cycle when going from duty to off
|
||||
int32_t dutyCcys; // Set next off cycle at low->high to maintain phase
|
||||
int32_t adjDutyCcys; // Temporary correction for next period
|
||||
int32_t periodCcys; // Set next phase cycle at low->high to maintain phase
|
||||
uint32_t expiryCcy; // For time-limited waveform, the CPU clock cycle when this waveform must stop. If WaveformMode::UPDATE, temporarily holds relative ccy count
|
||||
WaveformMode mode;
|
||||
bool autoPwm; // perform PWM duty to idle cycle ratio correction under high load at the expense of precise timings
|
||||
} Waveform;
|
||||
|
||||
namespace {
|
||||
|
||||
static struct {
|
||||
Waveform pins[17]; // State of all possible pins
|
||||
uint32_t states = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code
|
||||
uint32_t enabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code
|
||||
|
||||
// Enable lock-free by only allowing updates to waveform.states and waveform.enabled from IRQ service routine
|
||||
int32_t toSetBits = 0; // Message to the NMI handler to start/modify exactly one waveform
|
||||
int32_t toDisableBits = 0; // Message to the NMI handler to disable exactly one pin from waveform generation
|
||||
|
||||
// toSetBits temporaries
|
||||
// cheaper than packing them in every Waveform, since we permit only one use at a time
|
||||
uint32_t phaseCcy; // positive phase offset ccy count
|
||||
int8_t alignPhase; // < 0 no phase alignment, otherwise starts waveform in relative phase offset to given pin
|
||||
|
||||
uint32_t(*timer1CB)() = nullptr;
|
||||
|
||||
bool timer1Running = false;
|
||||
|
||||
uint32_t nextEventCcy;
|
||||
} waveform;
|
||||
|
||||
}
|
||||
|
||||
// Interrupt on/off control
|
||||
static IRAM_ATTR void timer1Interrupt();
|
||||
|
||||
// Non-speed critical bits
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
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);
|
||||
waveform.timer1Running = true;
|
||||
timer1_write(IRQLATENCYCCYS); // Cause an interrupt post-haste
|
||||
}
|
||||
|
||||
static void IRAM_ATTR deinitTimer() {
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
|
||||
timer1_disable();
|
||||
timer1_isr_init();
|
||||
waveform.timer1Running = false;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Set a callback. Pass in NULL to stop it
|
||||
void setTimer1Callback_weak(uint32_t (*fn)()) {
|
||||
waveform.timer1CB = fn;
|
||||
std::atomic_thread_fence(std::memory_order_acq_rel);
|
||||
if (!waveform.timer1Running && fn) {
|
||||
initTimer();
|
||||
} else if (waveform.timer1Running && !fn && !waveform.enabled) {
|
||||
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 startWaveformClockCycles_weak(uint8_t pin, uint32_t highCcys, uint32_t lowCcys,
|
||||
uint32_t runTimeCcys, int8_t alignPhase, uint32_t phaseOffsetCcys, bool autoPwm) {
|
||||
uint32_t periodCcys = highCcys + lowCcys;
|
||||
if (periodCcys < MAXIRQTICKSCCYS) {
|
||||
if (!highCcys) {
|
||||
periodCcys = (MAXIRQTICKSCCYS / periodCcys) * periodCcys;
|
||||
}
|
||||
else if (!lowCcys) {
|
||||
highCcys = periodCcys = (MAXIRQTICKSCCYS / periodCcys) * periodCcys;
|
||||
}
|
||||
}
|
||||
// sanity checks, including mixed signed/unsigned arithmetic safety
|
||||
if ((pin > 16) || isFlashInterfacePin(pin) || (alignPhase > 16) ||
|
||||
static_cast<int32_t>(periodCcys) <= 0 ||
|
||||
static_cast<int32_t>(highCcys) < 0 || static_cast<int32_t>(lowCcys) < 0) {
|
||||
return false;
|
||||
}
|
||||
Waveform& wave = waveform.pins[pin];
|
||||
wave.dutyCcys = highCcys;
|
||||
wave.adjDutyCcys = 0;
|
||||
wave.periodCcys = periodCcys;
|
||||
wave.autoPwm = autoPwm;
|
||||
waveform.alignPhase = (alignPhase < 0) ? -1 : alignPhase;
|
||||
waveform.phaseCcy = phaseOffsetCcys;
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
const uint32_t pinBit = 1UL << pin;
|
||||
if (!(waveform.enabled & pinBit)) {
|
||||
// wave.nextPeriodCcy and wave.endDutyCcy are initialized by the ISR
|
||||
wave.expiryCcy = runTimeCcys; // in WaveformMode::INIT, temporarily hold relative cycle count
|
||||
wave.mode = WaveformMode::INIT;
|
||||
if (!wave.dutyCcys) {
|
||||
// If initially at zero duty cycle, force GPIO off
|
||||
if (pin == 16) {
|
||||
GP16O = 0;
|
||||
}
|
||||
else {
|
||||
GPOC = pinBit;
|
||||
}
|
||||
}
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
waveform.toSetBits = 1UL << pin;
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
if (!waveform.timer1Running) {
|
||||
initTimer();
|
||||
}
|
||||
else if (T1V > IRQLATENCYCCYS) {
|
||||
// Must not interfere if Timer is due shortly
|
||||
timer1_write(IRQLATENCYCCYS);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wave.mode = WaveformMode::INFINITE; // turn off possible expiry to make update atomic from NMI
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
if (runTimeCcys) {
|
||||
wave.expiryCcy = runTimeCcys; // in WaveformMode::UPDATEEXPIRY, temporarily hold relative cycle count
|
||||
wave.mode = WaveformMode::UPDATEEXPIRY;
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
waveform.toSetBits = 1UL << pin;
|
||||
} else if (alignPhase >= 0) {
|
||||
// @willmmiles new feature
|
||||
wave.mode = WaveformMode::UPDATEPHASE; // recalculate start
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
waveform.toSetBits = 1UL << pin;
|
||||
}
|
||||
}
|
||||
std::atomic_thread_fence(std::memory_order_acq_rel);
|
||||
while (waveform.toSetBits) {
|
||||
esp_yield(); // Wait for waveform to update
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Stops a waveform on a pin
|
||||
IRAM_ATTR int stopWaveform_weak(uint8_t pin) {
|
||||
// Can't possibly need to stop anything if there is no timer active
|
||||
if (!waveform.timer1Running) {
|
||||
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
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
const uint32_t pinBit = 1UL << pin;
|
||||
if (waveform.enabled & pinBit) {
|
||||
waveform.toDisableBits = 1UL << pin;
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
// Must not interfere if Timer is due shortly
|
||||
if (T1V > IRQLATENCYCCYS) {
|
||||
timer1_write(IRQLATENCYCCYS);
|
||||
}
|
||||
while (waveform.toDisableBits) {
|
||||
/* no-op */ // Can't delay() since stopWaveform may be called from an IRQ
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
}
|
||||
}
|
||||
if (!waveform.enabled && !waveform.timer1CB) {
|
||||
deinitTimer();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Speed critical bits
|
||||
#pragma GCC optimize ("O2")
|
||||
|
||||
// For dynamic CPU clock frequency switch in loop the scaling logic would have to be adapted.
|
||||
// Using constexpr makes sure that the CPU clock frequency is compile-time fixed.
|
||||
static inline IRAM_ATTR int32_t scaleCcys(const int32_t ccys, const bool isCPU2X) {
|
||||
if (ISCPUFREQ160MHZ) {
|
||||
return isCPU2X ? ccys : (ccys >> 1);
|
||||
}
|
||||
else {
|
||||
return isCPU2X ? (ccys << 1) : ccys;
|
||||
}
|
||||
}
|
||||
|
||||
static IRAM_ATTR void timer1Interrupt() {
|
||||
const uint32_t isrStartCcy = ESP.getCycleCount();
|
||||
//int32_t clockDrift = isrStartCcy - waveform.nextEventCcy;
|
||||
|
||||
// ----- @willmmiles begin patch -----
|
||||
nmiCrashWorkaround();
|
||||
// ----- @willmmiles end patch -----
|
||||
|
||||
const bool isCPU2X = CPU2X & 1;
|
||||
if ((waveform.toSetBits && !(waveform.enabled & waveform.toSetBits)) || waveform.toDisableBits) {
|
||||
// Handle enable/disable requests from main app.
|
||||
waveform.enabled = (waveform.enabled & ~waveform.toDisableBits) | waveform.toSetBits; // Set the requested waveforms on/off
|
||||
// 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)
|
||||
waveform.toDisableBits = 0;
|
||||
}
|
||||
|
||||
if (waveform.toSetBits) {
|
||||
const int toSetPin = __builtin_ffs(waveform.toSetBits) - 1;
|
||||
Waveform& wave = waveform.pins[toSetPin];
|
||||
switch (wave.mode) {
|
||||
case WaveformMode::INIT:
|
||||
waveform.states &= ~waveform.toSetBits; // Clear the state of any just started
|
||||
if (waveform.alignPhase >= 0 && waveform.enabled & (1UL << waveform.alignPhase)) {
|
||||
wave.nextPeriodCcy = waveform.pins[waveform.alignPhase].nextPeriodCcy + scaleCcys(waveform.phaseCcy, isCPU2X);
|
||||
}
|
||||
else {
|
||||
wave.nextPeriodCcy = waveform.nextEventCcy;
|
||||
}
|
||||
if (!wave.expiryCcy) {
|
||||
wave.mode = WaveformMode::INFINITE;
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
case WaveformMode::UPDATEEXPIRY:
|
||||
// in WaveformMode::UPDATEEXPIRY, expiryCcy temporarily holds relative CPU cycle count
|
||||
wave.expiryCcy = wave.nextPeriodCcy + scaleCcys(wave.expiryCcy, isCPU2X);
|
||||
wave.mode = WaveformMode::EXPIRES;
|
||||
break;
|
||||
// @willmmiles new feature
|
||||
case WaveformMode::UPDATEPHASE:
|
||||
// in WaveformMode::UPDATEPHASE, we recalculate the targets
|
||||
if ((waveform.alignPhase >= 0) && (waveform.enabled & (1UL << waveform.alignPhase))) {
|
||||
// Compute phase shift to realign with target
|
||||
auto const newPeriodCcy = waveform.pins[waveform.alignPhase].nextPeriodCcy + scaleCcys(waveform.phaseCcy, isCPU2X);
|
||||
auto const period = scaleCcys(wave.periodCcys, isCPU2X);
|
||||
auto shift = ((static_cast<int32_t> (newPeriodCcy - wave.nextPeriodCcy) + period/2) % period) - (period/2);
|
||||
wave.nextPeriodCcy += static_cast<uint32_t>(shift);
|
||||
if (static_cast<int32_t>(wave.endDutyCcy - wave.nextPeriodCcy) > 0) {
|
||||
wave.endDutyCcy = wave.nextPeriodCcy;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
waveform.toSetBits = 0;
|
||||
}
|
||||
|
||||
// Exit the loop if the next event, if any, is sufficiently distant.
|
||||
const uint32_t isrTimeoutCcy = isrStartCcy + ISRTIMEOUTCCYS;
|
||||
uint32_t busyPins = waveform.enabled;
|
||||
waveform.nextEventCcy = isrStartCcy + MAXIRQTICKSCCYS;
|
||||
|
||||
uint32_t now = ESP.getCycleCount();
|
||||
uint32_t isrNextEventCcy = now;
|
||||
while (busyPins) {
|
||||
if (static_cast<int32_t>(isrNextEventCcy - now) > IRQLATENCYCCYS) {
|
||||
waveform.nextEventCcy = isrNextEventCcy;
|
||||
break;
|
||||
}
|
||||
isrNextEventCcy = waveform.nextEventCcy;
|
||||
uint32_t loopPins = busyPins;
|
||||
while (loopPins) {
|
||||
const int pin = __builtin_ffsl(loopPins) - 1;
|
||||
const uint32_t pinBit = 1UL << pin;
|
||||
loopPins ^= pinBit;
|
||||
|
||||
Waveform& wave = waveform.pins[pin];
|
||||
|
||||
/* @willmmiles - wtf? We don't want to accumulate drift
|
||||
if (clockDrift) {
|
||||
wave.endDutyCcy += clockDrift;
|
||||
wave.nextPeriodCcy += clockDrift;
|
||||
wave.expiryCcy += clockDrift;
|
||||
}
|
||||
*/
|
||||
|
||||
uint32_t waveNextEventCcy = (waveform.states & pinBit) ? wave.endDutyCcy : wave.nextPeriodCcy;
|
||||
if (WaveformMode::EXPIRES == wave.mode &&
|
||||
static_cast<int32_t>(waveNextEventCcy - wave.expiryCcy) >= 0 &&
|
||||
static_cast<int32_t>(now - wave.expiryCcy) >= 0) {
|
||||
// Disable any waveforms that are done
|
||||
waveform.enabled ^= pinBit;
|
||||
busyPins ^= pinBit;
|
||||
}
|
||||
else {
|
||||
const int32_t overshootCcys = now - waveNextEventCcy;
|
||||
if (overshootCcys >= 0) {
|
||||
const int32_t periodCcys = scaleCcys(wave.periodCcys, isCPU2X);
|
||||
if (waveform.states & pinBit) {
|
||||
// active configuration and forward are 100% duty
|
||||
if (wave.periodCcys == wave.dutyCcys) {
|
||||
wave.nextPeriodCcy += periodCcys;
|
||||
wave.endDutyCcy = wave.nextPeriodCcy;
|
||||
}
|
||||
else {
|
||||
if (wave.autoPwm) {
|
||||
wave.adjDutyCcys += overshootCcys;
|
||||
}
|
||||
waveform.states ^= pinBit;
|
||||
if (16 == pin) {
|
||||
GP16O = 0;
|
||||
}
|
||||
else {
|
||||
GPOC = pinBit;
|
||||
}
|
||||
}
|
||||
waveNextEventCcy = wave.nextPeriodCcy;
|
||||
}
|
||||
else {
|
||||
wave.nextPeriodCcy += periodCcys;
|
||||
if (!wave.dutyCcys) {
|
||||
wave.endDutyCcy = wave.nextPeriodCcy;
|
||||
}
|
||||
else {
|
||||
int32_t dutyCcys = scaleCcys(wave.dutyCcys, isCPU2X);
|
||||
if (dutyCcys <= wave.adjDutyCcys) {
|
||||
dutyCcys >>= 1;
|
||||
wave.adjDutyCcys -= dutyCcys;
|
||||
}
|
||||
else if (wave.adjDutyCcys) {
|
||||
dutyCcys -= wave.adjDutyCcys;
|
||||
wave.adjDutyCcys = 0;
|
||||
}
|
||||
wave.endDutyCcy = now + dutyCcys;
|
||||
if (static_cast<int32_t>(wave.endDutyCcy - wave.nextPeriodCcy) > 0) {
|
||||
wave.endDutyCcy = wave.nextPeriodCcy;
|
||||
}
|
||||
waveform.states |= pinBit;
|
||||
if (16 == pin) {
|
||||
GP16O = 1;
|
||||
}
|
||||
else {
|
||||
GPOS = pinBit;
|
||||
}
|
||||
}
|
||||
waveNextEventCcy = wave.endDutyCcy;
|
||||
}
|
||||
|
||||
if (WaveformMode::EXPIRES == wave.mode && static_cast<int32_t>(waveNextEventCcy - wave.expiryCcy) > 0) {
|
||||
waveNextEventCcy = wave.expiryCcy;
|
||||
}
|
||||
}
|
||||
|
||||
if (static_cast<int32_t>(waveNextEventCcy - isrTimeoutCcy) >= 0) {
|
||||
busyPins ^= pinBit;
|
||||
if (static_cast<int32_t>(waveform.nextEventCcy - waveNextEventCcy) > 0) {
|
||||
waveform.nextEventCcy = waveNextEventCcy;
|
||||
}
|
||||
}
|
||||
else if (static_cast<int32_t>(isrNextEventCcy - waveNextEventCcy) > 0) {
|
||||
isrNextEventCcy = waveNextEventCcy;
|
||||
}
|
||||
}
|
||||
now = ESP.getCycleCount();
|
||||
}
|
||||
//clockDrift = 0;
|
||||
}
|
||||
|
||||
int32_t callbackCcys = 0;
|
||||
if (waveform.timer1CB) {
|
||||
callbackCcys = scaleCcys(waveform.timer1CB(), isCPU2X);
|
||||
}
|
||||
now = ESP.getCycleCount();
|
||||
int32_t nextEventCcys = waveform.nextEventCcy - now;
|
||||
// Account for unknown duration of timer1CB().
|
||||
if (waveform.timer1CB && nextEventCcys > callbackCcys) {
|
||||
waveform.nextEventCcy = now + callbackCcys;
|
||||
nextEventCcys = callbackCcys;
|
||||
}
|
||||
|
||||
// Timer is 80MHz fixed. 160MHz CPU frequency need scaling.
|
||||
int32_t deltaIrqCcys = DELTAIRQCCYS;
|
||||
int32_t irqLatencyCcys = IRQLATENCYCCYS;
|
||||
if (isCPU2X) {
|
||||
nextEventCcys >>= 1;
|
||||
deltaIrqCcys >>= 1;
|
||||
irqLatencyCcys >>= 1;
|
||||
}
|
||||
|
||||
// Firing timer too soon, the NMI occurs before ISR has returned.
|
||||
if (nextEventCcys < irqLatencyCcys + deltaIrqCcys) {
|
||||
waveform.nextEventCcy = now + IRQLATENCYCCYS + DELTAIRQCCYS;
|
||||
nextEventCcys = irqLatencyCcys;
|
||||
}
|
||||
else {
|
||||
nextEventCcys -= deltaIrqCcys;
|
||||
}
|
||||
|
||||
// Register access is fast and edge IRQ was configured before.
|
||||
T1L = nextEventCcys;
|
||||
}
|
||||
469
lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h
Normal file
469
lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h
Normal file
@@ -0,0 +1,469 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel driver for ESP32 RMTs using High-priority Interrupt
|
||||
|
||||
(NB. This cannot be mixed with the non-HI driver.)
|
||||
|
||||
Written by Will M. Miles.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by donating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus 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 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus 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 NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
// Use the NeoEspRmtSpeed types from the driver-based implementation
|
||||
#include <NeoPixelBus.h>
|
||||
|
||||
|
||||
namespace NeoEsp32RmtHiMethodDriver {
|
||||
// Install the driver for a specific channel, specifying timing properties
|
||||
esp_err_t Install(rmt_channel_t channel, uint32_t rmtBit0, uint32_t rmtBit1, uint32_t resetDuration);
|
||||
|
||||
// Remove the driver on a specific channel
|
||||
esp_err_t Uninstall(rmt_channel_t channel);
|
||||
|
||||
// Write a buffer of data to a specific channel.
|
||||
// Buffer reference is held until write completes.
|
||||
esp_err_t Write(rmt_channel_t channel, const uint8_t *src, size_t src_size);
|
||||
|
||||
// Wait until transaction is complete.
|
||||
esp_err_t WaitForTxDone(rmt_channel_t channel, TickType_t wait_time);
|
||||
};
|
||||
|
||||
template<typename T_SPEED, typename T_CHANNEL> class NeoEsp32RmtHIMethodBase
|
||||
{
|
||||
public:
|
||||
typedef NeoNoSettings SettingsObject;
|
||||
|
||||
NeoEsp32RmtHIMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
|
||||
_sizeData(pixelCount * elementSize + settingsSize),
|
||||
_pin(pin)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
NeoEsp32RmtHIMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) :
|
||||
_sizeData(pixelCount* elementSize + settingsSize),
|
||||
_pin(pin),
|
||||
_channel(channel)
|
||||
{
|
||||
construct();
|
||||
}
|
||||
|
||||
~NeoEsp32RmtHIMethodBase()
|
||||
{
|
||||
// wait until the last send finishes before destructing everything
|
||||
// arbitrary time out of 10 seconds
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(NeoEsp32RmtHiMethodDriver::WaitForTxDone(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS));
|
||||
|
||||
ESP_ERROR_CHECK(NeoEsp32RmtHiMethodDriver::Uninstall(_channel.RmtChannelNumber));
|
||||
|
||||
gpio_matrix_out(_pin, SIG_GPIO_OUT_IDX, false, false);
|
||||
pinMode(_pin, INPUT);
|
||||
|
||||
free(_dataEditing);
|
||||
free(_dataSending);
|
||||
}
|
||||
|
||||
bool IsReadyToUpdate() const
|
||||
{
|
||||
return (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT_SILENT_TIMEOUT(NeoEsp32RmtHiMethodDriver::WaitForTxDone(_channel.RmtChannelNumber, 0)));
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
rmt_config_t config = {};
|
||||
|
||||
config.rmt_mode = RMT_MODE_TX;
|
||||
config.channel = _channel.RmtChannelNumber;
|
||||
config.gpio_num = static_cast<gpio_num_t>(_pin);
|
||||
config.mem_block_num = 1;
|
||||
config.tx_config.loop_en = false;
|
||||
|
||||
config.tx_config.idle_output_en = true;
|
||||
config.tx_config.idle_level = T_SPEED::IdleLevel;
|
||||
|
||||
config.tx_config.carrier_en = false;
|
||||
config.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
|
||||
|
||||
config.clk_div = T_SPEED::RmtClockDivider;
|
||||
|
||||
ESP_ERROR_CHECK(rmt_config(&config)); // Uses ESP library
|
||||
ESP_ERROR_CHECK(NeoEsp32RmtHiMethodDriver::Install(_channel.RmtChannelNumber, T_SPEED::RmtBit0, T_SPEED::RmtBit1, T_SPEED::RmtDurationReset));
|
||||
}
|
||||
|
||||
void Update(bool maintainBufferConsistency)
|
||||
{
|
||||
// wait for not actively sending data
|
||||
// this will time out at 10 seconds, an arbitrarily long period of time
|
||||
// and do nothing if this happens
|
||||
if (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT(NeoEsp32RmtHiMethodDriver::WaitForTxDone(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS)))
|
||||
{
|
||||
// now start the RMT transmit with the editing buffer before we swap
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(NeoEsp32RmtHiMethodDriver::Write(_channel.RmtChannelNumber, _dataEditing, _sizeData));
|
||||
|
||||
if (maintainBufferConsistency)
|
||||
{
|
||||
// copy editing to sending,
|
||||
// this maintains the contract that "colors present before will
|
||||
// be the same after", otherwise GetPixelColor will be inconsistent
|
||||
memcpy(_dataSending, _dataEditing, _sizeData);
|
||||
}
|
||||
|
||||
// swap so the user can modify without affecting the async operation
|
||||
std::swap(_dataSending, _dataEditing);
|
||||
}
|
||||
}
|
||||
|
||||
bool AlwaysUpdate()
|
||||
{
|
||||
// this method requires update to be called only if changes to buffer
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SwapBuffers()
|
||||
{
|
||||
std::swap(_dataSending, _dataEditing);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t* getData() const
|
||||
{
|
||||
return _dataEditing;
|
||||
};
|
||||
|
||||
size_t getDataSize() const
|
||||
{
|
||||
return _sizeData;
|
||||
}
|
||||
|
||||
void applySettings([[maybe_unused]] const SettingsObject& settings)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const size_t _sizeData; // Size of '_data*' buffers
|
||||
const uint8_t _pin; // output pin number
|
||||
const T_CHANNEL _channel; // holds instance for multi channel support
|
||||
|
||||
// Holds data stream which include LED color values and other settings as needed
|
||||
uint8_t* _dataEditing; // exposed for get and set
|
||||
uint8_t* _dataSending; // used for async send using RMT
|
||||
|
||||
|
||||
void construct()
|
||||
{
|
||||
_dataEditing = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
// data cleared later in Begin()
|
||||
|
||||
_dataSending = static_cast<uint8_t*>(malloc(_sizeData));
|
||||
// no need to initialize it, it gets overwritten on every send
|
||||
}
|
||||
};
|
||||
|
||||
// normal
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannelN> NeoEsp32RmtHINWs2811Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannelN> NeoEsp32RmtHINWs2812xMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannelN> NeoEsp32RmtHINWs2816Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2805, NeoEsp32RmtChannelN> NeoEsp32RmtHINWs2805Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannelN> NeoEsp32RmtHINSk6812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannelN> NeoEsp32RmtHINTm1814Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannelN> NeoEsp32RmtHINTm1829Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannelN> NeoEsp32RmtHINTm1914Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannelN> NeoEsp32RmtHINApa106Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannelN> NeoEsp32RmtHINTx1812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedGs1903, NeoEsp32RmtChannelN> NeoEsp32RmtHINGs1903Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannelN> NeoEsp32RmtHIN800KbpsMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannelN> NeoEsp32RmtHIN400KbpsMethod;
|
||||
typedef NeoEsp32RmtHINWs2805Method NeoEsp32RmtHINWs2814Method;
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Ws2811Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Ws2812xMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Ws2816Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2805, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Ws2805Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Sk6812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Tm1814Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Tm1829Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Tm1914Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Apa106Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Tx1812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedGs1903, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Gs1903Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel0> NeoEsp32RmtHI0800KbpsMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel0> NeoEsp32RmtHI0400KbpsMethod;
|
||||
typedef NeoEsp32RmtHI0Ws2805Method NeoEsp32RmtHI0Ws2814Method;
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Ws2811Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Ws2812xMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Ws2816Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2805, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Ws2805Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Sk6812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Tm1814Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Tm1829Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Tm1914Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Apa106Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Tx1812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedGs1903, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Gs1903Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel1> NeoEsp32RmtHI1800KbpsMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel1> NeoEsp32RmtHI1400KbpsMethod;
|
||||
typedef NeoEsp32RmtHI1Ws2805Method NeoEsp32RmtHI1Ws2814Method;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Ws2811Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Ws2812xMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Ws2816Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2805, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Ws2805Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Sk6812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Tm1814Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Tm1829Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Tm1914Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Apa106Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Tx1812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedGs1903, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Gs1903Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel2> NeoEsp32RmtHI2800KbpsMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel2> NeoEsp32RmtHI2400KbpsMethod;
|
||||
typedef NeoEsp32RmtHI2Ws2805Method NeoEsp32RmtHI2Ws2814Method;
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Ws2811Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Ws2812xMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Ws2816Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2805, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Ws2805Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Sk6812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Tm1814Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Tm1829Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Tm1914Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Apa106Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Tx1812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedGs1903, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Gs1903Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel3> NeoEsp32RmtHI3800KbpsMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel3> NeoEsp32RmtHI3400KbpsMethod;
|
||||
typedef NeoEsp32RmtHI3Ws2805Method NeoEsp32RmtHI3Ws2814Method;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Ws2811Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Ws2812xMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Ws2816Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2805, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Ws2805Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Sk6812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Tm1814Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Tm1829Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Tm1914Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Apa106Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Tx1812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedGs1903, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Gs1903Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel4> NeoEsp32RmtHI4800KbpsMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel4> NeoEsp32RmtHI4400KbpsMethod;
|
||||
typedef NeoEsp32RmtHI4Ws2805Method NeoEsp32RmtHI4Ws2814Method;
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Ws2811Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Ws2812xMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Ws2816Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2805, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Ws2805Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Sk6812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Tm1814Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Tm1829Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Tm1914Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Apa106Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Tx1812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedGs1903, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Gs1903Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel5> NeoEsp32RmtHI5800KbpsMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel5> NeoEsp32RmtHI5400KbpsMethod;
|
||||
typedef NeoEsp32RmtHI5Ws2805Method NeoEsp32RmtHI5Ws2814Method;
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Ws2811Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Ws2812xMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Ws2816Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2805, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Ws2805Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Sk6812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Tm1814Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Tm1829Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Tm1914Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Apa106Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Tx1812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedGs1903, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Gs1903Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel6> NeoEsp32RmtHI6800KbpsMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel6> NeoEsp32RmtHI6400KbpsMethod;
|
||||
typedef NeoEsp32RmtHI6Ws2805Method NeoEsp32RmtHI6Ws2814Method;
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Ws2811Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Ws2812xMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Ws2816Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2805, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Ws2805Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Sk6812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Tm1814Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Tm1829Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Tm1914Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Apa106Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Tx1812Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedGs1903, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Gs1903Method;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel7> NeoEsp32RmtHI7800KbpsMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel7> NeoEsp32RmtHI7400KbpsMethod;
|
||||
typedef NeoEsp32RmtHI7Ws2805Method NeoEsp32RmtHI7Ws2814Method;
|
||||
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
// inverted
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannelN> NeoEsp32RmtHINWs2811InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannelN> NeoEsp32RmtHINWs2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannelN> NeoEsp32RmtHINWs2816InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2805, NeoEsp32RmtChannelN> NeoEsp32RmtHINWs2805InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannelN> NeoEsp32RmtHINSk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannelN> NeoEsp32RmtHINTm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannelN> NeoEsp32RmtHINTm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannelN> NeoEsp32RmtHINTm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannelN> NeoEsp32RmtHINApa106InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannelN> NeoEsp32RmtHINTx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedGs1903, NeoEsp32RmtChannelN> NeoEsp32RmtHINGs1903InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannelN> NeoEsp32RmtHIN800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannelN> NeoEsp32RmtHIN400KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHINWs2805InvertedMethod NeoEsp32RmtHINWs2814InvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Ws2816InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2805, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Ws2805InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Tx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedGs1903, NeoEsp32RmtChannel0> NeoEsp32RmtHI0Gs1903InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel0> NeoEsp32RmtHI0800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel0> NeoEsp32RmtHI0400KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHI0Ws2805InvertedMethod NeoEsp32RmtHI0Ws2814InvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Ws2816InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2805, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Ws2805InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Tx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedGs1903, NeoEsp32RmtChannel1> NeoEsp32RmtHI1Gs1903InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel1> NeoEsp32RmtHI1800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel1> NeoEsp32RmtHI1400KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHI1Ws2805InvertedMethod NeoEsp32RmtHI1Ws2814InvertedMethod;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Ws2816InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2805, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Ws2805InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Tx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedGs1903, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Gs1903InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel2> NeoEsp32RmtHI2800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel2> NeoEsp32RmtHI2400KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHI2Ws2805InvertedMethod NeoEsp32RmtHI2Ws2814InvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2805, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Ws2805InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Ws2816InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Tx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedGs1903, NeoEsp32RmtChannel3> NeoEsp32RmtHI3Gs1903InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel3> NeoEsp32RmtHI3800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel3> NeoEsp32RmtHI3400KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHI3Ws2805InvertedMethod NeoEsp32RmtHI3Ws2814InvertedMethod;
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Ws2816InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2805, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Ws2805InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Tx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedGs1903, NeoEsp32RmtChannel4> NeoEsp32RmtHI4Gs1903InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel4> NeoEsp32RmtHI4800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel4> NeoEsp32RmtHI4400KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHI4Ws2805InvertedMethod NeoEsp32RmtHI4Ws2814InvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Ws2816InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2805, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Ws2805InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Tx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedGs1903, NeoEsp32RmtChannel5> NeoEsp32RmtHI5Gs1903InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel5> NeoEsp32RmtHI5800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel5> NeoEsp32RmtHI5400KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHI5Ws2805InvertedMethod NeoEsp32RmtHI5Ws2814InvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Ws2816InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2805, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Ws2805InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Tx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedGs1903, NeoEsp32RmtChannel6> NeoEsp32RmtHI6Gs1903InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel6> NeoEsp32RmtHI6800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel6> NeoEsp32RmtHI6400KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHI6Ws2805InvertedMethod NeoEsp32RmtHI6Ws2814InvertedMethod;
|
||||
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Ws2811InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Ws2812xInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Ws2816InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2805, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Ws2805InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Sk6812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Tm1814InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Tm1829InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Tm1914InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Apa106InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Tx1812InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedGs1903, NeoEsp32RmtChannel7> NeoEsp32RmtHI7Gs1903InvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel7> NeoEsp32RmtHI7800KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel7> NeoEsp32RmtHI7400KbpsInvertedMethod;
|
||||
typedef NeoEsp32RmtHI7Ws2805InvertedMethod NeoEsp32RmtHI7Ws2814InvertedMethod;
|
||||
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
|
||||
#endif
|
||||
12
lib/NeoESP32RmtHI/library.json
Normal file
12
lib/NeoESP32RmtHI/library.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "NeoESP32RmtHI",
|
||||
"build": { "libArchive": false },
|
||||
"platforms": ["espressif32"],
|
||||
"dependencies": [
|
||||
{
|
||||
"owner": "makuna",
|
||||
"name": "NeoPixelBus",
|
||||
"version": "^2.8.3"
|
||||
}
|
||||
]
|
||||
}
|
||||
263
lib/NeoESP32RmtHI/src/NeoEsp32RmtHI.S
Normal file
263
lib/NeoESP32RmtHI/src/NeoEsp32RmtHI.S
Normal file
@@ -0,0 +1,263 @@
|
||||
/* RMT ISR shim
|
||||
* Bridges from a high-level interrupt to the C++ code.
|
||||
*
|
||||
* This code is largely derived from Espressif's 'hli_vector.S' Bluetooth ISR.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__XTENSA__) && defined(ESP32) && !defined(CONFIG_BTDM_CTRL_HLI)
|
||||
|
||||
#include <freertos/xtensa_context.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc.h"
|
||||
|
||||
/* If the Bluetooth driver has hooked the high-priority interrupt, we piggyback on it and don't need this. */
|
||||
#ifndef CONFIG_BTDM_CTRL_HLI
|
||||
|
||||
/*
|
||||
Select interrupt based on system check level
|
||||
- Base ESP32: could be 4 or 5, depends on platform config
|
||||
- S2: 5
|
||||
- S3: 5
|
||||
*/
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
|
||||
/* Use level 4 */
|
||||
#define RFI_X 4
|
||||
#define xt_highintx xt_highint4
|
||||
#else /* !CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
|
||||
/* Use level 5 */
|
||||
#define RFI_X 5
|
||||
#define xt_highintx xt_highint5
|
||||
#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
|
||||
|
||||
// Register map, based on interrupt level
|
||||
#define EPC_X (EPC + RFI_X)
|
||||
#define EXCSAVE_X (EXCSAVE + RFI_X)
|
||||
|
||||
// The sp mnemonic is used all over in ESP's assembly, though I'm not sure where it's expected to be defined?
|
||||
#define sp a1
|
||||
|
||||
/* Interrupt stack size, for C code. */
|
||||
#define RMT_INTR_STACK_SIZE 512
|
||||
|
||||
/* Save area for the CPU state:
|
||||
* - 64 words for the general purpose registers
|
||||
* - 7 words for some of the special registers:
|
||||
* - WINDOWBASE, WINDOWSTART — only WINDOWSTART is truly needed
|
||||
* - SAR, LBEG, LEND, LCOUNT — since the C code might use these
|
||||
* - EPC1 — since the C code might cause window overflow exceptions
|
||||
* This is not laid out as standard exception frame structure
|
||||
* for simplicity of the save/restore code.
|
||||
*/
|
||||
#define REG_FILE_SIZE (64 * 4)
|
||||
#define SPECREG_OFFSET REG_FILE_SIZE
|
||||
#define SPECREG_SIZE (7 * 4)
|
||||
#define REG_SAVE_AREA_SIZE (SPECREG_OFFSET + SPECREG_SIZE)
|
||||
|
||||
.data
|
||||
_rmt_intr_stack:
|
||||
.space RMT_INTR_STACK_SIZE
|
||||
_rmt_save_ctx:
|
||||
.space REG_SAVE_AREA_SIZE
|
||||
|
||||
.section .iram1,"ax"
|
||||
.global xt_highintx
|
||||
.type xt_highintx,@function
|
||||
.align 4
|
||||
|
||||
xt_highintx:
|
||||
|
||||
movi a0, _rmt_save_ctx
|
||||
/* save 4 lower registers */
|
||||
s32i a1, a0, 4
|
||||
s32i a2, a0, 8
|
||||
s32i a3, a0, 12
|
||||
rsr a2, EXCSAVE_X /* holds the value of a0 */
|
||||
s32i a2, a0, 0
|
||||
|
||||
/* Save special registers */
|
||||
addi a0, a0, SPECREG_OFFSET
|
||||
rsr a2, WINDOWBASE
|
||||
s32i a2, a0, 0
|
||||
rsr a2, WINDOWSTART
|
||||
s32i a2, a0, 4
|
||||
rsr a2, SAR
|
||||
s32i a2, a0, 8
|
||||
#if XCHAL_HAVE_LOOPS
|
||||
rsr a2, LBEG
|
||||
s32i a2, a0, 12
|
||||
rsr a2, LEND
|
||||
s32i a2, a0, 16
|
||||
rsr a2, LCOUNT
|
||||
s32i a2, a0, 20
|
||||
#endif
|
||||
rsr a2, EPC1
|
||||
s32i a2, a0, 24
|
||||
|
||||
/* disable exception mode, window overflow */
|
||||
movi a0, PS_INTLEVEL(RFI_X+1) | PS_EXCM
|
||||
wsr a0, PS
|
||||
rsync
|
||||
|
||||
/* Save the remaining physical registers.
|
||||
* 4 registers are already saved, which leaves 60 registers to save.
|
||||
* (FIXME: consider the case when the CPU is configured with physical 32 registers)
|
||||
* These 60 registers are saved in 5 iterations, 12 registers at a time.
|
||||
*/
|
||||
movi a1, 5
|
||||
movi a3, _rmt_save_ctx + 4 * 4
|
||||
|
||||
/* This is repeated 5 times, each time the window is shifted by 12 registers.
|
||||
* We come here with a1 = downcounter, a3 = save pointer, a2 and a0 unused.
|
||||
*/
|
||||
1:
|
||||
s32i a4, a3, 0
|
||||
s32i a5, a3, 4
|
||||
s32i a6, a3, 8
|
||||
s32i a7, a3, 12
|
||||
s32i a8, a3, 16
|
||||
s32i a9, a3, 20
|
||||
s32i a10, a3, 24
|
||||
s32i a11, a3, 28
|
||||
s32i a12, a3, 32
|
||||
s32i a13, a3, 36
|
||||
s32i a14, a3, 40
|
||||
s32i a15, a3, 44
|
||||
|
||||
/* We are about to rotate the window, so that a12-a15 will become the new a0-a3.
|
||||
* Copy a0-a3 to a12-15 to still have access to these values.
|
||||
* At the same time we can decrement the counter and adjust the save area pointer
|
||||
*/
|
||||
|
||||
/* a0 is constant (_rmt_save_ctx), no need to copy */
|
||||
addi a13, a1, -1 /* copy and decrement the downcounter */
|
||||
/* a2 is scratch so no need to copy */
|
||||
addi a15, a3, 48 /* copy and adjust the save area pointer */
|
||||
beqz a13, 2f /* have saved all registers ? */
|
||||
rotw 3 /* rotate the window and go back */
|
||||
j 1b
|
||||
|
||||
/* the loop is complete */
|
||||
2:
|
||||
rotw 4 /* this brings us back to the original window */
|
||||
/* a0 still points to _rmt_save_ctx */
|
||||
|
||||
/* Can clear WINDOWSTART now, all registers are saved */
|
||||
rsr a2, WINDOWBASE
|
||||
/* WINDOWSTART = (1 << WINDOWBASE) */
|
||||
movi a3, 1
|
||||
ssl a2
|
||||
sll a3, a3
|
||||
wsr a3, WINDOWSTART
|
||||
|
||||
_highint_stack_switch:
|
||||
movi a0, 0
|
||||
movi sp, _rmt_intr_stack + RMT_INTR_STACK_SIZE - 16
|
||||
s32e a0, sp, -12 /* For GDB: set null SP */
|
||||
s32e a0, sp, -16 /* For GDB: set null PC */
|
||||
movi a0, _highint_stack_switch /* For GDB: cosmetics, for the frame where stack switch happened */
|
||||
|
||||
/* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
|
||||
movi a6, PS_INTLEVEL(RFI_X) | PS_UM | PS_WOE
|
||||
wsr a6, PS
|
||||
rsync
|
||||
|
||||
/* Call C handler */
|
||||
mov a6, sp
|
||||
call4 NeoEsp32RmtMethodIsr
|
||||
|
||||
l32e sp, sp, -12 /* switch back to the original stack */
|
||||
|
||||
/* Done with C handler; re-enable exception mode, disabling window overflow */
|
||||
movi a2, PS_INTLEVEL(RFI_X+1) | PS_EXCM /* TOCHECK */
|
||||
wsr a2, PS
|
||||
rsync
|
||||
|
||||
/* Restore the special registers.
|
||||
* WINDOWSTART will be restored near the end.
|
||||
*/
|
||||
movi a0, _rmt_save_ctx + SPECREG_OFFSET
|
||||
l32i a2, a0, 8
|
||||
wsr a2, SAR
|
||||
#if XCHAL_HAVE_LOOPS
|
||||
l32i a2, a0, 12
|
||||
wsr a2, LBEG
|
||||
l32i a2, a0, 16
|
||||
wsr a2, LEND
|
||||
l32i a2, a0, 20
|
||||
wsr a2, LCOUNT
|
||||
#endif
|
||||
l32i a2, a0, 24
|
||||
wsr a2, EPC1
|
||||
|
||||
/* Restoring the physical registers.
|
||||
* This is the reverse to the saving process above.
|
||||
*/
|
||||
|
||||
/* Rotate back to the final window, then start loading 12 registers at a time,
|
||||
* in 5 iterations.
|
||||
* Again, a1 is the downcounter and a3 is the save area pointer.
|
||||
* After each rotation, a1 and a3 are copied from a13 and a15.
|
||||
* To simplify the loop, we put the initial values into a13 and a15.
|
||||
*/
|
||||
rotw -4
|
||||
movi a15, _rmt_save_ctx + 64 * 4 /* point to the end of the save area */
|
||||
movi a13, 5
|
||||
|
||||
1:
|
||||
/* Copy a1 and a3 from their previous location,
|
||||
* at the same time decrementing and adjusting the save area pointer.
|
||||
*/
|
||||
addi a1, a13, -1
|
||||
addi a3, a15, -48
|
||||
|
||||
/* Load 12 registers */
|
||||
l32i a4, a3, 0
|
||||
l32i a5, a3, 4
|
||||
l32i a6, a3, 8
|
||||
l32i a7, a3, 12
|
||||
l32i a8, a3, 16
|
||||
l32i a9, a3, 20
|
||||
l32i a10, a3, 24
|
||||
l32i a11, a3, 28 /* ensure PS and EPC written */
|
||||
l32i a12, a3, 32
|
||||
l32i a13, a3, 36
|
||||
l32i a14, a3, 40
|
||||
l32i a15, a3, 44
|
||||
|
||||
/* Done with the loop? */
|
||||
beqz a1, 2f
|
||||
/* If no, rotate the window and repeat */
|
||||
rotw -3
|
||||
j 1b
|
||||
|
||||
2:
|
||||
/* Done with the loop. Only 4 registers (a0-a3 in the original window) remain
|
||||
* to be restored. Also need to restore WINDOWSTART, since all the general
|
||||
* registers are now in place.
|
||||
*/
|
||||
movi a0, _rmt_save_ctx
|
||||
|
||||
l32i a2, a0, SPECREG_OFFSET + 4
|
||||
wsr a2, WINDOWSTART
|
||||
|
||||
l32i a1, a0, 4
|
||||
l32i a2, a0, 8
|
||||
l32i a3, a0, 12
|
||||
rsr a0, EXCSAVE_X /* holds the value of a0 before the interrupt handler */
|
||||
|
||||
/* Return from the interrupt, restoring PS from EPS_X */
|
||||
rfi RFI_X
|
||||
|
||||
|
||||
/* The linker has no reason to link in this file; all symbols it exports are already defined
|
||||
(weakly!) in the default int handler. Define a symbol here so we can use it to have the
|
||||
linker inspect this anyway. */
|
||||
|
||||
.global ld_include_hli_vectors_rmt
|
||||
ld_include_hli_vectors_rmt:
|
||||
|
||||
|
||||
#endif // CONFIG_BTDM_CTRL_HLI
|
||||
#endif // XTensa
|
||||
507
lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp
Normal file
507
lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp
Normal file
@@ -0,0 +1,507 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
NeoPixel library helper functions for Esp32.
|
||||
|
||||
A BIG thanks to Andreas Merkle for the investigation and implementation of
|
||||
a workaround to the GCC bug that drops method attributes from template methods
|
||||
|
||||
Written by Michael C. Miller.
|
||||
|
||||
I invest time and resources providing this open source code,
|
||||
please support me by donating (see https://github.com/Makuna/NeoPixelBus)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
This file is part of the Makuna/NeoPixelBus library.
|
||||
|
||||
NeoPixelBus 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 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixelBus 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 NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
#include <algorithm>
|
||||
#include "esp_idf_version.h"
|
||||
#include "NeoEsp32RmtHIMethod.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rmt_reg.h"
|
||||
|
||||
#ifdef __riscv
|
||||
#include "riscv/interrupt.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
|
||||
#include "hal/rmt_ll.h"
|
||||
#else
|
||||
/* Shims for older ESP-IDF v3; we can safely assume original ESP32 */
|
||||
#include "soc/rmt_struct.h"
|
||||
|
||||
// Selected RMT API functions borrowed from ESP-IDF v4.4.8
|
||||
// components/hal/esp32/include/hal/rmt_ll.h
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
dev->conf_ch[channel].conf1.mem_rd_rst = 0;
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.tx_start = 1;
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
RMTMEM.chan[channel].data32[0].val = 0;
|
||||
dev->conf_ch[channel].conf1.tx_start = 0;
|
||||
dev->conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
dev->conf_ch[channel].conf1.mem_rd_rst = 0;
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_tx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->apb_conf.mem_tx_wrap_en = enable;
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.tx_conti_mode = enable;
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline uint32_t rmt_ll_tx_get_channel_status(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
return dev->status_ch[channel];
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit)
|
||||
{
|
||||
dev->tx_lim_ch[channel].limit = limit;
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
dev->int_ena.val |= mask;
|
||||
} else {
|
||||
dev->int_ena.val &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_enable_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->int_ena.val &= ~(1 << (channel * 3));
|
||||
dev->int_ena.val |= (enable << (channel * 3));
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_enable_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->int_ena.val &= ~(1 << (channel * 3 + 2));
|
||||
dev->int_ena.val |= (enable << (channel * 3 + 2));
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_enable_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->int_ena.val &= ~(1 << (channel + 24));
|
||||
dev->int_ena.val |= (enable << (channel + 24));
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_clear_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->int_clr.val = (1 << (channel * 3));
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_clear_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->int_clr.val = (1 << (channel * 3 + 2));
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void rmt_ll_clear_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->int_clr.val = (1 << (channel + 24));
|
||||
}
|
||||
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline uint32_t rmt_ll_get_tx_thres_interrupt_status(rmt_dev_t *dev)
|
||||
{
|
||||
uint32_t status = dev->int_st.val;
|
||||
return (status & 0xFF000000) >> 24;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// *********************************
|
||||
// Select method for binding interrupt
|
||||
//
|
||||
// - If the Bluetooth driver has registered a high-level interrupt, piggyback on that API
|
||||
// - If we're on a modern core, allocate the interrupt with the API (old cores are bugged)
|
||||
// - Otherwise use the low-level hardware API to manually bind the interrupt
|
||||
|
||||
|
||||
#if defined(CONFIG_BTDM_CTRL_HLI)
|
||||
// Espressif's bluetooth driver offers a helpful sharing layer; bring in the interrupt management calls
|
||||
#include "hal/interrupt_controller_hal.h"
|
||||
extern "C" esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask);
|
||||
|
||||
#else /* !CONFIG_BTDM_CTRL_HLI*/
|
||||
|
||||
// Declare the our high-priority ISR handler
|
||||
extern "C" void ld_include_hli_vectors_rmt(); // an object with an address, but no space
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#include "soc/periph_defs.h"
|
||||
#endif
|
||||
|
||||
// Select level flag
|
||||
#if defined(__riscv)
|
||||
// RISCV chips don't block interrupts while scheduling; all we need to do is be higher than the WiFi ISR
|
||||
#define INT_LEVEL_FLAG ESP_INTR_FLAG_LEVEL3
|
||||
#elif defined(CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5)
|
||||
#define INT_LEVEL_FLAG ESP_INTR_FLAG_LEVEL4
|
||||
#else
|
||||
#define INT_LEVEL_FLAG ESP_INTR_FLAG_LEVEL5
|
||||
#endif
|
||||
|
||||
// ESP-IDF v3 cannot enable high priority interrupts through the API at all;
|
||||
// and ESP-IDF v4 on XTensa cannot enable Level 5 due to incorrect interrupt descriptor tables
|
||||
#if !defined(__XTENSA__) || (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) || ((ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) && CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5))
|
||||
#define NEOESP32_RMT_CAN_USE_INTR_ALLOC
|
||||
|
||||
// XTensa cores require the assembly bridge
|
||||
#ifdef __XTENSA__
|
||||
#define HI_IRQ_HANDLER nullptr
|
||||
#define HI_IRQ_HANDLER_ARG ld_include_hli_vectors_rmt
|
||||
#else
|
||||
#define HI_IRQ_HANDLER NeoEsp32RmtMethodIsr
|
||||
#define HI_IRQ_HANDLER_ARG nullptr
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* !CONFIG_BTDM_CTRL_HLI && !NEOESP32_RMT_CAN_USE_INTR_ALLOC */
|
||||
// This is the index of the LV5 interrupt vector - see interrupt descriptor table in idf components/hal/esp32/interrupt_descriptor_table.c
|
||||
#define ESP32_LV5_IRQ_INDEX 26
|
||||
|
||||
#endif /* NEOESP32_RMT_CAN_USE_INTR_ALLOC */
|
||||
#endif /* CONFIG_BTDM_CTRL_HLI */
|
||||
|
||||
|
||||
// RMT driver implementation
|
||||
struct NeoEsp32RmtHIChannelState {
|
||||
uint32_t rmtBit0, rmtBit1;
|
||||
uint32_t resetDuration;
|
||||
|
||||
const byte* txDataStart; // data array
|
||||
const byte* txDataEnd; // one past end
|
||||
const byte* txDataCurrent; // current location
|
||||
size_t rmtOffset;
|
||||
};
|
||||
|
||||
// Global variables
|
||||
#if defined(NEOESP32_RMT_CAN_USE_INTR_ALLOC)
|
||||
static intr_handle_t isrHandle = nullptr;
|
||||
#endif
|
||||
|
||||
static NeoEsp32RmtHIChannelState** driverState = nullptr;
|
||||
constexpr size_t rmtBatchSize = RMT_MEM_ITEM_NUM / 2;
|
||||
|
||||
// Fill the RMT buffer memory
|
||||
// This is implemented using many arguments instead of passing the structure object to ensure we do only one lookup
|
||||
// All the arguments are passed in registers, so they don't need to be looked up again
|
||||
static void IRAM_ATTR RmtFillBuffer(uint8_t channel, const byte** src_ptr, const byte* end, uint32_t bit0, uint32_t bit1, size_t* offset_ptr, size_t reserve) {
|
||||
// We assume that (rmtToWrite % 8) == 0
|
||||
size_t rmtToWrite = rmtBatchSize - reserve;
|
||||
rmt_item32_t* dest =(rmt_item32_t*) &RMTMEM.chan[channel].data32[*offset_ptr + reserve]; // write directly in to RMT memory
|
||||
const byte* psrc = *src_ptr;
|
||||
|
||||
*offset_ptr ^= rmtBatchSize;
|
||||
|
||||
if (psrc != end) {
|
||||
while (rmtToWrite > 0) {
|
||||
uint8_t data = *psrc;
|
||||
for (uint8_t bit = 0; bit < 8; bit++)
|
||||
{
|
||||
dest->val = (data & 0x80) ? bit1 : bit0;
|
||||
dest++;
|
||||
data <<= 1;
|
||||
}
|
||||
rmtToWrite -= 8;
|
||||
psrc++;
|
||||
|
||||
if (psrc == end) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*src_ptr = psrc;
|
||||
}
|
||||
|
||||
if (rmtToWrite > 0) {
|
||||
// Add end event
|
||||
rmt_item32_t bit0_val = {{.val = bit0 }};
|
||||
*dest = rmt_item32_t {{{ .duration0 = 0, .level0 = bit0_val.level1, .duration1 = 0, .level1 = bit0_val.level1 }}};
|
||||
}
|
||||
}
|
||||
|
||||
static void IRAM_ATTR RmtStartWrite(uint8_t channel, NeoEsp32RmtHIChannelState& state) {
|
||||
// Reset context state
|
||||
state.rmtOffset = 0;
|
||||
|
||||
// Fill the first part of the buffer with a reset event
|
||||
// FUTURE: we could do timing analysis with the last interrupt on this channel
|
||||
// Use 8 words to stay aligned with the buffer fill logic
|
||||
rmt_item32_t bit0_val = {{.val = state.rmtBit0 }};
|
||||
rmt_item32_t fill = {{{ .duration0 = 100, .level0 = bit0_val.level1, .duration1 = 100, .level1 = bit0_val.level1 }}};
|
||||
rmt_item32_t* dest = (rmt_item32_t*) &RMTMEM.chan[channel].data32[0];
|
||||
for (auto i = 0; i < 7; ++i) dest[i] = fill;
|
||||
fill.duration1 = state.resetDuration > 1400 ? (state.resetDuration - 1400) : 100;
|
||||
dest[7] = fill;
|
||||
|
||||
// Fill the remaining buffer with real data
|
||||
RmtFillBuffer(channel, &state.txDataCurrent, state.txDataEnd, state.rmtBit0, state.rmtBit1, &state.rmtOffset, 8);
|
||||
RmtFillBuffer(channel, &state.txDataCurrent, state.txDataEnd, state.rmtBit0, state.rmtBit1, &state.rmtOffset, 0);
|
||||
|
||||
// Start operation
|
||||
rmt_ll_clear_tx_thres_interrupt(&RMT, channel);
|
||||
rmt_ll_tx_reset_pointer(&RMT, channel);
|
||||
rmt_ll_tx_start(&RMT, channel);
|
||||
}
|
||||
|
||||
extern "C" void IRAM_ATTR NeoEsp32RmtMethodIsr(void *arg) {
|
||||
// Tx threshold interrupt
|
||||
uint32_t status = rmt_ll_get_tx_thres_interrupt_status(&RMT);
|
||||
while (status) {
|
||||
uint8_t channel = __builtin_ffs(status) - 1;
|
||||
if (driverState[channel]) {
|
||||
// Normal case
|
||||
NeoEsp32RmtHIChannelState& state = *driverState[channel];
|
||||
RmtFillBuffer(channel, &state.txDataCurrent, state.txDataEnd, state.rmtBit0, state.rmtBit1, &state.rmtOffset, 0);
|
||||
} else {
|
||||
// Danger - another driver got invoked?
|
||||
rmt_ll_tx_stop(&RMT, channel);
|
||||
}
|
||||
rmt_ll_clear_tx_thres_interrupt(&RMT, channel);
|
||||
status = rmt_ll_get_tx_thres_interrupt_status(&RMT);
|
||||
}
|
||||
};
|
||||
|
||||
// Wrapper around the register analysis defines
|
||||
// For all currently supported chips, this is constant for all channels; but this is not true of *all* ESP32
|
||||
static inline bool _RmtStatusIsTransmitting(rmt_channel_t channel, uint32_t status) {
|
||||
uint32_t v;
|
||||
switch(channel) {
|
||||
#ifdef RMT_STATE_CH0
|
||||
case 0: v = (status >> RMT_STATE_CH0_S) & RMT_STATE_CH0_V; break;
|
||||
#endif
|
||||
#ifdef RMT_STATE_CH1
|
||||
case 1: v = (status >> RMT_STATE_CH1_S) & RMT_STATE_CH1_V; break;
|
||||
#endif
|
||||
#ifdef RMT_STATE_CH2
|
||||
case 2: v = (status >> RMT_STATE_CH2_S) & RMT_STATE_CH2_V; break;
|
||||
#endif
|
||||
#ifdef RMT_STATE_CH3
|
||||
case 3: v = (status >> RMT_STATE_CH3_S) & RMT_STATE_CH3_V; break;
|
||||
#endif
|
||||
#ifdef RMT_STATE_CH4
|
||||
case 4: v = (status >> RMT_STATE_CH4_S) & RMT_STATE_CH4_V; break;
|
||||
#endif
|
||||
#ifdef RMT_STATE_CH5
|
||||
case 5: v = (status >> RMT_STATE_CH5_S) & RMT_STATE_CH5_V; break;
|
||||
#endif
|
||||
#ifdef RMT_STATE_CH6
|
||||
case 6: v = (status >> RMT_STATE_CH6_S) & RMT_STATE_CH6_V; break;
|
||||
#endif
|
||||
#ifdef RMT_STATE_CH7
|
||||
case 7: v = (status >> RMT_STATE_CH7_S) & RMT_STATE_CH7_V; break;
|
||||
#endif
|
||||
default: v = 0;
|
||||
}
|
||||
|
||||
return v != 0;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t NeoEsp32RmtHiMethodDriver::Install(rmt_channel_t channel, uint32_t rmtBit0, uint32_t rmtBit1, uint32_t reset) {
|
||||
// Validate channel number
|
||||
if (channel >= RMT_CHANNEL_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t err = ESP_OK;
|
||||
if (!driverState) {
|
||||
// First time init
|
||||
driverState = reinterpret_cast<NeoEsp32RmtHIChannelState**>(heap_caps_calloc(RMT_CHANNEL_MAX, sizeof(NeoEsp32RmtHIChannelState*), MALLOC_CAP_INTERNAL));
|
||||
if (!driverState) return ESP_ERR_NO_MEM;
|
||||
|
||||
// Ensure all interrupts are cleared before binding
|
||||
RMT.int_ena.val = 0;
|
||||
RMT.int_clr.val = 0xFFFFFFFF;
|
||||
|
||||
// Bind interrupt handler
|
||||
#if defined(CONFIG_BTDM_CTRL_HLI)
|
||||
// Bluetooth driver has taken the empty high-priority interrupt. Fortunately, it allows us to
|
||||
// hook up another handler.
|
||||
err = hli_intr_register(NeoEsp32RmtMethodIsr, nullptr, (uintptr_t) &RMT.int_st, 0xFF000000);
|
||||
// 25 is the magic number of the bluetooth ISR on ESP32 - see soc/soc.h.
|
||||
intr_matrix_set(cpu_hal_get_core_id(), ETS_RMT_INTR_SOURCE, 25);
|
||||
intr_cntrl_ll_enable_interrupts(1<<25);
|
||||
#elif defined(NEOESP32_RMT_CAN_USE_INTR_ALLOC)
|
||||
// Use the platform code to allocate the interrupt
|
||||
// If we need the additional assembly bridge, we pass it as the "arg" to the IDF so it gets linked in
|
||||
err = esp_intr_alloc(ETS_RMT_INTR_SOURCE, INT_LEVEL_FLAG | ESP_INTR_FLAG_IRAM, HI_IRQ_HANDLER, (void*) HI_IRQ_HANDLER_ARG, &isrHandle);
|
||||
//err = ESP_ERR_NOT_FINISHED;
|
||||
#else
|
||||
// Broken IDF API does not allow us to reserve the interrupt; do it manually
|
||||
static volatile const void* __attribute__((used)) pleaseLinkAssembly = (void*) ld_include_hli_vectors_rmt;
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_RMT_INTR_SOURCE, ESP32_LV5_IRQ_INDEX);
|
||||
ESP_INTR_ENABLE(ESP32_LV5_IRQ_INDEX);
|
||||
#endif
|
||||
|
||||
if (err != ESP_OK) {
|
||||
heap_caps_free(driverState);
|
||||
driverState = nullptr;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (driverState[channel] != nullptr) {
|
||||
return ESP_ERR_INVALID_STATE; // already in use
|
||||
}
|
||||
|
||||
NeoEsp32RmtHIChannelState* state = reinterpret_cast<NeoEsp32RmtHIChannelState*>(heap_caps_calloc(1, sizeof(NeoEsp32RmtHIChannelState), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
|
||||
if (state == nullptr) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
// Store timing information
|
||||
state->rmtBit0 = rmtBit0;
|
||||
state->rmtBit1 = rmtBit1;
|
||||
state->resetDuration = reset;
|
||||
|
||||
// Initialize hardware
|
||||
rmt_ll_tx_stop(&RMT, channel);
|
||||
rmt_ll_tx_reset_pointer(&RMT, channel);
|
||||
rmt_ll_enable_tx_err_interrupt(&RMT, channel, false);
|
||||
rmt_ll_enable_tx_end_interrupt(&RMT, channel, false);
|
||||
rmt_ll_enable_tx_thres_interrupt(&RMT, channel, false);
|
||||
rmt_ll_clear_tx_err_interrupt(&RMT, channel);
|
||||
rmt_ll_clear_tx_end_interrupt(&RMT, channel);
|
||||
rmt_ll_clear_tx_thres_interrupt(&RMT, channel);
|
||||
|
||||
rmt_ll_tx_enable_loop(&RMT, channel, false);
|
||||
rmt_ll_tx_enable_pingpong(&RMT, channel, true);
|
||||
rmt_ll_tx_set_limit(&RMT, channel, rmtBatchSize);
|
||||
|
||||
driverState[channel] = state;
|
||||
|
||||
rmt_ll_enable_tx_thres_interrupt(&RMT, channel, true);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t NeoEsp32RmtHiMethodDriver::Uninstall(rmt_channel_t channel) {
|
||||
if ((channel >= RMT_CHANNEL_MAX) || !driverState || !driverState[channel]) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
NeoEsp32RmtHIChannelState* state = driverState[channel];
|
||||
|
||||
WaitForTxDone(channel, 10000 / portTICK_PERIOD_MS);
|
||||
|
||||
// Done or not, we're out of here
|
||||
rmt_ll_tx_stop(&RMT, channel);
|
||||
rmt_ll_enable_tx_thres_interrupt(&RMT, channel, false);
|
||||
driverState[channel] = nullptr;
|
||||
heap_caps_free(state);
|
||||
|
||||
#if !defined(CONFIG_BTDM_CTRL_HLI) /* Cannot unbind from bluetooth ISR */
|
||||
// Turn off the driver ISR and release global state if none are left
|
||||
for (uint8_t channelIndex = 0; channelIndex < RMT_CHANNEL_MAX; ++channelIndex) {
|
||||
if (driverState[channelIndex]) return ESP_OK; // done
|
||||
}
|
||||
|
||||
#if defined(NEOESP32_RMT_CAN_USE_INTR_ALLOC)
|
||||
esp_intr_free(isrHandle);
|
||||
#else
|
||||
ESP_INTR_DISABLE(ESP32_LV5_IRQ_INDEX);
|
||||
#endif
|
||||
|
||||
heap_caps_free(driverState);
|
||||
driverState = nullptr;
|
||||
#endif /* !defined(CONFIG_BTDM_CTRL_HLI) */
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t NeoEsp32RmtHiMethodDriver::Write(rmt_channel_t channel, const uint8_t *src, size_t src_size) {
|
||||
if ((channel >= RMT_CHANNEL_MAX) || !driverState || !driverState[channel]) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
NeoEsp32RmtHIChannelState& state = *driverState[channel];
|
||||
esp_err_t result = WaitForTxDone(channel, 10000 / portTICK_PERIOD_MS);
|
||||
|
||||
if (result == ESP_OK) {
|
||||
state.txDataStart = src;
|
||||
state.txDataCurrent = src;
|
||||
state.txDataEnd = src + src_size;
|
||||
RmtStartWrite(channel, state);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
esp_err_t NeoEsp32RmtHiMethodDriver::WaitForTxDone(rmt_channel_t channel, TickType_t wait_time) {
|
||||
if ((channel >= RMT_CHANNEL_MAX) || !driverState || !driverState[channel]) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
NeoEsp32RmtHIChannelState& state = *driverState[channel];
|
||||
// yield-wait until wait_time
|
||||
esp_err_t rv = ESP_OK;
|
||||
uint32_t status;
|
||||
while(1) {
|
||||
status = rmt_ll_tx_get_channel_status(&RMT, channel);
|
||||
if (!_RmtStatusIsTransmitting(channel, status)) break;
|
||||
if (wait_time == 0) { rv = ESP_ERR_TIMEOUT; break; };
|
||||
|
||||
TickType_t sleep = std::min(wait_time, (TickType_t) 5);
|
||||
vTaskDelay(sleep);
|
||||
wait_time -= sleep;
|
||||
};
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
||||
788
package-lock.json
generated
Normal file
788
package-lock.json
generated
Normal file
@@ -0,0 +1,788 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.16.0-alpha",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wled",
|
||||
"version": "0.16.0-alpha",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"clean-css": "^5.3.3",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"nodemon": "^3.1.9",
|
||||
"web-resource-inliner": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
|
||||
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/set-array": "^1.2.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/set-array": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
||||
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/source-map": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
|
||||
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.25",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.14.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
||||
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-colors": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
|
||||
"integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/camel-case": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
|
||||
"integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pascal-case": "^3.1.2",
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/clean-css": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz",
|
||||
"integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"source-map": "~0.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
||||
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/dom-serializer": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
|
||||
"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^4.2.0",
|
||||
"entities": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-serializer/node_modules/domhandler": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
|
||||
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-serializer/node_modules/entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
|
||||
"license": "BSD-2-Clause",
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domelementtype": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
||||
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/domhandler": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz",
|
||||
"integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||
"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^1.0.1",
|
||||
"domelementtype": "^2.2.0",
|
||||
"domhandler": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domutils/node_modules/domhandler": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
|
||||
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dot-case": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
|
||||
"integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"no-case": "^3.0.4",
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-goat": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz",
|
||||
"integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/html-minifier-terser": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz",
|
||||
"integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"camel-case": "^4.1.2",
|
||||
"clean-css": "~5.3.2",
|
||||
"commander": "^10.0.0",
|
||||
"entities": "^4.4.0",
|
||||
"param-case": "^3.0.4",
|
||||
"relateurl": "^0.2.7",
|
||||
"terser": "^5.15.1"
|
||||
},
|
||||
"bin": {
|
||||
"html-minifier-terser": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.13.1 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz",
|
||||
"integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^3.3.0",
|
||||
"domutils": "^2.4.2",
|
||||
"entities": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/htmlparser2?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2/node_modules/entities": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
|
||||
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
|
||||
"license": "BSD-2-Clause",
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore-by-default": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
|
||||
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lower-case": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
|
||||
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
|
||||
"integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mime": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/no-case": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
||||
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lower-case": "^2.0.2",
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon": {
|
||||
"version": "3.1.9",
|
||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz",
|
||||
"integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.2",
|
||||
"debug": "^4",
|
||||
"ignore-by-default": "^1.0.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"pstree.remy": "^1.1.8",
|
||||
"semver": "^7.5.3",
|
||||
"simple-update-notifier": "^2.0.0",
|
||||
"supports-color": "^5.5.0",
|
||||
"touch": "^3.1.0",
|
||||
"undefsafe": "^2.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"nodemon": "bin/nodemon.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/nodemon"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/param-case": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
|
||||
"integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dot-case": "^3.0.4",
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/pascal-case": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
|
||||
"integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"no-case": "^3.0.4",
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pstree.remy": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
|
||||
"integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/relateurl": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
||||
"integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz",
|
||||
"integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-update-notifier": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
|
||||
"integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"semver": "^7.5.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-support": {
|
||||
"version": "0.5.21",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.37.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz",
|
||||
"integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
"acorn": "^8.8.2",
|
||||
"commander": "^2.20.0",
|
||||
"source-map-support": "~0.5.20"
|
||||
},
|
||||
"bin": {
|
||||
"terser": "bin/terser"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/terser/node_modules/commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/touch": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
|
||||
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"nodetouch": "bin/nodetouch.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/undefsafe": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
|
||||
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/valid-data-url": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz",
|
||||
"integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/web-resource-inliner": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-7.0.0.tgz",
|
||||
"integrity": "sha512-NlfnGF8MY9ZUwFjyq3vOUBx7KwF8bmE+ywR781SB0nWB6MoMxN4BA8gtgP1KGTZo/O/AyWJz7HZpR704eaj4mg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-colors": "^4.1.1",
|
||||
"escape-goat": "^3.0.0",
|
||||
"htmlparser2": "^5.0.0",
|
||||
"mime": "^2.4.6",
|
||||
"valid-data-url": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
34
package.json
Normal file
34
package.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.16.0-alpha",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
"lib": "lib",
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node tools/cdata.js",
|
||||
"test": "node --test",
|
||||
"dev": "nodemon -e js,html,htm,css,png,jpg,gif,ico,js -w tools/ -w wled00/data/ -x node tools/cdata.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wled-dev/WLED.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/wled-dev/WLED/issues"
|
||||
},
|
||||
"homepage": "https://github.com/wled-dev/WLED#readme",
|
||||
"dependencies": {
|
||||
"clean-css": "^5.3.3",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"web-resource-inliner": "^7.0.0",
|
||||
"nodemon": "^3.1.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
}
|
||||
21
pio-scripts/build_ui.py
Normal file
21
pio-scripts/build_ui.py
Normal file
@@ -0,0 +1,21 @@
|
||||
Import("env")
|
||||
import shutil
|
||||
|
||||
node_ex = shutil.which("node")
|
||||
# Check if Node.js is installed and present in PATH if it failed, abort the build
|
||||
if node_ex is None:
|
||||
print('\x1b[0;31;43m' + 'Node.js is not installed or missing from PATH html css js will not be processed check https://kno.wled.ge/advanced/compiling-wled/' + '\x1b[0m')
|
||||
exitCode = env.Execute("null")
|
||||
exit(exitCode)
|
||||
else:
|
||||
# Install the necessary node packages for the pre-build asset bundling script
|
||||
print('\x1b[6;33;42m' + 'Installing node packages' + '\x1b[0m')
|
||||
env.Execute("npm ci")
|
||||
|
||||
# Call the bundling script
|
||||
exitCode = env.Execute("npm run build")
|
||||
|
||||
# If it failed, abort the build
|
||||
if (exitCode):
|
||||
print('\x1b[0;31;43m' + 'npm run build fails check https://kno.wled.ge/advanced/compiling-wled/' + '\x1b[0m')
|
||||
exit(exitCode)
|
||||
107
pio-scripts/load_usermods.py
Normal file
107
pio-scripts/load_usermods.py
Normal file
@@ -0,0 +1,107 @@
|
||||
Import('env')
|
||||
from collections import deque
|
||||
from pathlib import Path # For OS-agnostic path manipulation
|
||||
from click import secho
|
||||
from SCons.Script import Exit
|
||||
from platformio.builder.tools.piolib import LibBuilderBase
|
||||
|
||||
usermod_dir = Path(env["PROJECT_DIR"]).resolve() / "usermods"
|
||||
|
||||
# Utility functions
|
||||
def find_usermod(mod: str) -> Path:
|
||||
"""Locate this library in the usermods folder.
|
||||
We do this to avoid needing to rename a bunch of folders;
|
||||
this could be removed later
|
||||
"""
|
||||
# Check name match
|
||||
mp = usermod_dir / mod
|
||||
if mp.exists():
|
||||
return mp
|
||||
mp = usermod_dir / f"{mod}_v2"
|
||||
if mp.exists():
|
||||
return mp
|
||||
mp = usermod_dir / f"usermod_v2_{mod}"
|
||||
if mp.exists():
|
||||
return mp
|
||||
raise RuntimeError(f"Couldn't locate module {mod} in usermods directory!")
|
||||
|
||||
def is_wled_module(dep: LibBuilderBase) -> bool:
|
||||
"""Returns true if the specified library is a wled module
|
||||
"""
|
||||
return usermod_dir in Path(dep.src_dir).parents or str(dep.name).startswith("wled-")
|
||||
|
||||
## Script starts here
|
||||
# Process usermod option
|
||||
usermods = env.GetProjectOption("custom_usermods","")
|
||||
|
||||
# Handle "all usermods" case
|
||||
if usermods == '*':
|
||||
usermods = [f.name for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()]
|
||||
else:
|
||||
usermods = usermods.split()
|
||||
|
||||
if usermods:
|
||||
# Inject usermods in to project lib_deps
|
||||
symlinks = [f"symlink://{find_usermod(mod).resolve()}" for mod in usermods]
|
||||
env.GetProjectConfig().set("env:" + env['PIOENV'], 'lib_deps', env.GetProjectOption('lib_deps') + symlinks)
|
||||
|
||||
# Utility function for assembling usermod include paths
|
||||
def cached_add_includes(dep, dep_cache: set, includes: deque):
|
||||
""" Add dep's include paths to includes if it's not in the cache """
|
||||
if dep not in dep_cache:
|
||||
dep_cache.add(dep)
|
||||
for include in dep.get_include_dirs():
|
||||
if include not in includes:
|
||||
includes.appendleft(include)
|
||||
if usermod_dir not in Path(dep.src_dir).parents:
|
||||
# Recurse, but only for NON-usermods
|
||||
for subdep in dep.depbuilders:
|
||||
cached_add_includes(subdep, dep_cache, includes)
|
||||
|
||||
# Monkey-patch ConfigureProjectLibBuilder to mark up the dependencies
|
||||
# Save the old value
|
||||
old_ConfigureProjectLibBuilder = env.ConfigureProjectLibBuilder
|
||||
|
||||
# Our new wrapper
|
||||
def wrapped_ConfigureProjectLibBuilder(xenv):
|
||||
# Call the wrapped function
|
||||
result = old_ConfigureProjectLibBuilder.clone(xenv)()
|
||||
|
||||
# Fix up include paths
|
||||
# In PlatformIO >=6.1.17, this could be done prior to ConfigureProjectLibBuilder
|
||||
wled_dir = xenv["PROJECT_SRC_DIR"]
|
||||
# Build a list of dependency include dirs
|
||||
# TODO: Find out if this is the order that PlatformIO/SCons puts them in??
|
||||
processed_deps = set()
|
||||
extra_include_dirs = deque() # Deque used for fast prepend
|
||||
for dep in result.depbuilders:
|
||||
cached_add_includes(dep, processed_deps, extra_include_dirs)
|
||||
|
||||
wled_deps = [dep for dep in result.depbuilders if is_wled_module(dep)]
|
||||
|
||||
broken_usermods = []
|
||||
for dep in wled_deps:
|
||||
# Add the wled folder to the include path
|
||||
dep.env.PrependUnique(CPPPATH=str(wled_dir))
|
||||
# Add WLED's own dependencies
|
||||
for dir in extra_include_dirs:
|
||||
dep.env.PrependUnique(CPPPATH=str(dir))
|
||||
# Enforce that libArchive is not set; we must link them directly to the executable
|
||||
if dep.lib_archive:
|
||||
broken_usermods.append(dep)
|
||||
|
||||
if broken_usermods:
|
||||
broken_usermods = [usermod.name for usermod in broken_usermods]
|
||||
secho(
|
||||
f"ERROR: libArchive=false is missing on usermod(s) {' '.join(broken_usermods)} -- modules will not compile in correctly",
|
||||
fg="red",
|
||||
err=True)
|
||||
Exit(1)
|
||||
|
||||
# Save the depbuilders list for later validation
|
||||
xenv.Replace(WLED_MODULES=wled_deps)
|
||||
|
||||
return result
|
||||
|
||||
# Apply the wrapper
|
||||
env.AddMethod(wrapped_ConfigureProjectLibBuilder, "ConfigureProjectLibBuilder")
|
||||
24
pio-scripts/obj-dump.py
Normal file
24
pio-scripts/obj-dump.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# Little convenience script to get an object dump
|
||||
# You may add "-S" to the objdump commandline (i.e. replace "-D -C " with "-d -S -C ")
|
||||
# to get source code intermixed with disassembly (SLOW !)
|
||||
|
||||
Import('env')
|
||||
|
||||
def obj_dump_after_elf(source, target, env):
|
||||
platform = env.PioPlatform()
|
||||
board = env.BoardConfig()
|
||||
mcu = board.get("build.mcu", "esp32")
|
||||
|
||||
print("Create firmware.asm")
|
||||
if mcu == "esp8266":
|
||||
env.Execute("xtensa-lx106-elf-objdump "+ "-D -C " + str(target[0]) + " > "+ "$BUILD_DIR/${PROGNAME}.asm")
|
||||
if mcu == "esp32":
|
||||
env.Execute("xtensa-esp32-elf-objdump "+ "-D -C " + str(target[0]) + " > "+ "$BUILD_DIR/${PROGNAME}.asm")
|
||||
if mcu == "esp32s2":
|
||||
env.Execute("xtensa-esp32s2-elf-objdump "+ "-D -C " + str(target[0]) + " > "+ "$BUILD_DIR/${PROGNAME}.asm")
|
||||
if mcu == "esp32s3":
|
||||
env.Execute("xtensa-esp32s3-elf-objdump "+ "-D -C " + str(target[0]) + " > "+ "$BUILD_DIR/${PROGNAME}.asm")
|
||||
if mcu == "esp32c3":
|
||||
env.Execute("riscv32-esp-elf-objdump "+ "-D -C " + str(target[0]) + " > "+ "$BUILD_DIR/${PROGNAME}.asm")
|
||||
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", [obj_dump_after_elf])
|
||||
66
pio-scripts/output_bins.py
Normal file
66
pio-scripts/output_bins.py
Normal file
@@ -0,0 +1,66 @@
|
||||
Import('env')
|
||||
import os
|
||||
import shutil
|
||||
import gzip
|
||||
|
||||
OUTPUT_DIR = "build_output{}".format(os.path.sep)
|
||||
#OUTPUT_DIR = os.path.join("build_output")
|
||||
|
||||
def _get_cpp_define_value(env, define):
|
||||
define_list = [item[-1] for item in env["CPPDEFINES"] if item[0] == define]
|
||||
|
||||
if define_list:
|
||||
return define_list[0]
|
||||
|
||||
return None
|
||||
|
||||
def _create_dirs(dirs=["map", "release", "firmware"]):
|
||||
for d in dirs:
|
||||
os.makedirs(os.path.join(OUTPUT_DIR, d), exist_ok=True)
|
||||
|
||||
def create_release(source):
|
||||
release_name_def = _get_cpp_define_value(env, "WLED_RELEASE_NAME")
|
||||
if release_name_def:
|
||||
release_name = release_name_def.replace("\\\"", "")
|
||||
version = _get_cpp_define_value(env, "WLED_VERSION")
|
||||
release_file = os.path.join(OUTPUT_DIR, "release", f"WLED_{version}_{release_name}.bin")
|
||||
release_gz_file = release_file + ".gz"
|
||||
print(f"Copying {source} to {release_file}")
|
||||
shutil.copy(source, release_file)
|
||||
bin_gzip(release_file, release_gz_file)
|
||||
else:
|
||||
variant = env["PIOENV"]
|
||||
bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant)
|
||||
print(f"Copying {source} to {bin_file}")
|
||||
shutil.copy(source, bin_file)
|
||||
|
||||
def bin_rename_copy(source, target, env):
|
||||
_create_dirs()
|
||||
variant = env["PIOENV"]
|
||||
builddir = os.path.join(env["PROJECT_BUILD_DIR"], variant)
|
||||
source_map = os.path.join(builddir, env["PROGNAME"] + ".map")
|
||||
|
||||
# create string with location and file names based on variant
|
||||
map_file = "{}map{}{}.map".format(OUTPUT_DIR, os.path.sep, variant)
|
||||
|
||||
create_release(str(target[0]))
|
||||
|
||||
# copy firmware.map to map/<variant>.map
|
||||
if os.path.isfile("firmware.map"):
|
||||
print("Found linker mapfile firmware.map")
|
||||
shutil.copy("firmware.map", map_file)
|
||||
if os.path.isfile(source_map):
|
||||
print(f"Found linker mapfile {source_map}")
|
||||
shutil.copy(source_map, map_file)
|
||||
|
||||
def bin_gzip(source, target):
|
||||
# only create gzip for esp8266
|
||||
if not env["PIOPLATFORM"] == "espressif8266":
|
||||
return
|
||||
|
||||
print(f"Creating gzip file {target} from {source}")
|
||||
with open(source,"rb") as fp:
|
||||
with gzip.open(target, "wb", compresslevel = 9) as f:
|
||||
shutil.copyfileobj(fp, f)
|
||||
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", bin_rename_copy)
|
||||
79
pio-scripts/set_repo.py
Normal file
79
pio-scripts/set_repo.py
Normal file
@@ -0,0 +1,79 @@
|
||||
Import('env')
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
def get_github_repo():
|
||||
"""Extract GitHub repository name from git remote URL.
|
||||
|
||||
Uses the remote that the current branch tracks, falling back to 'origin'.
|
||||
This handles cases where repositories have multiple remotes or where the
|
||||
main remote is not named 'origin'.
|
||||
|
||||
Returns:
|
||||
str: Repository name in 'owner/repo' format for GitHub repos,
|
||||
'unknown' for non-GitHub repos, missing git CLI, or any errors.
|
||||
"""
|
||||
try:
|
||||
remote_name = 'origin' # Default fallback
|
||||
|
||||
# Try to get the remote for the current branch
|
||||
try:
|
||||
# Get current branch name
|
||||
branch_result = subprocess.run(['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
|
||||
capture_output=True, text=True, check=True)
|
||||
current_branch = branch_result.stdout.strip()
|
||||
|
||||
# Get the remote for the current branch
|
||||
remote_result = subprocess.run(['git', 'config', f'branch.{current_branch}.remote'],
|
||||
capture_output=True, text=True, check=True)
|
||||
tracked_remote = remote_result.stdout.strip()
|
||||
|
||||
# Use the tracked remote if we found one
|
||||
if tracked_remote:
|
||||
remote_name = tracked_remote
|
||||
except subprocess.CalledProcessError:
|
||||
# If branch config lookup fails, continue with 'origin' as fallback
|
||||
pass
|
||||
|
||||
# Get the remote URL for the determined remote
|
||||
result = subprocess.run(['git', 'remote', 'get-url', remote_name],
|
||||
capture_output=True, text=True, check=True)
|
||||
remote_url = result.stdout.strip()
|
||||
|
||||
# Check if it's a GitHub URL
|
||||
if 'github.com' not in remote_url.lower():
|
||||
return 'unknown'
|
||||
|
||||
# Parse GitHub URL patterns:
|
||||
# https://github.com/owner/repo.git
|
||||
# git@github.com:owner/repo.git
|
||||
# https://github.com/owner/repo
|
||||
|
||||
# Remove .git suffix if present
|
||||
if remote_url.endswith('.git'):
|
||||
remote_url = remote_url[:-4]
|
||||
|
||||
# Handle HTTPS URLs
|
||||
https_match = re.search(r'github\.com/([^/]+/[^/]+)', remote_url, re.IGNORECASE)
|
||||
if https_match:
|
||||
return https_match.group(1)
|
||||
|
||||
# Handle SSH URLs
|
||||
ssh_match = re.search(r'github\.com:([^/]+/[^/]+)', remote_url, re.IGNORECASE)
|
||||
if ssh_match:
|
||||
return ssh_match.group(1)
|
||||
|
||||
return 'unknown'
|
||||
|
||||
except FileNotFoundError:
|
||||
# Git CLI is not installed or not in PATH
|
||||
return 'unknown'
|
||||
except subprocess.CalledProcessError:
|
||||
# Git command failed (e.g., not a git repo, no remote, etc.)
|
||||
return 'unknown'
|
||||
except Exception:
|
||||
# Any other unexpected error
|
||||
return 'unknown'
|
||||
|
||||
repo = get_github_repo()
|
||||
env.Append(BUILD_FLAGS=[f'-DWLED_REPO=\\"{repo}\\"'])
|
||||
8
pio-scripts/set_version.py
Normal file
8
pio-scripts/set_version.py
Normal file
@@ -0,0 +1,8 @@
|
||||
Import('env')
|
||||
import json
|
||||
|
||||
PACKAGE_FILE = "package.json"
|
||||
|
||||
with open(PACKAGE_FILE, "r") as package:
|
||||
version = json.load(package)["version"]
|
||||
env.Append(BUILD_FLAGS=[f"-DWLED_VERSION={version}"])
|
||||
15
pio-scripts/strip-floats.py
Normal file
15
pio-scripts/strip-floats.py
Normal file
@@ -0,0 +1,15 @@
|
||||
Import('env')
|
||||
|
||||
#
|
||||
# Dump build environment (for debug)
|
||||
#print env.Dump()
|
||||
#
|
||||
|
||||
flags = " ".join(env['LINKFLAGS'])
|
||||
flags = flags.replace("-u _printf_float", "")
|
||||
flags = flags.replace("-u _scanf_float", "")
|
||||
newflags = flags.split()
|
||||
|
||||
env.Replace(
|
||||
LINKFLAGS=newflags
|
||||
)
|
||||
9
pio-scripts/user_config_copy.py
Normal file
9
pio-scripts/user_config_copy.py
Normal file
@@ -0,0 +1,9 @@
|
||||
Import('env')
|
||||
import os
|
||||
import shutil
|
||||
|
||||
# copy WLED00/my_config_sample.h to WLED00/my_config.h
|
||||
if os.path.isfile("wled00/my_config.h"):
|
||||
print ("*** use existing my_config.h ***")
|
||||
else:
|
||||
shutil.copy("wled00/my_config_sample.h", "wled00/my_config.h")
|
||||
80
pio-scripts/validate_modules.py
Normal file
80
pio-scripts/validate_modules.py
Normal file
@@ -0,0 +1,80 @@
|
||||
import re
|
||||
from pathlib import Path # For OS-agnostic path manipulation
|
||||
from typing import Iterable
|
||||
from click import secho
|
||||
from SCons.Script import Action, Exit
|
||||
from platformio.builder.tools.piolib import LibBuilderBase
|
||||
|
||||
|
||||
def is_wled_module(env, dep: LibBuilderBase) -> bool:
|
||||
"""Returns true if the specified library is a wled module
|
||||
"""
|
||||
usermod_dir = Path(env["PROJECT_DIR"]).resolve() / "usermods"
|
||||
return usermod_dir in Path(dep.src_dir).parents or str(dep.name).startswith("wled-")
|
||||
|
||||
|
||||
def read_lines(p: Path):
|
||||
""" Read in the contents of a file for analysis """
|
||||
with p.open("r", encoding="utf-8", errors="ignore") as f:
|
||||
return f.readlines()
|
||||
|
||||
|
||||
def check_map_file_objects(map_file: list[str], dirs: Iterable[str]) -> set[str]:
|
||||
""" Identify which dirs contributed to the final build
|
||||
|
||||
Returns the (sub)set of dirs that are found in the output ELF
|
||||
"""
|
||||
# Pattern to match symbols in object directories
|
||||
# Join directories into alternation
|
||||
usermod_dir_regex = "|".join([re.escape(dir) for dir in dirs])
|
||||
# Matches nonzero address, any size, and any path in a matching directory
|
||||
object_path_regex = re.compile(r"0x0*[1-9a-f][0-9a-f]*\s+0x[0-9a-f]+\s+\S+[/\\](" + usermod_dir_regex + r")[/\\]\S+\.o")
|
||||
|
||||
found = set()
|
||||
for line in map_file:
|
||||
matches = object_path_regex.findall(line)
|
||||
for m in matches:
|
||||
found.add(m)
|
||||
return found
|
||||
|
||||
|
||||
def count_usermod_objects(map_file: list[str]) -> int:
|
||||
""" Returns the number of usermod objects in the usermod list """
|
||||
# Count the number of entries in the usermods table section
|
||||
return len([x for x in map_file if ".dtors.tbl.usermods.1" in x])
|
||||
|
||||
|
||||
def validate_map_file(source, target, env):
|
||||
""" Validate that all modules appear in the output build """
|
||||
build_dir = Path(env.subst("$BUILD_DIR"))
|
||||
map_file_path = build_dir / env.subst("${PROGNAME}.map")
|
||||
|
||||
if not map_file_path.exists():
|
||||
secho(f"ERROR: Map file not found: {map_file_path}", fg="red", err=True)
|
||||
Exit(1)
|
||||
|
||||
# Identify the WLED module builders, set by load_usermods.py
|
||||
module_lib_builders = env['WLED_MODULES']
|
||||
|
||||
# Extract the values we care about
|
||||
modules = {Path(builder.build_dir).name: builder.name for builder in module_lib_builders}
|
||||
secho(f"INFO: {len(modules)} libraries linked as WLED optional/user modules")
|
||||
|
||||
# Now parse the map file
|
||||
map_file_contents = read_lines(map_file_path)
|
||||
usermod_object_count = count_usermod_objects(map_file_contents)
|
||||
secho(f"INFO: {usermod_object_count} usermod object entries")
|
||||
|
||||
confirmed_modules = check_map_file_objects(map_file_contents, modules.keys())
|
||||
missing_modules = [modname for mdir, modname in modules.items() if mdir not in confirmed_modules]
|
||||
if missing_modules:
|
||||
secho(
|
||||
f"ERROR: No object files from {missing_modules} found in linked output!",
|
||||
fg="red",
|
||||
err=True)
|
||||
Exit(1)
|
||||
return None
|
||||
|
||||
Import("env")
|
||||
env.Append(LINKFLAGS=[env.subst("-Wl,--Map=${BUILD_DIR}/${PROGNAME}.map")])
|
||||
env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", Action(validate_map_file, cmdstr='Checking linked optional modules (usermods) in map file'))
|
||||
813
platformio.ini
813
platformio.ini
@@ -2,31 +2,96 @@
|
||||
; Please visit documentation: https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
# ------------------------------------------------------------------------------
|
||||
# ENVIRONMENTS
|
||||
#
|
||||
# Please uncomment one of the lines below to select your board(s)
|
||||
# (use `platformio_override.ini` when building for your own board; see `platformio_override.ini.sample` for an example)
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# CI/release binaries
|
||||
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover, usermods
|
||||
|
||||
src_dir = ./wled00
|
||||
data_dir = ./wled00/data
|
||||
;lib_extra_dirs = ./wled00/src
|
||||
lib_dir = ./wled00/src
|
||||
; Please uncomment one of the 5 lines below to select your board
|
||||
default_envs = nodemcuv2
|
||||
; default_envs = esp01
|
||||
; default_envs = esp01_1m
|
||||
; default_envs = esp07
|
||||
; default_envs = d1_mini
|
||||
; default_envs = esp32dev
|
||||
; default_envs = esp8285_4CH_MagicHome
|
||||
; default_envs = esp8285_4CH_H801
|
||||
; default_envs = esp8285_5CH_H801
|
||||
build_cache_dir = ~/.buildcache
|
||||
extra_configs =
|
||||
platformio_override.ini
|
||||
|
||||
[common]
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
board_build.flash_mode = dout
|
||||
upload_speed = 115200
|
||||
upload_speed_fast = 921600
|
||||
# ------------------------------------------------------------------------------
|
||||
# PLATFORM:
|
||||
# !! DO NOT confuse platformio's ESP8266 development platform with Arduino core for ESP8266
|
||||
#
|
||||
# arduino core 2.6.3 = platformIO 2.3.2
|
||||
# arduino core 2.7.0 = platformIO 2.5.0
|
||||
# ------------------------------------------------------------------------------
|
||||
arduino_core_2_6_3 = espressif8266@2.3.3
|
||||
arduino_core_2_7_4 = espressif8266@2.6.2
|
||||
arduino_core_3_0_0 = espressif8266@3.0.0
|
||||
arduino_core_3_0_2 = espressif8266@3.2.0
|
||||
arduino_core_3_1_0 = espressif8266@4.1.0
|
||||
arduino_core_3_1_2 = espressif8266@4.2.1
|
||||
|
||||
# Development platforms
|
||||
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
|
||||
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
|
||||
|
||||
# Platform to use for ESP8266
|
||||
platform_wled_default = ${common.arduino_core_3_1_2}
|
||||
# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
|
||||
#platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
|
||||
platform_packages = platformio/toolchain-xtensa @ ~2.100300.220621 #2.40802.200502
|
||||
platformio/tool-esptool #@ ~1.413.0
|
||||
platformio/tool-esptoolpy #@ ~1.30000.0
|
||||
|
||||
## previous platform for 8266, in case of problems with the new one
|
||||
## you'll need makuna/NeoPixelBus@ 2.6.9 for arduino_core_3_0_2, which does not support Ucs890x
|
||||
;; platform_wled_default = ${common.arduino_core_3_0_2}
|
||||
;; platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
|
||||
;; platformio/toolchain-xtensa @ ~2.40802.200502
|
||||
;; platformio/tool-esptool @ ~1.413.0
|
||||
;; platformio/tool-esptoolpy @ ~1.30000.0
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# FLAGS: DEBUG
|
||||
# esp8266 : see https://docs.platformio.org/en/latest/platforms/espressif8266.html#debug-level
|
||||
# esp32 : see https://docs.platformio.org/en/latest/platforms/espressif32.html#debug-level
|
||||
# ------------------------------------------------------------------------------
|
||||
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 ;; for esp8266
|
||||
# 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 (available ldscripts at https://github.com/esp8266/Arduino/tree/master/tools/sdk/ld)
|
||||
# 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?
|
||||
#
|
||||
# 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
|
||||
# -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
||||
#
|
||||
# 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 =
|
||||
-w ; supresses all C/C++ warnings
|
||||
; -D VERSION=0.8.5
|
||||
; -D DEBUG
|
||||
-DMQTT_MAX_PACKET_SIZE=1024
|
||||
-DSECURE_CLIENT=SECURE_CLIENT_BEARSSL
|
||||
-DBEARSSL_SSL_BASIC
|
||||
-D CORE_DEBUG_LEVEL=0
|
||||
-D NDEBUG
|
||||
-Wno-attributes ;; silence warnings about unknown attribute 'maybe_unused' in NeoPixelBus
|
||||
#build_flags for the IRremoteESP8266 library (enabled decoders have to appear here)
|
||||
-D _IR_ENABLE_DEFAULT_=false
|
||||
-D DECODE_HASH=true
|
||||
@@ -34,231 +99,529 @@ build_flags =
|
||||
-D DECODE_SONY=true
|
||||
-D DECODE_SAMSUNG=true
|
||||
-D DECODE_LG=true
|
||||
-DWLED_USE_MY_CONFIG
|
||||
|
||||
build_unflags =
|
||||
|
||||
ldscript_1m128k = eagle.flash.1m128.ld
|
||||
ldscript_2m512k = eagle.flash.2m512.ld
|
||||
ldscript_2m1m = eagle.flash.2m1m.ld
|
||||
ldscript_4m1m = eagle.flash.4m1m.ld
|
||||
|
||||
[scripts_defaults]
|
||||
extra_scripts =
|
||||
pre:pio-scripts/set_version.py
|
||||
pre:pio-scripts/set_repo.py
|
||||
post:pio-scripts/output_bins.py
|
||||
post:pio-scripts/strip-floats.py
|
||||
pre:pio-scripts/user_config_copy.py
|
||||
pre:pio-scripts/load_usermods.py
|
||||
pre:pio-scripts/build_ui.py
|
||||
post:pio-scripts/validate_modules.py ;; double-check the build output usermods
|
||||
; post:pio-scripts/obj-dump.py ;; convenience script to create a disassembly dump of the firmware (hardcore debugging)
|
||||
|
||||
# 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(changed)
|
||||
#E131@1.0.0(changed)
|
||||
FastLED@3.3.2
|
||||
NeoPixelBus@2.5.6
|
||||
ESPAsyncTCP@1.2.0
|
||||
ESPAsyncUDP@697c75a025
|
||||
AsyncTCP@1.0.3
|
||||
Esp Async WebServer@1.2.0
|
||||
#ArduinoJson@5.13.5
|
||||
#IRremoteESP8266@2.7.2
|
||||
https://github.com/crankyoldgit/IRremoteESP8266.git
|
||||
#Time@1.5
|
||||
#Timezone@1.2.1
|
||||
#For use SSD1306 OLED display uncomment following
|
||||
#U8g2@~2.27.2
|
||||
#For Dallas sensor uncomment following 2 lines
|
||||
#DallasTemperature@~3.8.0
|
||||
#OneWire@~2.3.5
|
||||
[common:esp8266]
|
||||
# ------------------------------------------------------------------------------
|
||||
# PLATFORM:
|
||||
# !! DO NOT confuse platformio's ESP8266 development platform with Arduino core for ESP8266
|
||||
# We use Arduino Core 2.5.0 (platformIO 2.0.4) as default
|
||||
# COMMON SETTINGS:
|
||||
# ------------------------------------------------------------------------------
|
||||
[env]
|
||||
framework = arduino
|
||||
board_build.flash_mode = dout
|
||||
monitor_speed = 115200
|
||||
# slow upload speed but most compatible (use platformio_override.ini to use faster speed)
|
||||
upload_speed = 115200
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# LIBRARIES: required dependencies
|
||||
# Please note that we don't always use the latest version of a library.
|
||||
#
|
||||
# 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 stage = platformIO feature#stage
|
||||
# The following libraries have been included (and some of them changed) in the source:
|
||||
# ArduinoJson@5.13.5, E131@1.0.0(changed), Time@1.5, Timezone@1.2.1
|
||||
# ------------------------------------------------------------------------------
|
||||
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_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
|
||||
arduino_core_stage = https://github.com/platformio/platform-espressif8266.git#feature/stage
|
||||
platform = ${common:esp8266.arduino_core_2_6_3}
|
||||
build_flags =
|
||||
-D ESP8266
|
||||
-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH
|
||||
-Wl,-Teagle.flash.4m1m.ld ;;;; Required for core > v2.5.0 or staging version 4MB Flash 3MB SPIFFs
|
||||
lib_ignore = AsyncTCP
|
||||
lib_compat_mode = strict
|
||||
lib_deps =
|
||||
fastled/FastLED @ 3.6.0
|
||||
IRremoteESP8266 @ 2.8.2
|
||||
makuna/NeoPixelBus @ 2.8.3
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.2
|
||||
marvinroger/AsyncMqttClient @ 0.9.0
|
||||
# for I2C interface
|
||||
;Wire
|
||||
# ESP-NOW library
|
||||
;gmag11/QuickESPNow @ ~0.7.0
|
||||
https://github.com/blazoncek/QuickESPNow.git#optional-debug
|
||||
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
|
||||
#TFT_eSPI
|
||||
#For compatible OLED display uncomment following
|
||||
#olikraus/U8g2 #@ ~2.33.15
|
||||
#For Dallas sensor uncomment following
|
||||
#paulstoffregen/OneWire @ ~2.3.8
|
||||
#For BME280 sensor uncomment following
|
||||
#BME280 @ ~3.0.0
|
||||
;adafruit/Adafruit BMP280 Library @ 2.1.0
|
||||
;adafruit/Adafruit CCS811 Library @ 1.0.4
|
||||
;adafruit/Adafruit Si7021 Library @ 1.4.0
|
||||
#For MAX1704x Lipo Monitor / Fuel Gauge uncomment following
|
||||
; https://github.com/adafruit/Adafruit_BusIO @ 1.14.5
|
||||
; https://github.com/adafruit/Adafruit_MAX1704X @ 1.0.2
|
||||
#For MPU6050 IMU uncomment follwoing
|
||||
;electroniccats/MPU6050 @1.0.1
|
||||
# SHT85
|
||||
;robtillaart/SHT85@~0.3.3
|
||||
|
||||
[common:esp8266_1M]
|
||||
platform = espressif8266@1.8.0
|
||||
build_flags =
|
||||
-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
||||
-Wl,-Teagle.flash.1m0.ld ;;;; Compile with no SPIFFS to leave space for OTA
|
||||
; -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
|
||||
lib_ignore = ${common:esp8266.lib_ignore}
|
||||
extra_scripts = ${scripts_defaults.extra_scripts}
|
||||
|
||||
[common:esp8266_512k]
|
||||
platform = espressif8266@1.8.0
|
||||
[esp8266]
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags =
|
||||
-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
||||
-Wl,-Teagle.flash.512k0.ld ;;;; Compile with no SPIFFS
|
||||
; -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
|
||||
lib_ignore = ${common:esp8266.lib_ignore}
|
||||
-DESP8266
|
||||
-DFP_IN_IROM
|
||||
;-Wno-deprecated-declarations
|
||||
;-Wno-register ;; leaves some warnings when compiling C files: command-line option '-Wno-register' is valid for C++/ObjC++ but not for C
|
||||
;-Dregister= # remove warnings in C++17 due to use of deprecated register keyword by the FastLED library ;; warning: this can be dangerous
|
||||
-Wno-misleading-indentation
|
||||
; NONOSDK22x_190703 = 2.2.2-dev(38a443e)
|
||||
-DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
|
||||
; lwIP 2 - Higher Bandwidth no Features
|
||||
; -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
||||
; lwIP 1.4 - Higher Bandwidth (Aircoookie has)
|
||||
-DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
|
||||
; VTABLES in Flash
|
||||
-DVTABLES_IN_FLASH
|
||||
; restrict to minimal mime-types
|
||||
-DMIMETYPE_MINIMAL
|
||||
; other special-purpose framework flags (see https://docs.platformio.org/en/latest/platforms/espressif8266.html)
|
||||
; decrease code cache size and increase IRAM to fit all pixel functions
|
||||
-D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;; in case of linker errors like "section `.text1' will not fit in region `iram1_0_seg'"
|
||||
; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED ;; (experimental) adds some extra heap, but may cause slowdown
|
||||
-D NON32XFER_HANDLER ;; ask forgiveness for PROGMEM misuse
|
||||
|
||||
[common:esp32]
|
||||
platform = espressif32@1.11.2
|
||||
build_flags =
|
||||
-D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH
|
||||
-D ARDUINO_ARCH_ESP32
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
lib_deps =
|
||||
#https://github.com/lorol/LITTLEFS.git
|
||||
ESPAsyncTCP @ 1.2.2
|
||||
ESPAsyncUDP
|
||||
ESP8266PWM
|
||||
${env.lib_deps}
|
||||
|
||||
;; compatibilty flags - same as 0.14.0 which seems to work better on some 8266 boards. Not using PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48
|
||||
build_flags_compat =
|
||||
-DESP8266
|
||||
-DFP_IN_IROM
|
||||
;;-Wno-deprecated-declarations
|
||||
-Wno-misleading-indentation
|
||||
;;-Wno-attributes ;; silence warnings about unknown attribute 'maybe_unused' in NeoPixelBus
|
||||
-DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
|
||||
-DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
|
||||
-DVTABLES_IN_FLASH
|
||||
-DMIMETYPE_MINIMAL
|
||||
-DWLED_SAVE_IRAM ;; needed to prevent linker error
|
||||
|
||||
;; this platform version was used for WLED 0.14.0
|
||||
platform_compat = espressif8266@4.2.0
|
||||
platform_packages_compat =
|
||||
platformio/toolchain-xtensa @ ~2.100300.220621 #2.40802.200502
|
||||
platformio/tool-esptool #@ ~1.413.0
|
||||
platformio/tool-esptoolpy #@ ~1.30000.0
|
||||
|
||||
;; experimental - for using older NeoPixelBus 2.7.9
|
||||
lib_deps_compat =
|
||||
ESPAsyncTCP @ 1.2.2
|
||||
ESPAsyncUDP
|
||||
ESP8266PWM
|
||||
fastled/FastLED @ 3.6.0
|
||||
IRremoteESP8266 @ 2.8.2
|
||||
makuna/NeoPixelBus @ 2.7.9
|
||||
https://github.com/blazoncek/QuickESPNow.git#optional-debug
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.0
|
||||
|
||||
[esp32_all_variants]
|
||||
lib_deps =
|
||||
esp32async/AsyncTCP @ 3.4.7
|
||||
bitbank2/AnimatedGIF@^1.4.7
|
||||
https://github.com/Aircoookie/GifDecoder#bc3af18
|
||||
build_flags =
|
||||
-D CONFIG_ASYNC_TCP_USE_WDT=0
|
||||
-D CONFIG_ASYNC_TCP_STACK_SIZE=8192
|
||||
-D WLED_ENABLE_GIF
|
||||
|
||||
[esp32]
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages =
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${esp32_idf_V4.build_flags}
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
|
||||
tiny_partitions = tools/WLED_ESP32_2MB_noOTA.csv
|
||||
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
|
||||
extended_partitions = tools/WLED_ESP32_4MB_700k_FS.csv
|
||||
big_partitions = tools/WLED_ESP32_4MB_256KB_FS.csv ;; 1.8MB firmware, 256KB filesystem, coredump support
|
||||
large_partitions = tools/WLED_ESP32_8MB.csv
|
||||
extreme_partitions = tools/WLED_ESP32_16MB_9MB_FS.csv
|
||||
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
# additional build flags for audioreactive - must be applied globally
|
||||
AR_build_flags = ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster)
|
||||
AR_lib_deps = ;; for pre-usermod-library platformio_override compatibility
|
||||
|
||||
|
||||
[esp32_idf_V4]
|
||||
;; build environment for ESP32 using ESP-IDF 4.4.x / arduino-esp32 v2.0.5
|
||||
;;
|
||||
;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly.
|
||||
;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio.
|
||||
|
||||
;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.06.02/platform-espressif32.zip ;; Tasmota Arduino Core 2.0.9 with IPv6 support, based on IDF 4.4.4
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one
|
||||
-DARDUINO_ARCH_ESP32 -DESP32
|
||||
${esp32_all_variants.build_flags}
|
||||
-D WLED_ENABLE_DMX_INPUT
|
||||
lib_deps =
|
||||
${esp32_all_variants.lib_deps}
|
||||
https://github.com/someweisguy/esp_dmx.git#47db25d
|
||||
${env.lib_deps}
|
||||
|
||||
[esp32s2]
|
||||
;; generic definitions for all ESP32-S2 boards
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_ARCH_ESP32S2
|
||||
-DCONFIG_IDF_TARGET_ESP32S2=1
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0
|
||||
-DCO
|
||||
-DARDUINO_USB_MODE=0 ;; this flag is mandatory for ESP32-S2 !
|
||||
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
|
||||
;; ARDUINO_USB_CDC_ON_BOOT
|
||||
${esp32_idf_V4.build_flags}
|
||||
lib_deps =
|
||||
${esp32_idf_V4.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
|
||||
[esp32c3]
|
||||
;; generic definitions for all ESP32-C3 boards
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_ARCH_ESP32C3
|
||||
-DCONFIG_IDF_TARGET_ESP32C3=1
|
||||
-DCO
|
||||
-DARDUINO_USB_MODE=1 ;; this flag is mandatory for ESP32-C3
|
||||
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
|
||||
;; ARDUINO_USB_CDC_ON_BOOT
|
||||
${esp32_idf_V4.build_flags}
|
||||
lib_deps =
|
||||
${esp32_idf_V4.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
|
||||
board_build.flash_mode = qio
|
||||
|
||||
[esp32s3]
|
||||
;; generic definitions for all ESP32-S3 boards
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = -g
|
||||
-DESP32
|
||||
-DARDUINO_ARCH_ESP32
|
||||
-DARDUINO_ARCH_ESP32S3
|
||||
-DCONFIG_IDF_TARGET_ESP32S3=1
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_DFU_ON_BOOT=0
|
||||
-DCO
|
||||
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
|
||||
;; ARDUINO_USB_MODE, ARDUINO_USB_CDC_ON_BOOT
|
||||
${esp32_idf_V4.build_flags}
|
||||
lib_deps =
|
||||
${esp32_idf_V4.lib_deps}
|
||||
board_build.partitions = ${esp32.large_partitions} ;; default partioning for 8MB flash - can be overridden in build envs
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# WLED BUILDS
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# 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}
|
||||
lib_compat_mode = strict
|
||||
lib_ignore = ${common:esp8266.lib_ignore}
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266\" #-DWLED_DISABLE_2D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
monitor_filters = esp8266_exception_decoder
|
||||
|
||||
[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}
|
||||
lib_compat_mode = strict
|
||||
lib_ignore = ${common:esp8266.lib_ignore}
|
||||
[env:nodemcuv2_compat]
|
||||
extends = env:nodemcuv2
|
||||
;; using platform version and build options from WLED 0.14.0
|
||||
platform = ${esp8266.platform_compat}
|
||||
platform_packages = ${esp8266.platform_packages_compat}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP8266_compat\" #-DWLED_DISABLE_2D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
;; lib_deps = ${esp8266.lib_deps_compat} ;; experimental - use older NeoPixelBus 2.7.9
|
||||
|
||||
[env:esp01_1m]
|
||||
[env:nodemcuv2_160]
|
||||
extends = env:nodemcuv2
|
||||
board_build.f_cpu = 160000000L
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266_160\" #-DWLED_DISABLE_2D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
custom_usermods = audioreactive
|
||||
|
||||
[env:esp8266_2m]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02\"
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM1D
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:esp8266_2m_compat]
|
||||
extends = env:esp8266_2m
|
||||
;; using platform version and build options from WLED 0.14.0
|
||||
platform = ${esp8266.platform_compat}
|
||||
platform_packages = ${esp8266.platform_packages_compat}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP02_compat\" #-DWLED_DISABLE_2D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM1D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
|
||||
[env:esp8266_2m_160]
|
||||
extends = env:esp8266_2m
|
||||
board_build.f_cpu = 160000000L
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02_160\"
|
||||
-D WLED_DISABLE_PARTICLESYSTEM1D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
custom_usermods = audioreactive
|
||||
|
||||
[env:esp01_1m_full]
|
||||
board = esp01_1m
|
||||
platform = ${common:esp8266_1M.platform}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
upload_speed = ${common.upload_speed}
|
||||
framework = ${common.framework}
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
${common:esp8266_1M.build_flags}
|
||||
# disable IR because there is no pin for it
|
||||
-D WLED_DISABLE_INFRARED
|
||||
lib_deps =
|
||||
${common.lib_deps_external}
|
||||
lib_compat_mode = strict
|
||||
lib_ignore = ${common:esp8266.lib_ignore}
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01\" -D WLED_DISABLE_OTA
|
||||
; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM
|
||||
-D WLED_DISABLE_PARTICLESYSTEM1D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[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}
|
||||
-D WLED_DISABLE_INFRARED
|
||||
lib_deps =
|
||||
${common.lib_deps_external}
|
||||
lib_compat_mode = strict
|
||||
lib_ignore = ${common:esp8266.lib_ignore}
|
||||
[env:esp01_1m_full_compat]
|
||||
extends = env:esp01_1m_full
|
||||
;; using platform version and build options from WLED 0.14.0
|
||||
platform = ${esp8266.platform_compat}
|
||||
platform_packages = ${esp8266.platform_packages_compat}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP01_compat\" -D WLED_DISABLE_OTA #-DWLED_DISABLE_2D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM1D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
|
||||
[env:esp07]
|
||||
board = esp07
|
||||
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}
|
||||
lib_compat_mode = strict
|
||||
lib_ignore = ${common:esp8266.lib_ignore}
|
||||
[env:esp01_1m_full_160]
|
||||
extends = env:esp01_1m_full
|
||||
board_build.f_cpu = 160000000L
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01_160\" -D WLED_DISABLE_OTA
|
||||
; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM
|
||||
-D WLED_DISABLE_PARTICLESYSTEM1D
|
||||
-D WLED_DISABLE_PARTICLESYSTEM2D
|
||||
custom_usermods = audioreactive
|
||||
|
||||
# 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_fast}
|
||||
framework = ${common.framework}
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
${common:esp32.build_flags}
|
||||
lib_deps =
|
||||
${common.lib_deps_external}
|
||||
lib_ignore = ${common:esp32.lib_ignore}
|
||||
lib_compat_mode = strict
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
build_unflags = ${common.build_unflags}
|
||||
custom_usermods = audioreactive
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_V4\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
-DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.flash_mode = dio
|
||||
|
||||
[env:esp8285_4CH_MagicHome]
|
||||
board = esp8285
|
||||
platform = ${common:esp8266_1M.platform}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
upload_speed = ${common.upload_speed}
|
||||
framework = ${common.framework}
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
${common:esp8266_1M.build_flags}
|
||||
-D WLED_DISABLE_HUESYNC
|
||||
-D WLED_USE_ANALOG_LEDS
|
||||
lib_deps =
|
||||
${common.lib_deps_external}
|
||||
lib_compat_mode = strict
|
||||
lib_ignore = ${common:esp8266.lib_ignore}
|
||||
[env:esp32dev_8M]
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.large_partitions}
|
||||
board_upload.flash_size = 8MB
|
||||
board_upload.maximum_size = 8388608
|
||||
; board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = dio
|
||||
|
||||
[env:esp8285_4CH_H801]
|
||||
board = esp8285
|
||||
platform = ${common:esp8266_1M.platform}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
upload_speed = ${common.upload_speed}
|
||||
framework = ${common.framework}
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
${common:esp8266_1M.build_flags}
|
||||
-D WLED_DISABLE_HUESYNC
|
||||
-D WLED_USE_ANALOG_LEDS
|
||||
-D WLED_USE_H801
|
||||
lib_deps =
|
||||
${common.lib_deps_external}
|
||||
lib_compat_mode = strict
|
||||
lib_ignore = ${common:esp8266.lib_ignore}
|
||||
[env:esp32dev_16M]
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.extreme_partitions}
|
||||
board_upload.flash_size = 16MB
|
||||
board_upload.maximum_size = 16777216
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = dio
|
||||
|
||||
[env:esp8285_5CH_H801]
|
||||
board = esp8285
|
||||
platform = ${common:esp8266_1M.platform}
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
upload_speed = ${common.upload_speed}
|
||||
framework = ${common.framework}
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
${common:esp8266_1M.build_flags}
|
||||
-D WLED_DISABLE_HUESYNC
|
||||
-D WLED_USE_ANALOG_LEDS
|
||||
-D WLED_USE_H801
|
||||
-D WLED_ENABLE_5CH_LEDS
|
||||
lib_deps =
|
||||
${common.lib_deps_external}
|
||||
lib_compat_mode = strict
|
||||
lib_ignore = ${common:esp8266.lib_ignore}
|
||||
[env:esp32_eth]
|
||||
board = esp32-poe
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
upload_speed = 921600
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_Ethernet\" -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1
|
||||
; -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.flash_mode = dio
|
||||
|
||||
[env:esp32_wrover]
|
||||
extends = esp32_idf_V4
|
||||
board = ttgo-t7-v14-mini32
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
board_build.partitions = ${esp32.extended_partitions}
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_WROVER\"
|
||||
-DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html
|
||||
-D DATA_PINS=25
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
|
||||
[env:esp32c3dev]
|
||||
extends = esp32c3
|
||||
platform = ${esp32c3.platform}
|
||||
framework = arduino
|
||||
board = esp32-c3-devkitm-1
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-C3\"
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
|
||||
;-DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
|
||||
upload_speed = 460800
|
||||
build_unflags = ${common.build_unflags}
|
||||
lib_deps = ${esp32c3.lib_deps}
|
||||
|
||||
[env:esp32s3dev_16MB_opi]
|
||||
;; ESP32-S3 development board, with 16MB FLASH and >= 8MB PSRAM (memory_type: qio_opi)
|
||||
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
|
||||
board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
|
||||
platform = ${esp32s3.platform}
|
||||
upload_speed = 921600
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_16MB_opi\"
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
board_build.partitions = ${esp32.extreme_partitions}
|
||||
board_upload.flash_size = 16MB
|
||||
board_upload.maximum_size = 16777216
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:esp32s3dev_8MB_opi]
|
||||
;; ESP32-S3 development board, with 8MB FLASH and >= 8MB PSRAM (memory_type: qio_opi)
|
||||
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
|
||||
board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB
|
||||
platform = ${esp32s3.platform}
|
||||
upload_speed = 921600
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_8MB_opi\"
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
board_build.partitions = ${esp32.large_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:esp32S3_wroom2]
|
||||
;; For ESP32-S3 WROOM-2, a.k.a. ESP32-S3 DevKitC-1 v1.1
|
||||
;; with >= 16MB FLASH and >= 8MB PSRAM (memory_type: opi_opi)
|
||||
platform = ${esp32s3.platform}
|
||||
board = esp32s3camlcd ;; this is the only standard board with "opi_opi"
|
||||
board_build.arduino.memory_type = opi_opi
|
||||
upload_speed = 921600
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_WROOM-2\"
|
||||
-D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip
|
||||
;; -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
-D LEDPIN=38 -D DATA_PINS=38 ;; buildin WS2812b LED
|
||||
-D BTNPIN=0 -D RLYPIN=16 -D IRPIN=17 -D AUDIOPIN=-1
|
||||
-D WLED_DEBUG
|
||||
-D SR_DMTYPE=1 -D I2S_SDPIN=13 -D I2S_CKPIN=14 -D I2S_WSPIN=15 -D MCLK_PIN=4 ;; I2S mic
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
|
||||
board_build.partitions = ${esp32.extreme_partitions}
|
||||
board_upload.flash_size = 16MB
|
||||
board_upload.maximum_size = 16777216
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:esp32s3_4M_qspi]
|
||||
;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi)
|
||||
board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM
|
||||
platform = ${esp32s3.platform}
|
||||
upload_speed = 921600
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\"
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:lolin_s2_mini]
|
||||
platform = ${esp32s2.platform}
|
||||
board = lolin_s2_mini
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.flash_mode = qio
|
||||
board_build.f_flash = 80000000L
|
||||
custom_usermods = audioreactive
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S2\"
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0
|
||||
-DARDUINO_USB_DFU_ON_BOOT=0
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D DATA_PINS=16
|
||||
-D HW_PIN_SCL=35
|
||||
-D HW_PIN_SDA=33
|
||||
-D HW_PIN_CLOCKSPI=7
|
||||
-D HW_PIN_DATASPI=11
|
||||
-D HW_PIN_MISOSPI=9
|
||||
; -D STATUSLED=15
|
||||
lib_deps = ${esp32s2.lib_deps}
|
||||
|
||||
|
||||
[env:usermods]
|
||||
board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_USERMODS\"
|
||||
-DTOUCH_CS=9
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.flash_mode = dio
|
||||
custom_usermods = * ; Expands to all usermods in usermods folder
|
||||
board_build.partitions = ${esp32.extreme_partitions} ; We're gonna need a bigger boat
|
||||
|
||||
611
platformio_override.sample.ini
Normal file
611
platformio_override.sample.ini
Normal file
@@ -0,0 +1,611 @@
|
||||
# Example PlatformIO Project Configuration Override
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copy to platformio_override.ini to activate overrides
|
||||
# ------------------------------------------------------------------------------
|
||||
# Please visit documentation: https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
default_envs = WLED_generic8266_1M, esp32dev_V4_dio80 # put the name(s) of your own build environment here. You can define as many as you need
|
||||
|
||||
#----------
|
||||
# SAMPLE
|
||||
#----------
|
||||
[env:WLED_generic8266_1M]
|
||||
extends = env:esp01_1m_full # when you want to extend the existing environment (define only updated options)
|
||||
; board = esp01_1m # uncomment when ou need different board
|
||||
; platform = ${common.platform_wled_default} # uncomment and change when you want particular platform
|
||||
; platform_packages = ${common.platform_packages}
|
||||
; board_build.ldscript = ${common.ldscript_1m128k}
|
||||
; upload_speed = 921600 # fast upload speed (remove ';' if your board supports fast upload speed)
|
||||
# Sample libraries used for various usermods. Uncomment when using particular usermod.
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
; olikraus/U8g2 # @~2.33.15
|
||||
; paulstoffregen/OneWire@~2.3.8
|
||||
; adafruit/Adafruit Unified Sensor@^1.1.4
|
||||
; adafruit/DHT sensor library@^1.4.1
|
||||
; adafruit/Adafruit BME280 Library@^2.2.2
|
||||
; Wire
|
||||
; robtillaart/SHT85@~0.3.3
|
||||
; ;gmag11/QuickESPNow @ ~0.7.0 # will also load QuickDebug
|
||||
; https://github.com/blazoncek/QuickESPNow.git#optional-debug ;; exludes debug library
|
||||
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
;
|
||||
; *** To use the below defines/overrides, copy and paste each onto its own line just below build_flags in the section above.
|
||||
;
|
||||
; Set a release name that may be used to distinguish required binary for flashing
|
||||
; -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\"
|
||||
;
|
||||
; disable specific features
|
||||
; -D WLED_DISABLE_OTA
|
||||
; -D WLED_DISABLE_ALEXA
|
||||
; -D WLED_DISABLE_HUESYNC
|
||||
; -D WLED_DISABLE_LOXONE
|
||||
; -D WLED_DISABLE_INFRARED
|
||||
; -D WLED_DISABLE_WEBSOCKETS
|
||||
; -D WLED_DISABLE_MQTT
|
||||
; -D WLED_DISABLE_ADALIGHT
|
||||
; -D WLED_DISABLE_2D
|
||||
; -D WLED_DISABLE_PXMAGIC
|
||||
; -D WLED_DISABLE_ESPNOW
|
||||
; -D WLED_DISABLE_BROWNOUT_DET
|
||||
;
|
||||
; enable optional built-in features
|
||||
; -D WLED_ENABLE_PIXART
|
||||
; -D WLED_ENABLE_USERMOD_PAGE # if created
|
||||
; -D WLED_ENABLE_DMX
|
||||
;
|
||||
; PIN defines - uncomment and change, if needed:
|
||||
; -D DATA_PINS=2
|
||||
; or use this for multiple outputs
|
||||
; -D DATA_PINS=1,3
|
||||
; -D BTNPIN=0
|
||||
; -D IRPIN=4
|
||||
; -D RLYPIN=12
|
||||
; -D RLYMDE=1
|
||||
; -D RLYODRAIN=0
|
||||
; -D LED_BUILTIN=2 # GPIO of built-in LED
|
||||
;
|
||||
; Limit max buses
|
||||
; -D WLED_MAX_BUSSES=2
|
||||
; -D WLED_MAX_ANALOG_CHANNELS=3 # only 3 PWM HW pins available
|
||||
; -D WLED_MAX_DIGITAL_CHANNELS=2 # only 2 HW accelerated pins available
|
||||
;
|
||||
; Configure default WiFi
|
||||
; -D CLIENT_SSID='"MyNetwork"'
|
||||
; -D CLIENT_PASS='"Netw0rkPassw0rd"'
|
||||
;
|
||||
; Configure and use Ethernet
|
||||
; -D WLED_USE_ETHERNET
|
||||
; -D WLED_ETH_DEFAULT=5
|
||||
; do not use pins 5, (16,) 17, 18, 19, 21, 22, 23, 25, 26, 27 for anything but ethernet
|
||||
; -D PHY_ADDR=0 -D ETH_PHY_POWER=5 -D ETH_PHY_MDC=23 -D ETH_PHY_MDIO=18
|
||||
; -D ETH_CLK_MODE=ETH_CLOCK_GPIO17_OUT
|
||||
;
|
||||
; NTP time configuration
|
||||
; -D WLED_NTP_ENABLED=true
|
||||
; -D WLED_TIMEZONE=2
|
||||
; -D WLED_LAT=48.86
|
||||
; -D WLED_LON=2.33
|
||||
;
|
||||
; Use Watchdog timer with 10s guard
|
||||
; -D WLED_WATCHDOG_TIMEOUT=10
|
||||
;
|
||||
; Create debug build (with remote debug)
|
||||
; -D WLED_DEBUG
|
||||
; -D WLED_DEBUG_HOST='"192.168.0.100"'
|
||||
; -D WLED_DEBUG_PORT=7868
|
||||
;
|
||||
; Use Autosave usermod and set it to do save after 90s
|
||||
; -D USERMOD_AUTO_SAVE
|
||||
; -D AUTOSAVE_AFTER_SEC=90
|
||||
;
|
||||
; Use AHT10/AHT15/AHT20 usermod
|
||||
; -D USERMOD_AHT10
|
||||
;
|
||||
; Use INA226 usermod
|
||||
; -D USERMOD_INA226
|
||||
;
|
||||
; Use 4 Line Display usermod with SPI display
|
||||
; -D USERMOD_FOUR_LINE_DISPLAY
|
||||
; -DFLD_SPI_DEFAULT
|
||||
; -D FLD_TYPE=SSD1306_SPI64
|
||||
; -D FLD_PIN_CLOCKSPI=14
|
||||
; -D FLD_PIN_DATASPI=13
|
||||
; -D FLD_PIN_DC=26
|
||||
; -D FLD_PIN_CS=15
|
||||
; -D FLD_PIN_RESET=27
|
||||
;
|
||||
; Use Rotary encoder usermod (in conjunction with 4LD)
|
||||
; -D USERMOD_ROTARY_ENCODER_UI
|
||||
; -D ENCODER_DT_PIN=5
|
||||
; -D ENCODER_CLK_PIN=18
|
||||
; -D ENCODER_SW_PIN=19
|
||||
;
|
||||
; Use Dallas DS18B20 temperature sensor usermod and configure it to use GPIO13
|
||||
; -D USERMOD_DALLASTEMPERATURE
|
||||
; -D TEMPERATURE_PIN=13
|
||||
;
|
||||
; Use Multi Relay usermod and configure it to use 6 relays and appropriate GPIO
|
||||
; -D USERMOD_MULTI_RELAY
|
||||
; -D MULTI_RELAY_MAX_RELAYS=6
|
||||
; -D MULTI_RELAY_PINS=12,23,22,21,24,25
|
||||
;
|
||||
; Use PIR sensor usermod and configure it to use GPIO4 and timer of 60s
|
||||
; -D USERMOD_PIRSWITCH
|
||||
; -D PIR_SENSOR_PIN=4 # use -1 to disable usermod
|
||||
; -D PIR_SENSOR_OFF_SEC=60
|
||||
; -D PIR_SENSOR_MAX_SENSORS=2 # max allowable sensors (uses OR logic for triggering)
|
||||
;
|
||||
; Use Audioreactive usermod and configure I2S microphone
|
||||
; -D AUDIOPIN=-1
|
||||
; -D DMTYPE=1 # 0-analog/disabled, 1-I2S generic, 2-ES7243, 3-SPH0645, 4-I2S+mclk, 5-I2S PDM
|
||||
; -D I2S_SDPIN=36
|
||||
; -D I2S_WSPIN=23
|
||||
; -D I2S_CKPIN=19
|
||||
;
|
||||
; Use PWM fan usermod
|
||||
; -D USERMOD_PWM_FAN
|
||||
; -D TACHO_PIN=33
|
||||
; -D PWM_PIN=32
|
||||
;
|
||||
; Use POV Display usermod
|
||||
; -D USERMOD_POV_DISPLAY
|
||||
; Use built-in or custom LED as a status indicator (assumes LED is connected to GPIO16)
|
||||
; -D STATUSLED=16
|
||||
;
|
||||
; set the name of the module - make sure there is a quote-backslash-quote before the name and a backslash-quote-quote after the name
|
||||
; -D SERVERNAME="\"WLED\""
|
||||
;
|
||||
; set the number of LEDs
|
||||
; -D PIXEL_COUNTS=30
|
||||
; or this for multiple outputs
|
||||
; -D PIXEL_COUNTS=30,30
|
||||
;
|
||||
; set the default LED type
|
||||
; -D LED_TYPES=22 # see const.h (TYPE_xxxx)
|
||||
; or this for multiple outputs
|
||||
; -D LED_TYPES=TYPE_SK6812_RGBW,TYPE_WS2812_RGB
|
||||
;
|
||||
; set default color order of your led strip
|
||||
; -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB
|
||||
;
|
||||
; set milliampere limit when using ESP power pin (or inadequate PSU) to power LEDs
|
||||
; -D ABL_MILLIAMPS_DEFAULT=850
|
||||
; -D LED_MILLIAMPS_DEFAULT=55
|
||||
;
|
||||
; enable IR by setting remote type
|
||||
; -D IRTYPE=0 # 0 Remote disabled | 1 24-key RGB | 2 24-key with CT | 3 40-key blue | 4 40-key RGB | 5 21-key RGB | 6 6-key black | 7 9-key red | 8 JSON remote
|
||||
;
|
||||
; use PSRAM on classic ESP32 rev.1 (rev.3 or above has no issues)
|
||||
; -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue # needed only for classic ESP32 rev.1
|
||||
;
|
||||
; configure I2C and SPI interface (for various hardware)
|
||||
; -D I2CSDAPIN=33 # initialise interface
|
||||
; -D I2CSCLPIN=35 # initialise interface
|
||||
; -D HW_PIN_SCL=35
|
||||
; -D HW_PIN_SDA=33
|
||||
; -D HW_PIN_CLOCKSPI=7
|
||||
; -D HW_PIN_DATASPI=11
|
||||
; -D HW_PIN_MISOSPI=9
|
||||
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# PRE-CONFIGURED DEVELOPMENT BOARDS AND CONTROLLERS
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
[env:esp07]
|
||||
board = esp07
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:d1_mini]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
upload_speed = 921600
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
monitor_filters = esp8266_exception_decoder
|
||||
|
||||
[env:heltec_wifi_kit_8]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:h803wf]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=1 -D WLED_DISABLE_INFRARED
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:esp32dev_qio80]
|
||||
extends = env:esp32dev # we want to extend the existing esp32dev environment (and define only updated options)
|
||||
board = esp32dev
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} #-D WLED_DISABLE_BROWNOUT_DET
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
|
||||
[env:esp32dev_V4_dio80]
|
||||
;; experimental ESP32 env using ESP-IDF V4.4.x
|
||||
;; Warning: this build environment is not stable!!
|
||||
;; please erase your device before installing.
|
||||
extends = esp32_idf_V4 # based on newer "esp-idf V4" platform environment
|
||||
board = esp32dev
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} #-D WLED_DISABLE_BROWNOUT_DET
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions} ;; if you get errors about "out of program space", change this to ${esp32.extended_partitions} or even ${esp32.big_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = dio
|
||||
|
||||
[env:esp32s2_saola]
|
||||
extends = esp32s2
|
||||
board = esp32-s2-saola-1
|
||||
platform = ${esp32s2.platform}
|
||||
platform_packages = ${esp32s2.platform_packages}
|
||||
framework = arduino
|
||||
board_build.flash_mode = qio
|
||||
upload_speed = 460800
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags}
|
||||
;-DLOLIN_WIFI_FIX ;; try this in case Wifi does not work
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
lib_deps = ${esp32s2.lib_deps}
|
||||
|
||||
[env:esp32s3dev_8MB_PSRAM_qspi]
|
||||
;; ESP32-TinyS3 development board, with 8MB FLASH and PSRAM (memory_type: qio_qspi)
|
||||
extends = env:esp32s3dev_8MB_PSRAM_opi
|
||||
;board = um_tinys3 ; -> needs workaround from https://github.com/wled-dev/WLED/pull/2905#issuecomment-1328049860
|
||||
board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support
|
||||
board_build.arduino.memory_type = qio_qspi ;; use with PSRAM: 2MB or 4MB
|
||||
|
||||
[env:esp8285_4CH_MagicHome]
|
||||
board = esp8285
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_DISABLE_OTA
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:esp8285_H801]
|
||||
board = esp8285
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_DISABLE_OTA
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:d1_mini_5CH_Shojo_PCB]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_USE_SHOJO_PCB ;; NB: WLED_USE_SHOJO_PCB is not used anywhere in the source code. Not sure why its needed.
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:d1_mini_debug]
|
||||
board = d1_mini
|
||||
build_type = debug
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} ${common.debug_flags}
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:d1_mini_ota]
|
||||
board = d1_mini
|
||||
upload_protocol = espota
|
||||
# exchange for your WLED IP
|
||||
upload_port = "10.10.1.27"
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:anavi_miracle_controller]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=12 -D IRPIN=-1 -D RLYPIN=2
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:esp32c3dev_2MB]
|
||||
;; for ESP32-C3 boards with 2MB flash (instead of 4MB).
|
||||
;; this board need a specific partition file. OTA not possible.
|
||||
extends = esp32c3
|
||||
platform = ${esp32c3.platform}
|
||||
platform_packages = ${esp32c3.platform_packages}
|
||||
board = esp32-c3-devkitm-1
|
||||
build_flags = ${common.build_flags} ${esp32c3.build_flags}
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D WLED_DISABLE_OTA
|
||||
; -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
|
||||
-DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
|
||||
build_unflags = ${common.build_unflags}
|
||||
upload_speed = 115200
|
||||
lib_deps = ${esp32c3.lib_deps}
|
||||
board_build.partitions = tools/WLED_ESP32_2MB_noOTA.csv
|
||||
board_build.flash_mode = dio
|
||||
board_upload.flash_size = 2MB
|
||||
board_upload.maximum_size = 2097152
|
||||
|
||||
[env:wemos_shield_esp32]
|
||||
extends = esp32 ;; use default esp32 platform
|
||||
board = esp32dev
|
||||
upload_speed = 460800
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags}
|
||||
-D WLED_RELEASE_NAME=\"ESP32_wemos_shield\"
|
||||
-D DATA_PINS=16
|
||||
-D RLYPIN=19
|
||||
-D BTNPIN=17
|
||||
-D IRPIN=18
|
||||
-UWLED_USE_MY_CONFIG
|
||||
-D USERMOD_DALLASTEMPERATURE
|
||||
-D USERMOD_FOUR_LINE_DISPLAY
|
||||
-D TEMPERATURE_PIN=23
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
OneWire@~2.3.5 ;; needed for USERMOD_DALLASTEMPERATURE
|
||||
olikraus/U8g2 @ ^2.28.8 ;; needed for USERMOD_FOUR_LINE_DISPLAY
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
|
||||
[env:esp32_pico-D4]
|
||||
extends = esp32 ;; use default esp32 platform
|
||||
board = pico32 ;; pico32-D4 is different from the standard esp32dev
|
||||
;; hardware details from https://github.com/srg74/WLED-ESP32-pico
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags}
|
||||
-D WLED_RELEASE_NAME=\"pico32-D4\" -D SERVERNAME='"WLED-pico32"'
|
||||
-D WLED_DISABLE_ADALIGHT ;; no serial-to-USB chip on this board - better to disable serial protocols
|
||||
-D DATA_PINS=2,18 ;; LED pins
|
||||
-D RLYPIN=19 -D BTNPIN=0 -D IRPIN=-1 ;; no default pin for IR
|
||||
-D UM_AUDIOREACTIVE_ENABLE ;; enable AR by default
|
||||
;; Audioreactive settings for on-board microphone (ICS-43432)
|
||||
-D SR_DMTYPE=1 -D I2S_SDPIN=25 -D I2S_WSPIN=15 -D I2S_CKPIN=14
|
||||
-D SR_SQUELCH=5 -D SR_GAIN=30
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
|
||||
[env:m5atom]
|
||||
extends = env:esp32dev # we want to extend the existing esp32dev environment (and define only updated options)
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D DATA_PINS=27 -D BTNPIN=39
|
||||
|
||||
[env:sp501e]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=3 -D BTNPIN=1
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:sp511e]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=3 -D BTNPIN=2 -D IRPIN=5 -D WLED_MAX_BUTTONS=3
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:Athom_RGBCW] ;7w and 5w(GU10) bulbs
|
||||
board = esp8285
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,13,5
|
||||
-D LED_TYPES=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:Athom_15w_RGBCW] ;15w bulb
|
||||
board = esp8285
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,5,13
|
||||
-D LED_TYPES=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -D WLED_USE_IC_CCT
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:Athom_3Pin_Controller] ;small controller with only data
|
||||
board = esp8285
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=0 -D RLYPIN=-1 -D DATA_PINS=1 -D WLED_DISABLE_INFRARED
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:Athom_4Pin_Controller] ; With clock and data interface
|
||||
board = esp8285
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=0 -D RLYPIN=12 -D DATA_PINS=1 -D WLED_DISABLE_INFRARED
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:Athom_5Pin_Controller] ;Analog light strip controller
|
||||
board = esp8285
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=0 -D RLYPIN=-1 DATA_PINS=4,12,14,13 -D WLED_DISABLE_INFRARED
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:MY9291]
|
||||
board = esp01_1m
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_1m128k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_DISABLE_OTA -D USERMOD_MY9291
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# codm pixel controller board configurations
|
||||
# codm-controller-0_6 can also be used for the TYWE3S controller
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
[env:codm-controller-0_6]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_2m512k}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
[env:codm-controller-0_6-rev2]
|
||||
board = esp_wroom_02
|
||||
platform = ${common.platform_wled_default}
|
||||
platform_packages = ${common.platform_packages}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp8266.build_flags}
|
||||
lib_deps = ${esp8266.lib_deps}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# EleksTube-IPS
|
||||
# ------------------------------------------------------------------------------
|
||||
[env:elekstube_ips]
|
||||
extends = esp32 ;; use default esp32 platform
|
||||
board = esp32dev
|
||||
upload_speed = 921600
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} RTC EleksTube_IPS
|
||||
build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED
|
||||
-D DATA_PINS=12
|
||||
-D RLYPIN=27
|
||||
-D BTNPIN=34
|
||||
-D PIXEL_COUNTS=6
|
||||
# Display config
|
||||
-D ST7789_DRIVER
|
||||
-D TFT_WIDTH=135
|
||||
-D TFT_HEIGHT=240
|
||||
-D CGRAM_OFFSET
|
||||
-D TFT_SDA_READ
|
||||
-D TFT_MOSI=23
|
||||
-D TFT_SCLK=18
|
||||
-D TFT_DC=25
|
||||
-D TFT_RST=26
|
||||
-D SPI_FREQUENCY=40000000
|
||||
-D USER_SETUP_LOADED
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Usermod examples
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# 433MHz RF remote example for esp32dev
|
||||
[env:esp32dev_usermod_RF433]
|
||||
extends = env:esp32dev
|
||||
build_flags = ${env:esp32dev.build_flags} -D USERMOD_RF433
|
||||
lib_deps = ${env:esp32dev.lib_deps}
|
||||
sui77/rc-switch @ 2.6.4
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Hub75 examples
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
[env:esp32dev_hub75]
|
||||
board = esp32dev
|
||||
upload_speed = 921600
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages =
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags}
|
||||
-D WLED_RELEASE_NAME=\"ESP32_hub75\"
|
||||
-D WLED_ENABLE_HUB75MATRIX -D NO_GFX
|
||||
-D WLED_DEBUG_BUS
|
||||
; -D WLED_DEBUG
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA.git#3.0.11
|
||||
|
||||
monitor_filters = esp32_exception_decoder
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.flash_mode = dio
|
||||
|
||||
[env:esp32dev_hub75_forum_pinout]
|
||||
extends = env:esp32dev_hub75
|
||||
build_flags = ${common.build_flags}
|
||||
-D WLED_RELEASE_NAME=\"ESP32_hub75_forum_pinout\"
|
||||
-D WLED_ENABLE_HUB75MATRIX -D NO_GFX
|
||||
-D ESP32_FORUM_PINOUT ;; enable for SmartMatrix default pins
|
||||
-D WLED_DEBUG_BUS
|
||||
; -D WLED_DEBUG
|
||||
|
||||
|
||||
|
||||
[env:adafruit_matrixportal_esp32s3]
|
||||
; ESP32-S3 processor, 8 MB flash, 2 MB of PSRAM, dedicated driver pins for HUB75
|
||||
board = adafruit_matrixportal_esp32s3
|
||||
platform = ${esp32s3.platform}
|
||||
platform_packages =
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\"
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D WLED_ENABLE_HUB75MATRIX -D NO_GFX
|
||||
-D S3_LCD_DIV_NUM=20 ;; Attempt to fix wifi performance issue when panel active with S3 chips
|
||||
-D ARDUINO_ADAFRUIT_MATRIXPORTAL_ESP32S3
|
||||
-D WLED_DEBUG_BUS
|
||||
|
||||
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA.git#aa28e2a ;; S3_LCD_DIV_NUM fix
|
||||
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
||||
[env:esp32S3_PSRAM_HUB75]
|
||||
;; MOONHUB HUB75 adapter board
|
||||
board = lilygo-t7-s3
|
||||
platform = ${esp32s3.platform}
|
||||
platform_packages =
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"esp32S3_16MB_PSRAM_HUB75\"
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
-D WLED_WATCHDOG_TIMEOUT=0
|
||||
-D WLED_ENABLE_HUB75MATRIX -D NO_GFX
|
||||
-D S3_LCD_DIV_NUM=20 ;; Attempt to fix wifi performance issue when panel active with S3 chips
|
||||
-D MOONHUB_S3_PINOUT ;; HUB75 pinout
|
||||
-D WLED_DEBUG_BUS
|
||||
|
||||
lib_deps = ${esp32s3.lib_deps}
|
||||
https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA.git#aa28e2a ;; S3_LCD_DIV_NUM fix
|
||||
|
||||
board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
monitor_filters = esp32_exception_decoder
|
||||
98
readme.md
98
readme.md
@@ -1,69 +1,87 @@
|
||||

|
||||
<p align="center">
|
||||
<img src="/images/wled_logo_akemi.png">
|
||||
<a href="https://github.com/wled-dev/WLED/releases"><img src="https://img.shields.io/github/release/wled-dev/WLED.svg?style=flat-square"></a>
|
||||
<a href="https://raw.githubusercontent.com/wled-dev/WLED/main/LICENSE"><img src="https://img.shields.io/github/license/wled-dev/wled?color=blue&style=flat-square"></a>
|
||||
<a href="https://wled.discourse.group"><img src="https://img.shields.io/discourse/topics?colorB=blue&label=forum&server=https%3A%2F%2Fwled.discourse.group%2F&style=flat-square"></a>
|
||||
<a href="https://discord.gg/QAh7wJHrRM"><img src="https://img.shields.io/discord/473448917040758787.svg?colorB=blue&label=discord&style=flat-square"></a>
|
||||
<a href="https://kno.wled.ge"><img src="https://img.shields.io/badge/quick_start-wiki-blue.svg?style=flat-square"></a>
|
||||
<a href="https://github.com/Aircoookie/WLED-App"><img src="https://img.shields.io/badge/app-wled-blue.svg?style=flat-square"></a>
|
||||
<a href="https://gitpod.io/#https://github.com/wled-dev/WLED"><img src="https://img.shields.io/badge/Gitpod-ready--to--code-blue?style=flat-square&logo=gitpod"></a>
|
||||
|
||||
[](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)
|
||||
</p>
|
||||
|
||||
## Welcome to my project WLED!
|
||||
# Welcome to WLED! ✨
|
||||
|
||||
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812, APA102) LEDs!
|
||||
A fast and feature-rich implementation of an ESP32 and ESP8266 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102!
|
||||
|
||||
### Features:
|
||||
- WS2812FX library integrated for almost 100 special effects
|
||||
- FastLED noise effects and palettes
|
||||
Originally created by [Aircoookie](https://github.com/Aircoookie)
|
||||
|
||||
## ⚙️ Features
|
||||
- WS2812FX library with more than 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
|
||||
- Segments to set different effects and colors to user defined parts of the LED string
|
||||
- Settings page - configuration via the network
|
||||
- Access Point and station mode - automatic failsafe AP
|
||||
- [Up to 10 LED outputs](https://kno.wled.ge/features/multi-strip/#esp32) per instance
|
||||
- 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
|
||||
- Up to 250 user presets to save and load colors/effects easily, supports cycling through them.
|
||||
- Presets can be used 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
|
||||
- Full OTA software updateability (HTTP + ArduinoOTA), password protectable
|
||||
- Configurable analog clock (Cronixie, 7-segment and EleksTube IPS clock support via usermods)
|
||||
- Configurable Auto Brightness limit for safe operation
|
||||
- Filesystem-based config for easier backup of presets and settings
|
||||
|
||||
### Supported light control interfaces:
|
||||
- WLED app for Android and iOS
|
||||
## 💡 Supported light control interfaces
|
||||
- WLED app for [Android](https://play.google.com/store/apps/details?id=ca.cgagnier.wlednativeandroid) and [iOS](https://apps.apple.com/gb/app/wled-native/id6446207239)
|
||||
- JSON and HTTP request APIs
|
||||
- MQTT
|
||||
- Blynk IoT
|
||||
- E1.31
|
||||
- Hyperion
|
||||
- E1.31, Art-Net, DDP and TPM2.net
|
||||
- [diyHue](https://github.com/diyhue/diyHue) (Wled is supported by diyHue, including Hue Sync Entertainment under udp. Thanks to [Gregory Mallios](https://github.com/gmallios))
|
||||
- [Hyperion](https://github.com/hyperion-project/hyperion.ng)
|
||||
- UDP realtime
|
||||
- Alexa voice control (including dimming and color)
|
||||
- Sync to Philips hue lights
|
||||
- Adalight (PC ambilight via serial)
|
||||
- Adalight (PC ambilight via serial) and TPM2
|
||||
- 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:
|
||||
## 📲 Quick start guide and documentation
|
||||
|
||||
See the [wiki](https://github.com/Aircoookie/WLED/wiki)!
|
||||
See the [documentation on our official site](https://kno.wled.ge)!
|
||||
|
||||
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)
|
||||
[On this page](https://kno.wled.ge/basics/tutorials/) you can find excellent tutorials and tools to help you get your new project up and running!
|
||||
|
||||
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!
|
||||
## 🖼️ User interface
|
||||
<img src="/images/macbook-pro-space-gray-on-the-wooden-table.jpg" width="50%"><img src="/images/walking-with-iphone-x.jpg" width="50%">
|
||||
|
||||
### Other
|
||||
## 💾 Compatible hardware
|
||||
|
||||
Licensed under the MIT license
|
||||
Credits [here](https://github.com/Aircoookie/WLED/wiki/Contributors-&-About)!
|
||||
See [here](https://kno.wled.ge/basics/compatible-hardware)!
|
||||
|
||||
Uses Linearicons by Perxis!
|
||||
## ✌️ Other
|
||||
|
||||
Licensed under the EUPL v1.2 license
|
||||
Credits [here](https://kno.wled.ge/about/contributors/)!
|
||||
CORS proxy by [Corsfix](https://corsfix.com/)
|
||||
|
||||
Join the Discord server to discuss everything about WLED!
|
||||
|
||||
<a href="https://discord.gg/QAh7wJHrRM"><img src="https://discordapp.com/api/guilds/473448917040758787/widget.png?style=banner2" width="25%"></a>
|
||||
|
||||
Join the Discord [server](https://discord.gg/KuqP7NE) to discuss everything about WLED!
|
||||
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)
|
||||
|
||||
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 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.
|
||||
|
||||
If you are prone to photosensitive epilepsy, we recommended you do **not** use this software.
|
||||
If you still want to try, don't use strobe, lighting or noise modes or high effect speed settings.
|
||||
|
||||
As per the EUPL license, I assume no liability for any damage to you or any other person or equipment.
|
||||
|
||||
|
||||
1
requirements.in
Normal file
1
requirements.in
Normal file
@@ -0,0 +1 @@
|
||||
platformio>=6.1.17
|
||||
58
requirements.txt
Normal file
58
requirements.txt
Normal file
@@ -0,0 +1,58 @@
|
||||
#
|
||||
# This file is autogenerated by pip-compile with Python 3.11
|
||||
# by the following command:
|
||||
#
|
||||
# pip-compile requirements.in
|
||||
#
|
||||
ajsonrpc==1.2.0
|
||||
# via platformio
|
||||
anyio==4.8.0
|
||||
# via starlette
|
||||
bottle==0.13.2
|
||||
# via platformio
|
||||
certifi==2025.1.31
|
||||
# via requests
|
||||
charset-normalizer==3.4.1
|
||||
# via requests
|
||||
click==8.1.8
|
||||
# via
|
||||
# platformio
|
||||
# uvicorn
|
||||
colorama==0.4.6
|
||||
# via platformio
|
||||
h11==0.16.0
|
||||
# via
|
||||
# uvicorn
|
||||
# wsproto
|
||||
idna==3.10
|
||||
# via
|
||||
# anyio
|
||||
# requests
|
||||
marshmallow==3.26.1
|
||||
# via platformio
|
||||
packaging==24.2
|
||||
# via marshmallow
|
||||
platformio==6.1.17
|
||||
# via -r requirements.in
|
||||
pyelftools==0.32
|
||||
# via platformio
|
||||
pyserial==3.5
|
||||
# via platformio
|
||||
requests==2.32.4
|
||||
# via platformio
|
||||
semantic-version==2.10.0
|
||||
# via platformio
|
||||
sniffio==1.3.1
|
||||
# via anyio
|
||||
starlette==0.45.3
|
||||
# via platformio
|
||||
tabulate==0.9.0
|
||||
# via platformio
|
||||
typing-extensions==4.12.2
|
||||
# via anyio
|
||||
urllib3==2.5.0
|
||||
# via requests
|
||||
uvicorn==0.34.0
|
||||
# via platformio
|
||||
wsproto==1.2.0
|
||||
# via platformio
|
||||
BIN
tools/AutoCubeMap.xlsx
Normal file
BIN
tools/AutoCubeMap.xlsx
Normal file
Binary file not shown.
6
tools/WLED_ESP32-wrover_4MB.csv
Normal file
6
tools/WLED_ESP32-wrover_4MB.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x1A0000,
|
||||
app1, app, ota_1, 0x1B0000,0x1A0000,
|
||||
spiffs, data, spiffs, 0x350000,0xB0000,
|
||||
|
6
tools/WLED_ESP32_16MB.csv
Normal file
6
tools/WLED_ESP32_16MB.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x200000,
|
||||
app1, app, ota_1, 0x210000,0x200000,
|
||||
spiffs, data, spiffs, 0x410000,0xBE0000,
|
||||
|
8
tools/WLED_ESP32_16MB_9MB_FS.csv
Normal file
8
tools/WLED_ESP32_16MB_9MB_FS.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x300000,
|
||||
app1, app, ota_1, 0x310000,0x300000,
|
||||
spiffs, data, spiffs, 0x610000,0x9E0000,
|
||||
coredump, data, coredump,,64K
|
||||
# to create/use ffat, see https://github.com/marcmerlin/esp32_fatfsimage
|
||||
|
5
tools/WLED_ESP32_2MB_noOTA.csv
Normal file
5
tools/WLED_ESP32_2MB_noOTA.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 20K,
|
||||
otadata, data, ota, 0xe000, 8K,
|
||||
app0, app, ota_0, 0x10000, 1536K,
|
||||
spiffs, data, spiffs, 0x190000, 384K,
|
||||
|
6
tools/WLED_ESP32_4MB_1MB_FS.csv
Normal file
6
tools/WLED_ESP32_4MB_1MB_FS.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x180000,
|
||||
app1, app, ota_1, 0x190000,0x180000,
|
||||
spiffs, data, spiffs, 0x310000,0xF0000,
|
||||
|
7
tools/WLED_ESP32_4MB_256KB_FS.csv
Normal file
7
tools/WLED_ESP32_4MB_256KB_FS.csv
Normal file
@@ -0,0 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x1D0000,
|
||||
app1, app, ota_1, 0x1E0000,0x1D0000,
|
||||
spiffs, data, spiffs, 0x3B0000,0x40000,
|
||||
coredump, data, coredump,,64K
|
||||
|
7
tools/WLED_ESP32_4MB_512KB_FS.csv
Normal file
7
tools/WLED_ESP32_4MB_512KB_FS.csv
Normal file
@@ -0,0 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x1B0000,
|
||||
app1, app, ota_1, 0x1C0000,0x1B0000,
|
||||
spiffs, data, spiffs, 0x370000,0x80000,
|
||||
coredump, data, coredump,,64K
|
||||
|
6
tools/WLED_ESP32_4MB_700k_FS.csv
Normal file
6
tools/WLED_ESP32_4MB_700k_FS.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x1A0000,
|
||||
app1, app, ota_1, 0x1B0000,0x1A0000,
|
||||
spiffs, data, spiffs, 0x350000,0xB0000,
|
||||
|
7
tools/WLED_ESP32_8MB.csv
Normal file
7
tools/WLED_ESP32_8MB.csv
Normal file
@@ -0,0 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x200000,
|
||||
app1, app, ota_1, 0x210000,0x200000,
|
||||
spiffs, data, spiffs, 0x410000,0x3E0000,
|
||||
coredump, data, coredump,,64K
|
||||
|
17
tools/all_xml.sh
Normal file
17
tools/all_xml.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# Pull all settings pages for comparison
|
||||
HOST=$1
|
||||
TGT_PATH=$2
|
||||
CURL_ARGS="--compressed"
|
||||
|
||||
# Replicate one target many times
|
||||
function replicate() {
|
||||
for i in {0..10}
|
||||
do
|
||||
echo -n " http://${HOST}/settings.js?p=$i -o ${TGT_PATH}/$i.xml"
|
||||
done
|
||||
}
|
||||
read -a TARGETS <<< $(replicate)
|
||||
|
||||
mkdir -p ${TGT_PATH}
|
||||
curl ${CURL_ARGS} ${TARGETS[@]}
|
||||
212
tools/cdata-test.js
Normal file
212
tools/cdata-test.js
Normal file
@@ -0,0 +1,212 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert');
|
||||
const { describe, it, before, after } = require('node:test');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const child_process = require('child_process');
|
||||
const util = require('util');
|
||||
const execPromise = util.promisify(child_process.exec);
|
||||
|
||||
process.env.NODE_ENV = 'test'; // Set the environment to testing
|
||||
const cdata = require('./cdata.js');
|
||||
|
||||
describe('Function', () => {
|
||||
const testFolderPath = path.join(__dirname, 'testFolder');
|
||||
const oldFilePath = path.join(testFolderPath, 'oldFile.txt');
|
||||
const newFilePath = path.join(testFolderPath, 'newFile.txt');
|
||||
|
||||
// Create a temporary file before the test
|
||||
before(() => {
|
||||
// Create test folder
|
||||
if (!fs.existsSync(testFolderPath)) {
|
||||
fs.mkdirSync(testFolderPath);
|
||||
}
|
||||
|
||||
// Create an old file
|
||||
fs.writeFileSync(oldFilePath, 'This is an old file.');
|
||||
// Modify the 'mtime' to simulate an old file
|
||||
const oldTime = new Date();
|
||||
oldTime.setFullYear(oldTime.getFullYear() - 1);
|
||||
fs.utimesSync(oldFilePath, oldTime, oldTime);
|
||||
|
||||
// Create a new file
|
||||
fs.writeFileSync(newFilePath, 'This is a new file.');
|
||||
});
|
||||
|
||||
// delete the temporary files after the test
|
||||
after(() => {
|
||||
fs.rmSync(testFolderPath, { recursive: true });
|
||||
});
|
||||
|
||||
describe('isFileNewerThan', async () => {
|
||||
it('should return true if the file is newer than the provided time', async () => {
|
||||
const pastTime = Date.now() - 10000; // 10 seconds ago
|
||||
assert.strictEqual(cdata.isFileNewerThan(newFilePath, pastTime), true);
|
||||
});
|
||||
|
||||
it('should return false if the file is older than the provided time', async () => {
|
||||
assert.strictEqual(cdata.isFileNewerThan(oldFilePath, Date.now()), false);
|
||||
});
|
||||
|
||||
it('should throw an exception if the file does not exist', async () => {
|
||||
assert.throws(() => {
|
||||
cdata.isFileNewerThan('nonexistent.txt', Date.now());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAnyFileInFolderNewerThan', async () => {
|
||||
it('should return true if a file in the folder is newer than the given time', async () => {
|
||||
const time = fs.statSync(path.join(testFolderPath, 'oldFile.txt')).mtime;
|
||||
assert.strictEqual(cdata.isAnyFileInFolderNewerThan(testFolderPath, time), true);
|
||||
});
|
||||
|
||||
it('should return false if no files in the folder are newer than the given time', async () => {
|
||||
assert.strictEqual(cdata.isAnyFileInFolderNewerThan(testFolderPath, new Date()), false);
|
||||
});
|
||||
|
||||
it('should throw an exception if the folder does not exist', async () => {
|
||||
assert.throws(() => {
|
||||
cdata.isAnyFileInFolderNewerThan('nonexistent', new Date());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Script', () => {
|
||||
const folderPath = 'wled00';
|
||||
const dataPath = path.join(folderPath, 'data');
|
||||
|
||||
before(() => {
|
||||
process.env.NODE_ENV = 'production';
|
||||
// Backup files
|
||||
fs.cpSync("wled00/data", "wled00Backup", { recursive: true });
|
||||
fs.cpSync("tools/cdata.js", "cdata.bak.js");
|
||||
fs.cpSync("package.json", "package.bak.json");
|
||||
});
|
||||
after(() => {
|
||||
// Restore backup
|
||||
fs.rmSync("wled00/data", { recursive: true });
|
||||
fs.renameSync("wled00Backup", "wled00/data");
|
||||
fs.rmSync("tools/cdata.js");
|
||||
fs.renameSync("cdata.bak.js", "tools/cdata.js");
|
||||
fs.rmSync("package.json");
|
||||
fs.renameSync("package.bak.json", "package.json");
|
||||
});
|
||||
|
||||
// delete all html_*.h files
|
||||
async function deleteBuiltFiles() {
|
||||
const files = await fs.promises.readdir(folderPath);
|
||||
await Promise.all(files.map(file => {
|
||||
if (file.startsWith('html_') && path.extname(file) === '.h') {
|
||||
return fs.promises.unlink(path.join(folderPath, file));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// check if html_*.h files were created
|
||||
async function checkIfBuiltFilesExist() {
|
||||
const files = await fs.promises.readdir(folderPath);
|
||||
const htmlFiles = files.filter(file => file.startsWith('html_') && path.extname(file) === '.h');
|
||||
assert(htmlFiles.length > 0, 'html_*.h files were not created');
|
||||
}
|
||||
|
||||
async function runAndCheckIfBuiltFilesExist() {
|
||||
await execPromise('node tools/cdata.js');
|
||||
await checkIfBuiltFilesExist();
|
||||
}
|
||||
|
||||
async function checkIfFileWasNewlyCreated(file) {
|
||||
const modifiedTime = fs.statSync(file).mtimeMs;
|
||||
assert(Date.now() - modifiedTime < 500, file + ' was not modified');
|
||||
}
|
||||
|
||||
async function testFileModification(sourceFilePath, resultFile) {
|
||||
// run cdata.js to ensure html_*.h files are created
|
||||
await execPromise('node tools/cdata.js');
|
||||
|
||||
// modify file
|
||||
fs.appendFileSync(sourceFilePath, ' ');
|
||||
// delay for 1 second to ensure the modified time is different
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
// run script cdata.js again and wait for it to finish
|
||||
await execPromise('node tools/cdata.js');
|
||||
|
||||
await checkIfFileWasNewlyCreated(path.join(folderPath, resultFile));
|
||||
}
|
||||
|
||||
describe('should build if', () => {
|
||||
it('html_*.h files are missing', async () => {
|
||||
await deleteBuiltFiles();
|
||||
await runAndCheckIfBuiltFilesExist();
|
||||
});
|
||||
|
||||
it('only one html_*.h file is missing', async () => {
|
||||
// run script cdata.js and wait for it to finish
|
||||
await execPromise('node tools/cdata.js');
|
||||
|
||||
// delete a random html_*.h file
|
||||
let files = await fs.promises.readdir(folderPath);
|
||||
let htmlFiles = files.filter(file => file.startsWith('html_') && path.extname(file) === '.h');
|
||||
const randomFile = htmlFiles[Math.floor(Math.random() * htmlFiles.length)];
|
||||
await fs.promises.unlink(path.join(folderPath, randomFile));
|
||||
|
||||
await runAndCheckIfBuiltFilesExist();
|
||||
});
|
||||
|
||||
it('script was executed with -f or --force', async () => {
|
||||
await execPromise('node tools/cdata.js');
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
await execPromise('node tools/cdata.js --force');
|
||||
await checkIfFileWasNewlyCreated(path.join(folderPath, 'html_ui.h'));
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
await execPromise('node tools/cdata.js -f');
|
||||
await checkIfFileWasNewlyCreated(path.join(folderPath, 'html_ui.h'));
|
||||
});
|
||||
|
||||
it('a file changes', async () => {
|
||||
await testFileModification(path.join(dataPath, 'index.htm'), 'html_ui.h');
|
||||
});
|
||||
|
||||
it('a inlined file changes', async () => {
|
||||
await testFileModification(path.join(dataPath, 'index.js'), 'html_ui.h');
|
||||
});
|
||||
|
||||
it('a settings file changes', async () => {
|
||||
await testFileModification(path.join(dataPath, 'settings_leds.htm'), 'html_ui.h');
|
||||
});
|
||||
|
||||
it('the favicon changes', async () => {
|
||||
await testFileModification(path.join(dataPath, 'favicon.ico'), 'html_ui.h');
|
||||
});
|
||||
|
||||
it('cdata.js changes', async () => {
|
||||
await testFileModification('tools/cdata.js', 'html_ui.h');
|
||||
});
|
||||
|
||||
it('package.json changes', async () => {
|
||||
await testFileModification('package.json', 'html_ui.h');
|
||||
});
|
||||
});
|
||||
|
||||
describe('should not build if', () => {
|
||||
it('the files are already built', async () => {
|
||||
await deleteBuiltFiles();
|
||||
|
||||
// run script cdata.js and wait for it to finish
|
||||
let startTime = Date.now();
|
||||
await execPromise('node tools/cdata.js');
|
||||
const firstRunTime = Date.now() - startTime;
|
||||
|
||||
// run script cdata.js and wait for it to finish
|
||||
startTime = Date.now();
|
||||
await execPromise('node tools/cdata.js');
|
||||
const secondRunTime = Date.now() - startTime;
|
||||
|
||||
// check if second run was faster than the first (must be at least 2x faster)
|
||||
assert(secondRunTime < firstRunTime / 2, 'html_*.h files were rebuilt');
|
||||
});
|
||||
});
|
||||
});
|
||||
429
tools/cdata.js
Normal file
429
tools/cdata.js
Normal file
@@ -0,0 +1,429 @@
|
||||
/**
|
||||
* Writes compressed C arrays of data files (web interface)
|
||||
* How to use it?
|
||||
*
|
||||
* 1) Install Node 20+ and npm
|
||||
* 2) npm install
|
||||
* 3) npm run build
|
||||
*
|
||||
* If you change data folder often, you can run it in monitoring mode (it will recompile and update *.h on every file change)
|
||||
*
|
||||
* > npm run dev
|
||||
*
|
||||
* How it works?
|
||||
*
|
||||
* It uses NodeJS packages to inline, minify and GZIP files. See writeHtmlGzipped and writeChunks invocations at the bottom of the page.
|
||||
*/
|
||||
|
||||
const fs = require("node:fs");
|
||||
const path = require("path");
|
||||
const inline = require("web-resource-inliner");
|
||||
const zlib = require("node:zlib");
|
||||
const CleanCSS = require("clean-css");
|
||||
const minifyHtml = require("html-minifier-terser").minify;
|
||||
const packageJson = require("../package.json");
|
||||
|
||||
// Export functions for testing
|
||||
module.exports = { isFileNewerThan, isAnyFileInFolderNewerThan };
|
||||
|
||||
const output = ["wled00/html_ui.h", "wled00/html_pixart.h", "wled00/html_cpal.h", "wled00/html_pxmagic.h", "wled00/html_settings.h", "wled00/html_other.h"]
|
||||
|
||||
// \x1b[34m is blue, \x1b[36m is cyan, \x1b[0m is reset
|
||||
const wledBanner = `
|
||||
\t\x1b[34m ## ## ## ###### ######
|
||||
\t\x1b[34m## ## ## ## ## ## ##
|
||||
\t\x1b[34m## ## ## ## ###### ## ##
|
||||
\t\x1b[34m## ## ## ## ## ## ##
|
||||
\t\x1b[34m ## ## ###### ###### ######
|
||||
\t\t\x1b[36m build script for web UI
|
||||
\x1b[0m`;
|
||||
|
||||
const singleHeader = `/*
|
||||
* Binary array for the Web UI.
|
||||
* gzip is used for smaller size and improved speeds.
|
||||
*
|
||||
* Please see https://kno.wled.ge/advanced/custom-features/#changing-web-ui
|
||||
* to find out how to easily modify the web UI source!
|
||||
*/
|
||||
|
||||
`;
|
||||
|
||||
const multiHeader = `/*
|
||||
* More web UI HTML source arrays.
|
||||
* This file is auto generated, please don't make any changes manually.
|
||||
*
|
||||
* Instead, see https://kno.wled.ge/advanced/custom-features/#changing-web-ui
|
||||
* to find out how to easily modify the web UI source!
|
||||
*/
|
||||
`;
|
||||
|
||||
function hexdump(buffer, isHex = false) {
|
||||
let lines = [];
|
||||
|
||||
for (let i = 0; i < buffer.length; i += (isHex ? 32 : 16)) {
|
||||
var block;
|
||||
let hexArray = [];
|
||||
if (isHex) {
|
||||
block = buffer.slice(i, i + 32)
|
||||
for (let j = 0; j < block.length; j += 2) {
|
||||
hexArray.push("0x" + block.slice(j, j + 2))
|
||||
}
|
||||
} else {
|
||||
block = buffer.slice(i, i + 16); // cut buffer into blocks of 16
|
||||
for (let value of block) {
|
||||
hexArray.push("0x" + value.toString(16).padStart(2, "0"));
|
||||
}
|
||||
}
|
||||
|
||||
let hexString = hexArray.join(", ");
|
||||
let line = ` ${hexString}`;
|
||||
lines.push(line);
|
||||
}
|
||||
|
||||
return lines.join(",\n");
|
||||
}
|
||||
|
||||
function adoptVersionAndRepo(html) {
|
||||
let repoUrl = packageJson.repository ? packageJson.repository.url : undefined;
|
||||
if (repoUrl) {
|
||||
repoUrl = repoUrl.replace(/^git\+/, "");
|
||||
repoUrl = repoUrl.replace(/\.git$/, "");
|
||||
html = html.replaceAll("https://github.com/atuline/WLED", repoUrl);
|
||||
html = html.replaceAll("https://github.com/wled-dev/WLED", repoUrl);
|
||||
}
|
||||
let version = packageJson.version;
|
||||
if (version) {
|
||||
html = html.replaceAll("##VERSION##", version);
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
async function minify(str, type = "plain") {
|
||||
const options = {
|
||||
collapseWhitespace: true,
|
||||
conservativeCollapse: true, // preserve spaces in text
|
||||
collapseBooleanAttributes: true,
|
||||
collapseInlineTagWhitespace: true,
|
||||
minifyCSS: true,
|
||||
minifyJS: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeComments: true,
|
||||
sortAttributes: true,
|
||||
sortClassName: true,
|
||||
};
|
||||
|
||||
if (type == "plain") {
|
||||
return str;
|
||||
} else if (type == "css-minify") {
|
||||
return new CleanCSS({}).minify(str).styles;
|
||||
} else if (type == "js-minify") {
|
||||
let js = await minifyHtml('<script>' + str + '</script>', options);
|
||||
return js.replace(/<[\/]*script>/g, '');
|
||||
} else if (type == "html-minify") {
|
||||
return await minifyHtml(str, options);
|
||||
}
|
||||
|
||||
throw new Error("Unknown filter: " + type);
|
||||
}
|
||||
|
||||
async function writeHtmlGzipped(sourceFile, resultFile, page) {
|
||||
console.info("Reading " + sourceFile);
|
||||
inline.html({
|
||||
fileContent: fs.readFileSync(sourceFile, "utf8"),
|
||||
relativeTo: path.dirname(sourceFile),
|
||||
strict: true,
|
||||
},
|
||||
async function (error, html) {
|
||||
if (error) throw error;
|
||||
|
||||
html = adoptVersionAndRepo(html);
|
||||
const originalLength = html.length;
|
||||
html = await minify(html, "html-minify");
|
||||
const result = zlib.gzipSync(html, { level: zlib.constants.Z_BEST_COMPRESSION });
|
||||
console.info("Minified and compressed " + sourceFile + " from " + originalLength + " to " + result.length + " bytes");
|
||||
const array = hexdump(result);
|
||||
let src = singleHeader;
|
||||
src += `const uint16_t PAGE_${page}_length = ${result.length};\n`;
|
||||
src += `const uint8_t PAGE_${page}[] PROGMEM = {\n${array}\n};\n\n`;
|
||||
console.info("Writing " + resultFile);
|
||||
fs.writeFileSync(resultFile, src);
|
||||
});
|
||||
}
|
||||
|
||||
async function specToChunk(srcDir, s) {
|
||||
const buf = fs.readFileSync(srcDir + "/" + s.file);
|
||||
let chunk = `\n// Autogenerated from ${srcDir}/${s.file}, do not edit!!\n`
|
||||
|
||||
if (s.method == "plaintext" || s.method == "gzip") {
|
||||
let str = buf.toString("utf-8");
|
||||
str = adoptVersionAndRepo(str);
|
||||
const originalLength = str.length;
|
||||
if (s.method == "gzip") {
|
||||
if (s.mangle) str = s.mangle(str);
|
||||
const zip = zlib.gzipSync(await minify(str, s.filter), { level: zlib.constants.Z_BEST_COMPRESSION });
|
||||
console.info("Minified and compressed " + s.file + " from " + originalLength + " to " + zip.length + " bytes");
|
||||
const result = hexdump(zip);
|
||||
chunk += `const uint16_t ${s.name}_length = ${zip.length};\n`;
|
||||
chunk += `const uint8_t ${s.name}[] PROGMEM = {\n${result}\n};\n\n`;
|
||||
return chunk;
|
||||
} else {
|
||||
const minified = await minify(str, s.filter);
|
||||
console.info("Minified " + s.file + " from " + originalLength + " to " + minified.length + " bytes");
|
||||
chunk += `const char ${s.name}[] PROGMEM = R"${s.prepend || ""}${minified}${s.append || ""}";\n\n`;
|
||||
return s.mangle ? s.mangle(chunk) : chunk;
|
||||
}
|
||||
} else if (s.method == "binary") {
|
||||
const result = hexdump(buf);
|
||||
chunk += `const uint16_t ${s.name}_length = ${buf.length};\n`;
|
||||
chunk += `const uint8_t ${s.name}[] PROGMEM = {\n${result}\n};\n\n`;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
throw new Error("Unknown method: " + s.method);
|
||||
}
|
||||
|
||||
async function writeChunks(srcDir, specs, resultFile) {
|
||||
let src = multiHeader;
|
||||
for (const s of specs) {
|
||||
console.info("Reading " + srcDir + "/" + s.file + " as " + s.name);
|
||||
src += await specToChunk(srcDir, s);
|
||||
}
|
||||
console.info("Writing " + src.length + " characters into " + resultFile);
|
||||
fs.writeFileSync(resultFile, src);
|
||||
}
|
||||
|
||||
// Check if a file is newer than a given time
|
||||
function isFileNewerThan(filePath, time) {
|
||||
const stats = fs.statSync(filePath);
|
||||
return stats.mtimeMs > time;
|
||||
}
|
||||
|
||||
// Check if any file in a folder (or its subfolders) is newer than a given time
|
||||
function isAnyFileInFolderNewerThan(folderPath, time) {
|
||||
const files = fs.readdirSync(folderPath, { withFileTypes: true });
|
||||
for (const file of files) {
|
||||
const filePath = path.join(folderPath, file.name);
|
||||
if (isFileNewerThan(filePath, time)) {
|
||||
return true;
|
||||
}
|
||||
if (file.isDirectory() && isAnyFileInFolderNewerThan(filePath, time)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the web UI is already built
|
||||
function isAlreadyBuilt(webUIPath, packageJsonPath = "package.json") {
|
||||
let lastBuildTime = Infinity;
|
||||
|
||||
for (const file of output) {
|
||||
try {
|
||||
lastBuildTime = Math.min(lastBuildTime, fs.statSync(file).mtimeMs);
|
||||
} catch (e) {
|
||||
if (e.code !== 'ENOENT') throw e;
|
||||
console.info("File " + file + " does not exist. Rebuilding...");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !isAnyFileInFolderNewerThan(webUIPath, lastBuildTime) && !isFileNewerThan(packageJsonPath, lastBuildTime) && !isFileNewerThan(__filename, lastBuildTime);
|
||||
}
|
||||
|
||||
// Don't run this script if we're in a test environment
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
return;
|
||||
}
|
||||
|
||||
console.info(wledBanner);
|
||||
|
||||
if (isAlreadyBuilt("wled00/data") && process.argv[2] !== '--force' && process.argv[2] !== '-f') {
|
||||
console.info("Web UI is already built");
|
||||
return;
|
||||
}
|
||||
|
||||
writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h", 'index');
|
||||
writeHtmlGzipped("wled00/data/pixart/pixart.htm", "wled00/html_pixart.h", 'pixart');
|
||||
//writeHtmlGzipped("wled00/data/cpal/cpal.htm", "wled00/html_cpal.h", 'cpal');
|
||||
writeHtmlGzipped("wled00/data/pxmagic/pxmagic.htm", "wled00/html_pxmagic.h", 'pxmagic');
|
||||
|
||||
writeChunks(
|
||||
"wled00/data/cpal",
|
||||
[
|
||||
{
|
||||
file: "cpal.htm",
|
||||
name: "PAGE_cpal",
|
||||
method: "gzip",
|
||||
filter: "html-minify"
|
||||
}
|
||||
],
|
||||
"wled00/html_cpal.h"
|
||||
);
|
||||
|
||||
writeChunks(
|
||||
"wled00/data",
|
||||
[
|
||||
{
|
||||
file: "style.css",
|
||||
name: "PAGE_settingsCss",
|
||||
method: "gzip",
|
||||
filter: "css-minify",
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace("%%", "%")
|
||||
},
|
||||
{
|
||||
file: "common.js",
|
||||
name: "JS_common",
|
||||
method: "gzip",
|
||||
filter: "js-minify",
|
||||
},
|
||||
{
|
||||
file: "settings.htm",
|
||||
name: "PAGE_settings",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "settings_wifi.htm",
|
||||
name: "PAGE_settings_wifi",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "settings_leds.htm",
|
||||
name: "PAGE_settings_leds",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "settings_dmx.htm",
|
||||
name: "PAGE_settings_dmx",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "settings_ui.htm",
|
||||
name: "PAGE_settings_ui",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "settings_sync.htm",
|
||||
name: "PAGE_settings_sync",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "settings_time.htm",
|
||||
name: "PAGE_settings_time",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "settings_sec.htm",
|
||||
name: "PAGE_settings_sec",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "settings_um.htm",
|
||||
name: "PAGE_settings_um",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "settings_2D.htm",
|
||||
name: "PAGE_settings_2D",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "settings_pin.htm",
|
||||
name: "PAGE_settings_pin",
|
||||
method: "gzip",
|
||||
filter: "html-minify"
|
||||
}
|
||||
],
|
||||
"wled00/html_settings.h"
|
||||
);
|
||||
|
||||
writeChunks(
|
||||
"wled00/data",
|
||||
[
|
||||
{
|
||||
file: "usermod.htm",
|
||||
name: "PAGE_usermod",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
mangle: (str) =>
|
||||
str.replace(/fetch\("http\:\/\/.*\/win/gms, 'fetch("/win'),
|
||||
},
|
||||
{
|
||||
file: "msg.htm",
|
||||
name: "PAGE_msg",
|
||||
prepend: "=====(",
|
||||
append: ")=====",
|
||||
method: "plaintext",
|
||||
filter: "html-minify",
|
||||
mangle: (str) => str.replace(/\<h2\>.*\<\/body\>/gms, "<h2>%MSG%</body>"),
|
||||
},
|
||||
{
|
||||
file: "dmxmap.htm",
|
||||
name: "PAGE_dmxmap",
|
||||
prepend: "=====(",
|
||||
append: ")=====",
|
||||
method: "plaintext",
|
||||
filter: "html-minify",
|
||||
mangle: (str) => `
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
${str.replace(/function FM\(\)[ ]?\{/gms, "function FM() {%DMXVARS%\n")}
|
||||
#else
|
||||
const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
|
||||
#endif
|
||||
`,
|
||||
},
|
||||
{
|
||||
file: "update.htm",
|
||||
name: "PAGE_update",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
mangle: (str) =>
|
||||
str
|
||||
.replace(
|
||||
/function GetV().*\<\/script\>/gms,
|
||||
"</script><script src=\"/settings/s.js?p=9\"></script>"
|
||||
)
|
||||
},
|
||||
{
|
||||
file: "welcome.htm",
|
||||
name: "PAGE_welcome",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "liveview.htm",
|
||||
name: "PAGE_liveview",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "liveviewws2D.htm",
|
||||
name: "PAGE_liveviewws2D",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "404.htm",
|
||||
name: "PAGE_404",
|
||||
method: "gzip",
|
||||
filter: "html-minify",
|
||||
},
|
||||
{
|
||||
file: "favicon.ico",
|
||||
name: "favicon",
|
||||
method: "binary",
|
||||
}
|
||||
],
|
||||
"wled00/html_other.h"
|
||||
);
|
||||
232
tools/fps_test.htm
Normal file
232
tools/fps_test.htm
Normal file
@@ -0,0 +1,232 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>WLED frame rate test tool</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #222;
|
||||
color: #fff;
|
||||
font-family: Helvetica, Verdana, sans-serif;
|
||||
}
|
||||
input {
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
#ip {
|
||||
width: 100px;
|
||||
}
|
||||
#secs {
|
||||
width: 36px;
|
||||
}
|
||||
#csva {
|
||||
position: absolute;
|
||||
top: -100px; /*gtfo*/
|
||||
}
|
||||
button {
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
table, th, td {
|
||||
border: 1px solid #aaa;
|
||||
border-collapse: collapse;
|
||||
text-align: center;
|
||||
}
|
||||
.red {
|
||||
color: #d20;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var gotfx = false, running = false;
|
||||
var pos = 0, prev = 0, min = 999, max = 0, fpslist = [], names = [], names_checked = [];
|
||||
var to;
|
||||
function S() {
|
||||
document.getElementById('ip').value = localStorage.getItem('locIpFps');
|
||||
if (document.getElementById('ip').value) req(false);
|
||||
}
|
||||
function loadC() {
|
||||
hide(false);
|
||||
var list = localStorage.getItem('fpsFxSelection');
|
||||
if (!list) return;
|
||||
list = JSON.parse(list);
|
||||
var chks = document.querySelectorAll('.fxcheck');
|
||||
for (let i = 0; i < chks.length; i++) {
|
||||
if (i < list.length) chks[i].checked = list[i];
|
||||
}
|
||||
}
|
||||
function saveC() {
|
||||
var list = [];
|
||||
var chks = document.querySelectorAll('.fxcheck');
|
||||
for (let i = 0; i < chks.length; i++) {
|
||||
list.push(chks[i].checked);
|
||||
}
|
||||
localStorage.setItem('fpsFxSelection', JSON.stringify(list));
|
||||
}
|
||||
function setC(c) {
|
||||
hide(false);
|
||||
var chks = document.querySelectorAll('.fxcheck');
|
||||
for (let i = 0; i < chks.length; i++) {
|
||||
chks[i].checked = (c == 255);
|
||||
}
|
||||
if (c == 1 && chks.length > 100) {
|
||||
chks[1].checked = true; //Blink
|
||||
chks[15].checked = true; //Running
|
||||
chks[16].checked = true; //Saw
|
||||
chks[37].checked = true; //Running 2
|
||||
chks[44].checked = true; //Tetrix
|
||||
chks[63].checked = true; //Pride 2015
|
||||
chks[74].checked = true; //Colortwinkles
|
||||
chks[101].checked = true;//Pacifica
|
||||
}
|
||||
}
|
||||
function hide(h) {
|
||||
var trs = document.querySelectorAll('.trs');
|
||||
var chks = document.querySelectorAll('.fxcheck');
|
||||
for (let i = 0; i < trs.length; i++) {
|
||||
trs[i].style.display = (h && !chks[i].checked) ? "none":"table-row";
|
||||
}
|
||||
}
|
||||
function run(init) {
|
||||
if (init) {
|
||||
running = !running;
|
||||
document.getElementById('runbtn').innerText = running ? 'Stop':'Run';
|
||||
if (running) {pos = 0; prev = -1; min = 999; max = 0; fpslist = []; names_checked = []; hide(true);}
|
||||
clearTimeout(to);
|
||||
if (!running) {req({seg:{fx:0},v:true,stop:true}); return;}
|
||||
}
|
||||
if (!gotfx) {req(false); return;}
|
||||
var chks = document.querySelectorAll('.fxcheck');
|
||||
var fpsb = document.querySelectorAll('.fps');
|
||||
if (prev >= 0) {pos++};
|
||||
if (pos >= chks.length) {run(true); return;} //end
|
||||
while (!chks[pos].checked) {
|
||||
fpsb[pos].innerText = "-";
|
||||
pos++;
|
||||
if (pos >= chks.length) {run(true); return;} //end
|
||||
}
|
||||
names_checked.push(names[pos]);
|
||||
var extra = {};
|
||||
try {
|
||||
extra = JSON.parse(document.getElementById('ej').value);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
var cmd = {seg:{fx:pos},v:true};
|
||||
Object.assign(cmd, extra);
|
||||
req(cmd);
|
||||
}
|
||||
function req(command) {
|
||||
var ip = document.getElementById('ip').value;
|
||||
if (!ip) {alert("Please enter WLED IP"); return;}
|
||||
if (ip != localStorage.getItem('locIpFps')) localStorage.setItem('locIpFps', document.getElementById('ip').value);
|
||||
var url = command ? `http://${ip}/json/si` : `http://${ip}/json/effects`;
|
||||
var type = command ? 'post':'get';
|
||||
var req = undefined;
|
||||
if (command)
|
||||
{
|
||||
req = JSON.stringify(command);
|
||||
}
|
||||
fetch
|
||||
(url, {
|
||||
method: type,
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8"
|
||||
},
|
||||
body: req
|
||||
})
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
alert('Data malfunction');
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
.then(json => {
|
||||
if (!json) {
|
||||
alert('Empty response'); return;
|
||||
}
|
||||
if (!command) {
|
||||
names = json;
|
||||
var tblc = '';
|
||||
for (let i = 0; i < json.length; i++) {
|
||||
tblc += `<tr class="trs"><td><input type="checkbox" class="fxcheck" /></td><td>${i}</td><td>${json[i]}</td><td class="fps"></td></tr>`
|
||||
}
|
||||
var tbl = `<table>
|
||||
<tr>
|
||||
<th>Test?</th><th>ID</th><th>Effect Name</th><th>FPS</th>
|
||||
</tr>
|
||||
${tblc}
|
||||
</table>`;
|
||||
document.getElementById('tablecon').innerHTML = tbl;
|
||||
setC(1);
|
||||
loadC();
|
||||
gotfx = true;
|
||||
document.getElementById('runbtn').innerText = "Run";
|
||||
} else {
|
||||
if (!json.info) return;
|
||||
document.getElementById('leds').innerText = json.info.leds.count;
|
||||
document.getElementById('seg').innerText = json.state.seg[0].len;
|
||||
document.getElementById('bri').innerText = json.state.bri;
|
||||
if (prev >= 0) {
|
||||
var lastfps = parseInt(json.info.leds.fps); //previous FX
|
||||
if (lastfps < min) min = lastfps;
|
||||
if (lastfps > max) max = lastfps;
|
||||
fpslist.push(lastfps);
|
||||
var sum = 0;
|
||||
for (let i = 0; i < fpslist.length; i++) {
|
||||
sum += fpslist[i];
|
||||
}
|
||||
sum /= fpslist.length;
|
||||
document.getElementById('fps_min').innerText = min;
|
||||
document.getElementById('fps_max').innerText = max;
|
||||
document.getElementById('fps_avg').innerText = Math.round(sum*10)/10;
|
||||
var fpsb = document.querySelectorAll('.fps');
|
||||
fpsb[prev].innerHTML = lastfps;
|
||||
}
|
||||
prev = pos;
|
||||
var delay = parseInt(document.getElementById('secs').value)*1000;
|
||||
delay = Math.min(Math.max(delay, 2000), 15000)
|
||||
if (!command.stop) to = setTimeout(run,delay);
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
alert('Comms malfunction');
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
function csv(n) {
|
||||
var txt = "";
|
||||
for (let i = 0; i < fpslist.length; i++) {
|
||||
if (!n) txt += names_checked[i] + ',';
|
||||
txt += fpslist[i]; txt += "\n";
|
||||
}
|
||||
document.getElementById('csva').value = txt;
|
||||
var copyText = document.getElementById('csva');
|
||||
|
||||
copyText.select();
|
||||
copyText.setSelectionRange(0, 999999);
|
||||
document.execCommand("copy");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="S()">
|
||||
<h2>Starship monitoring dashboard</h2>
|
||||
(or rather just a WLED frame rate tester lol)<br><br>
|
||||
IP: <input id="ip" /><br>
|
||||
Time per effect: <input type=number id=secs value=5 max=15 min=2 />s<br>
|
||||
Effects to test:
|
||||
<button type="button" onclick="setC(255)">All</button>
|
||||
<button type="button" onclick="setC(1)">Selection 1</button>
|
||||
<button type="button" onclick="setC(0)">None</button>
|
||||
<button type="button" onclick="loadC()">Get LS</button>
|
||||
<button type="button" class="red" onclick="saveC()">Save to LS</button><br>
|
||||
Extra JSON: <input id="ej" /><br>
|
||||
|
||||
<button type="button" onclick="run(true)" id="runbtn">Fetch FX list</button><br>
|
||||
LEDs: <span id="leds">-</span>, Seg: <span id="seg">-</span>, Bri: <span id="bri">-</span><br>
|
||||
FPS min: <span id="fps_min">-</span>, max: <span id="fps_max">-</span>, avg: <span id="fps_avg">-</span><br><br>
|
||||
<div id="tablecon">
|
||||
</div><br>
|
||||
<button type="button" onclick="csv(false)">Copy csv to clipboard</button>
|
||||
<button type="button" onclick="csv(true)">Copy csv (FPS only)</button>
|
||||
<textarea id=csva></textarea>
|
||||
</body>
|
||||
</html>
|
||||
16
tools/multi-update.cmd
Normal file
16
tools/multi-update.cmd
Normal file
@@ -0,0 +1,16 @@
|
||||
@echo off
|
||||
SETLOCAL
|
||||
SET FWPATH=c:\path\to\your\WLED\build_output\firmware
|
||||
GOTO ESPS
|
||||
|
||||
:UPDATEONE
|
||||
IF NOT EXIST %FWPATH%\%2 GOTO SKIP
|
||||
ping -w 1000 -n 1 %1 | find "TTL=" || GOTO SKIP
|
||||
ECHO Updating %1
|
||||
curl -s -F "update=@%FWPATH%/%2" %1/update >nul
|
||||
:SKIP
|
||||
GOTO:EOF
|
||||
|
||||
:ESPS
|
||||
call :UPDATEONE 192.168.x.x firmware.bin
|
||||
call :UPDATEONE ....
|
||||
19
tools/multi-update.sh
Normal file
19
tools/multi-update.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
FWPATH=/path/to/your/WLED/build_output/firmware
|
||||
|
||||
update_one() {
|
||||
if [ -f $FWPATH/$2 ]; then
|
||||
ping -c 1 $1 >/dev/null
|
||||
PINGRESULT=$?
|
||||
if [ $PINGRESULT -eq 0 ]; then
|
||||
echo Updating $1
|
||||
curl -s -F "update=@${FWPATH}/$2" $1/update >/dev/null
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
update_one 192.168.x.x firmware.bin
|
||||
update_one 192.168.x.x firmware.bin
|
||||
# ...
|
||||
38
tools/stress_test.sh
Normal file
38
tools/stress_test.sh
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
# Some web server stress tests
|
||||
#
|
||||
# Perform a large number of parallel requests, stress testing the web server
|
||||
# TODO: some kind of performance metrics
|
||||
|
||||
# Accepts three command line arguments:
|
||||
# - first argument - mandatory - IP or hostname of target server
|
||||
# - second argument - target type (optional)
|
||||
# - third argument - xfer count (for replicated targets) (optional)
|
||||
HOST=$1
|
||||
declare -n TARGET_STR="${2:-JSON_LARGER}_TARGETS"
|
||||
REPLICATE_COUNT=$(("${3:-10}"))
|
||||
|
||||
PARALLEL_MAX=${PARALLEL_MAX:-50}
|
||||
|
||||
CURL_ARGS="--compressed --parallel --parallel-immediate --parallel-max ${PARALLEL_MAX}"
|
||||
CURL_PRINT_RESPONSE_ARGS="-w %{http_code}\n"
|
||||
|
||||
JSON_TARGETS=('json/state' 'json/info' 'json/si', 'json/palettes' 'json/fxdata' 'settings/s.js?p=2')
|
||||
FILE_TARGETS=('' 'iro.js' 'rangetouch.js' 'settings' 'settings/wifi')
|
||||
# Replicate one target many times
|
||||
function replicate() {
|
||||
printf "${1}?%d " $(seq 1 ${REPLICATE_COUNT})
|
||||
}
|
||||
read -a JSON_TINY_TARGETS <<< $(replicate "json/nodes")
|
||||
read -a JSON_SMALL_TARGETS <<< $(replicate "json/info")
|
||||
read -a JSON_LARGE_TARGETS <<< $(replicate "json/si")
|
||||
read -a JSON_LARGER_TARGETS <<< $(replicate "json/fxdata")
|
||||
read -a INDEX_TARGETS <<< $(replicate "")
|
||||
|
||||
# Expand target URLS to full arguments for curl
|
||||
TARGETS=(${TARGET_STR[@]})
|
||||
#echo "${TARGETS[@]}"
|
||||
FULL_TGT_OPTIONS=$(printf "http://${HOST}/%s -o /dev/null " "${TARGETS[@]}")
|
||||
#echo ${FULL_TGT_OPTIONS}
|
||||
|
||||
time curl ${CURL_ARGS} ${FULL_TGT_OPTIONS}
|
||||
46
tools/udp_test.py
Normal file
46
tools/udp_test.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import numpy as np
|
||||
import socket
|
||||
|
||||
class WledRealtimeClient:
|
||||
def __init__(self, wled_controller_ip, num_pixels, udp_port=21324, max_pixels_per_packet=126):
|
||||
self.wled_controller_ip = wled_controller_ip
|
||||
self.num_pixels = num_pixels
|
||||
self.udp_port = udp_port
|
||||
self.max_pixels_per_packet = max_pixels_per_packet
|
||||
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self._prev_pixels = np.full((3, self.num_pixels), 253, dtype=np.uint8)
|
||||
self.pixels = np.full((3, self.num_pixels), 1, dtype=np.uint8)
|
||||
|
||||
def update(self):
|
||||
# Truncate values and cast to integer
|
||||
self.pixels = np.clip(self.pixels, 0, 255).astype(np.uint8)
|
||||
p = np.copy(self.pixels)
|
||||
|
||||
idx = np.where(~np.all(p == self._prev_pixels, axis=0))[0]
|
||||
num_pixels = len(idx)
|
||||
n_packets = (num_pixels + self.max_pixels_per_packet - 1) // self.max_pixels_per_packet
|
||||
idx_split = np.array_split(idx, n_packets)
|
||||
|
||||
header = bytes([1, 2]) # WARLS protocol header
|
||||
for packet_indices in idx_split:
|
||||
data = bytearray(header)
|
||||
for i in packet_indices:
|
||||
data.extend([i, *p[:, i]]) # Index and RGB values
|
||||
self._sock.sendto(bytes(data), (self.wled_controller_ip, self.udp_port))
|
||||
|
||||
self._prev_pixels = np.copy(p)
|
||||
|
||||
|
||||
|
||||
################################## LED blink test ##################################
|
||||
if __name__ == "__main__":
|
||||
WLED_CONTROLLER_IP = "192.168.1.153"
|
||||
NUM_PIXELS = 255 # Amount of LEDs on your strip
|
||||
import time
|
||||
wled = WledRealtimeClient(WLED_CONTROLLER_IP, NUM_PIXELS)
|
||||
print('Starting LED blink test')
|
||||
while True:
|
||||
for i in range(NUM_PIXELS):
|
||||
wled.pixels[1, i] = 255 if wled.pixels[1, i] == 0 else 0
|
||||
wled.update()
|
||||
time.sleep(.01)
|
||||
329
tools/wled-tools
Executable file
329
tools/wled-tools
Executable file
@@ -0,0 +1,329 @@
|
||||
#!/bin/bash
|
||||
|
||||
# WLED Tools
|
||||
# A utility for managing WLED devices in a local network
|
||||
# https://github.com/wled/WLED
|
||||
|
||||
# Color Definitions
|
||||
GREEN="\e[32m"
|
||||
RED="\e[31m"
|
||||
BLUE="\e[34m"
|
||||
YELLOW="\e[33m"
|
||||
RESET="\e[0m"
|
||||
|
||||
# Logging function
|
||||
log() {
|
||||
local category="$1"
|
||||
local color="$2"
|
||||
local text="$3"
|
||||
|
||||
if [ "$quiet" = true ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -t 1 ]; then # Check if output is a terminal
|
||||
echo -e "${color}[${category}]${RESET} ${text}"
|
||||
else
|
||||
echo "[${category}] ${text}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Fetch a URL to a destination file, validating status codes.
|
||||
# Usage: fetch "<url>" "<dest or empty>" "200 404"
|
||||
fetch() {
|
||||
local url="$1"
|
||||
local dest="$2"
|
||||
local accepted="${3:-200}"
|
||||
|
||||
# If no dest given, just discard body
|
||||
local out
|
||||
if [ -n "$dest" ]; then
|
||||
# Write to ".tmp" files first, then move when success, to ensure we don't write partial files
|
||||
out="${dest}.tmp"
|
||||
else
|
||||
out="/dev/null"
|
||||
fi
|
||||
|
||||
response=$(curl --connect-timeout 5 --max-time 30 -s -w "%{http_code}" -o "$out" "$url")
|
||||
local curl_exit_code=$?
|
||||
|
||||
if [ $curl_exit_code -ne 0 ]; then
|
||||
[ -n "$dest" ] && rm -f "$out"
|
||||
log "ERROR" "$RED" "Connection error during request to $url (curl exit code: $curl_exit_code)."
|
||||
return 1
|
||||
fi
|
||||
|
||||
for code in $accepted; do
|
||||
if [ "$response" = "$code" ]; then
|
||||
# Accepted; only persist body for 2xx responses
|
||||
if [ -n "$dest" ]; then
|
||||
if [[ "$response" =~ ^2 ]]; then
|
||||
mv "$out" "$dest"
|
||||
else
|
||||
rm -f "$out"
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
# not accepted
|
||||
[ -n "$dest" ] && rm -f "$out"
|
||||
log "ERROR" "$RED" "Unexpected response from $url (HTTP $response)."
|
||||
return 2
|
||||
}
|
||||
|
||||
|
||||
# POST a file to a URL, validating status codes.
|
||||
# Usage: post_file "<url>" "<file>" "200"
|
||||
post_file() {
|
||||
local url="$1"
|
||||
local file="$2"
|
||||
local accepted="${3:-200}"
|
||||
|
||||
response=$(curl --connect-timeout 5 --max-time 300 -s -w "%{http_code}" -o /dev/null -X POST -F "file=@$file" "$url")
|
||||
local curl_exit_code=$?
|
||||
|
||||
if [ $curl_exit_code -ne 0 ]; then
|
||||
log "ERROR" "$RED" "Connection error during POST to $url (curl exit code: $curl_exit_code)."
|
||||
return 1
|
||||
fi
|
||||
|
||||
for code in $accepted; do
|
||||
if [ "$response" -eq "$code" ]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
log "ERROR" "$RED" "Unexpected response from $url (HTTP $response)."
|
||||
return 2
|
||||
}
|
||||
|
||||
|
||||
# Print help message
|
||||
show_help() {
|
||||
cat << EOF
|
||||
Usage: wled-tools.sh [OPTIONS] COMMAND [ARGS...]
|
||||
|
||||
Options:
|
||||
-h, --help Show this help message and exit.
|
||||
-t, --target <IP/Host> Specify a single WLED device by IP address or hostname.
|
||||
-D, --discover Discover multiple WLED devices using mDNS.
|
||||
-d, --directory <Path> Specify a directory for saving backups (default: working directory).
|
||||
-f, --firmware <File> Specify the firmware file for updating devices.
|
||||
-q, --quiet Suppress logging output (also makes discover output hostnames only).
|
||||
|
||||
Commands:
|
||||
backup Backup the current state of a WLED device or multiple discovered devices.
|
||||
update Update the firmware of a WLED device or multiple discovered devices.
|
||||
discover Discover WLED devices using mDNS and list their IP addresses and names.
|
||||
|
||||
Examples:
|
||||
# Discover all WLED devices on the network
|
||||
./wled-tools discover
|
||||
|
||||
# Backup a specific WLED device
|
||||
./wled-tools -t 192.168.1.100 backup
|
||||
|
||||
# Backup all discovered WLED devices to a specific directory
|
||||
./wled-tools -D -d /path/to/backups backup
|
||||
|
||||
# Update firmware on all discovered WLED devices
|
||||
./wled-tools -D -f /path/to/firmware.bin update
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# Discover devices using mDNS
|
||||
discover_devices() {
|
||||
if ! command -v avahi-browse &> /dev/null; then
|
||||
log "ERROR" "$RED" "'avahi-browse' is required but not installed, please install avahi-utils using your preferred package manager."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Map avahi responses to strings seperated by 0x1F (unit separator)
|
||||
mapfile -t raw_devices < <(avahi-browse _wled._tcp --terminate -r -p | awk -F';' '/^=/ {print $7"\x1F"$8"\x1F"$9}')
|
||||
|
||||
local devices_array=()
|
||||
for device in "${raw_devices[@]}"; do
|
||||
IFS=$'\x1F' read -r hostname address port <<< "$device"
|
||||
devices_array+=("$hostname" "$address" "$port")
|
||||
done
|
||||
|
||||
echo "${devices_array[@]}"
|
||||
}
|
||||
|
||||
# Backup one device
|
||||
backup_one() {
|
||||
local hostname="$1"
|
||||
local address="$2"
|
||||
local port="$3"
|
||||
|
||||
log "INFO" "$YELLOW" "Backing up device config/presets/ir: $hostname ($address:$port)"
|
||||
|
||||
mkdir -p "$backup_dir"
|
||||
|
||||
local file_prefix="${backup_dir}/${hostname}"
|
||||
|
||||
if ! fetch "http://$address:$port/cfg.json" "${file_prefix}.cfg.json"; then
|
||||
log "ERROR" "$RED" "Failed to backup configuration for $hostname"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! fetch "http://$address:$port/presets.json" "${file_prefix}.presets.json"; then
|
||||
log "ERROR" "$RED" "Failed to backup presets for $hostname"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# ir.json is optional
|
||||
if ! fetch "http://$address:$port/ir.json" "${file_prefix}.ir.json" "200 404"; then
|
||||
log "ERROR" "$RED" "Failed to backup ir configs for $hostname"
|
||||
fi
|
||||
|
||||
log "INFO" "$GREEN" "Successfully backed up config and presets for $hostname"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Update one device
|
||||
update_one() {
|
||||
local hostname="$1"
|
||||
local address="$2"
|
||||
local port="$3"
|
||||
local firmware="$4"
|
||||
|
||||
log "INFO" "$YELLOW" "Starting firmware update for device: $hostname ($address:$port)"
|
||||
|
||||
local url="http://$address:$port/update"
|
||||
|
||||
if ! post_file "$url" "$firmware" "200"; then
|
||||
log "ERROR" "$RED" "Failed to update firmware for $hostname"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log "INFO" "$GREEN" "Successfully initiated firmware update for $hostname"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Command-line arguments processing
|
||||
command=""
|
||||
target=""
|
||||
discover=false
|
||||
quiet=false
|
||||
backup_dir="./"
|
||||
firmware_file=""
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
show_help
|
||||
exit 0
|
||||
fi
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-t|--target)
|
||||
if [ -z "$2" ] || [[ "$2" == -* ]]; then
|
||||
log "ERROR" "$RED" "The --target option requires an argument."
|
||||
exit 1
|
||||
fi
|
||||
target="$2"
|
||||
shift 2
|
||||
;;
|
||||
-D|--discover)
|
||||
discover=true
|
||||
shift
|
||||
;;
|
||||
-d|--directory)
|
||||
if [ -z "$2" ] || [[ "$2" == -* ]]; then
|
||||
log "ERROR" "$RED" "The --directory option requires an argument."
|
||||
exit 1
|
||||
fi
|
||||
backup_dir="$2"
|
||||
shift 2
|
||||
;;
|
||||
-f|--firmware)
|
||||
if [ -z "$2" ] || [[ "$2" == -* ]]; then
|
||||
log "ERROR" "$RED" "The --firmware option requires an argument."
|
||||
exit 1
|
||||
fi
|
||||
firmware_file="$2"
|
||||
shift 2
|
||||
;;
|
||||
-q|--quiet)
|
||||
quiet=true
|
||||
shift
|
||||
;;
|
||||
backup|update|discover)
|
||||
command="$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
log "ERROR" "$RED" "Unknown argument: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Execute the appropriate command
|
||||
case "$command" in
|
||||
discover)
|
||||
read -ra devices <<< "$(discover_devices)"
|
||||
for ((i=0; i<${#devices[@]}; i+=3)); do
|
||||
hostname="${devices[$i]}"
|
||||
address="${devices[$i+1]}"
|
||||
port="${devices[$i+2]}"
|
||||
|
||||
if [ "$quiet" = true ]; then
|
||||
echo "$hostname"
|
||||
else
|
||||
log "INFO" "$BLUE" "Discovered device: Hostname=$hostname, Address=$address, Port=$port"
|
||||
fi
|
||||
done
|
||||
;;
|
||||
backup)
|
||||
if [ -n "$target" ]; then
|
||||
# Assume target is both the hostname and address, with port 80
|
||||
backup_one "$target" "$target" "80"
|
||||
elif [ "$discover" = true ]; then
|
||||
read -ra devices <<< "$(discover_devices)"
|
||||
for ((i=0; i<${#devices[@]}; i+=3)); do
|
||||
hostname="${devices[$i]}"
|
||||
address="${devices[$i+1]}"
|
||||
port="${devices[$i+2]}"
|
||||
backup_one "$hostname" "$address" "$port"
|
||||
done
|
||||
else
|
||||
log "ERROR" "$RED" "No target specified. Use --target or --discover."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
update)
|
||||
# Validate firmware before proceeding
|
||||
if [ -z "$firmware_file" ] || [ ! -f "$firmware_file" ]; then
|
||||
log "ERROR" "$RED" "Please provide a file in --firmware that exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$target" ]; then
|
||||
# Assume target is both the hostname and address, with port 80
|
||||
update_one "$target" "$target" "80" "$firmware_file"
|
||||
elif [ "$discover" = true ]; then
|
||||
read -ra devices <<< "$(discover_devices)"
|
||||
for ((i=0; i<${#devices[@]}; i+=3)); do
|
||||
hostname="${devices[$i]}"
|
||||
address="${devices[$i+1]}"
|
||||
port="${devices[$i+2]}"
|
||||
update_one "$hostname" "$address" "$port" "$firmware_file"
|
||||
done
|
||||
else
|
||||
log "ERROR" "$RED" "No target specified. Use --target or --discover."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
256
usermods/ADS1115_v2/ADS1115_v2.cpp
Normal file
256
usermods/ADS1115_v2/ADS1115_v2.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
#include "wled.h"
|
||||
#include <Adafruit_ADS1X15.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "ChannelSettings.h"
|
||||
|
||||
using namespace ADS1115;
|
||||
|
||||
class ADS1115Usermod : public Usermod {
|
||||
public:
|
||||
void setup() {
|
||||
ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V
|
||||
|
||||
if (!ads.begin()) {
|
||||
Serial.println("Failed to initialize ADS");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!initChannel()) {
|
||||
isInitialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
startReading();
|
||||
|
||||
isEnabled = true;
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (isEnabled && millis() - lastTime > loopInterval) {
|
||||
lastTime = millis();
|
||||
|
||||
// If we don't have new data, skip this iteration.
|
||||
if (!ads.conversionComplete()) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateResult();
|
||||
moveToNextChannel();
|
||||
startReading();
|
||||
}
|
||||
}
|
||||
|
||||
void addToJsonInfo(JsonObject& root)
|
||||
{
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject user = root[F("u")];
|
||||
if (user.isNull()) user = root.createNestedObject(F("u"));
|
||||
|
||||
for (uint8_t i = 0; i < channelsCount; i++) {
|
||||
ChannelSettings* settingsPtr = &(channelSettings[i]);
|
||||
|
||||
if (!settingsPtr->isEnabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonArray lightArr = user.createNestedArray(settingsPtr->name); //name
|
||||
float value = round((readings[i] + settingsPtr->offset) * settingsPtr->multiplier, settingsPtr->decimals);
|
||||
lightArr.add(value); //value
|
||||
lightArr.add(" " + settingsPtr->units); //unit
|
||||
}
|
||||
}
|
||||
|
||||
void addToConfig(JsonObject& root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject(F("ADC ADS1115"));
|
||||
|
||||
for (uint8_t i = 0; i < channelsCount; i++) {
|
||||
ChannelSettings* settingsPtr = &(channelSettings[i]);
|
||||
JsonObject channel = top.createNestedObject(settingsPtr->settingName);
|
||||
channel[F("Enabled")] = settingsPtr->isEnabled;
|
||||
channel[F("Name")] = settingsPtr->name;
|
||||
channel[F("Units")] = settingsPtr->units;
|
||||
channel[F("Multiplier")] = settingsPtr->multiplier;
|
||||
channel[F("Offset")] = settingsPtr->offset;
|
||||
channel[F("Decimals")] = settingsPtr->decimals;
|
||||
}
|
||||
|
||||
top[F("Loop Interval")] = loopInterval;
|
||||
}
|
||||
|
||||
bool readFromConfig(JsonObject& root)
|
||||
{
|
||||
JsonObject top = root[F("ADC ADS1115")];
|
||||
|
||||
bool configComplete = !top.isNull();
|
||||
bool hasEnabledChannels = false;
|
||||
|
||||
for (uint8_t i = 0; i < channelsCount && configComplete; i++) {
|
||||
ChannelSettings* settingsPtr = &(channelSettings[i]);
|
||||
JsonObject channel = top[settingsPtr->settingName];
|
||||
|
||||
configComplete &= !channel.isNull();
|
||||
|
||||
configComplete &= getJsonValue(channel[F("Enabled")], settingsPtr->isEnabled);
|
||||
configComplete &= getJsonValue(channel[F("Name")], settingsPtr->name);
|
||||
configComplete &= getJsonValue(channel[F("Units")], settingsPtr->units);
|
||||
configComplete &= getJsonValue(channel[F("Multiplier")], settingsPtr->multiplier);
|
||||
configComplete &= getJsonValue(channel[F("Offset")], settingsPtr->offset);
|
||||
configComplete &= getJsonValue(channel[F("Decimals")], settingsPtr->decimals);
|
||||
|
||||
hasEnabledChannels |= settingsPtr->isEnabled;
|
||||
}
|
||||
|
||||
configComplete &= getJsonValue(top[F("Loop Interval")], loopInterval);
|
||||
|
||||
isEnabled = isInitialized && configComplete && hasEnabledChannels;
|
||||
|
||||
return configComplete;
|
||||
}
|
||||
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_ADS1115;
|
||||
}
|
||||
|
||||
private:
|
||||
static const uint8_t channelsCount = 8;
|
||||
|
||||
ChannelSettings channelSettings[channelsCount] = {
|
||||
{
|
||||
"Differential reading from AIN0 (P) and AIN1 (N)",
|
||||
false,
|
||||
"Differential AIN0 AIN1",
|
||||
"V",
|
||||
ADS1X15_REG_CONFIG_MUX_DIFF_0_1,
|
||||
1,
|
||||
0,
|
||||
3
|
||||
},
|
||||
{
|
||||
"Differential reading from AIN0 (P) and AIN3 (N)",
|
||||
false,
|
||||
"Differential AIN0 AIN3",
|
||||
"V",
|
||||
ADS1X15_REG_CONFIG_MUX_DIFF_0_3,
|
||||
1,
|
||||
0,
|
||||
3
|
||||
},
|
||||
{
|
||||
"Differential reading from AIN1 (P) and AIN3 (N)",
|
||||
false,
|
||||
"Differential AIN1 AIN3",
|
||||
"V",
|
||||
ADS1X15_REG_CONFIG_MUX_DIFF_1_3,
|
||||
1,
|
||||
0,
|
||||
3
|
||||
},
|
||||
{
|
||||
"Differential reading from AIN2 (P) and AIN3 (N)",
|
||||
false,
|
||||
"Differential AIN2 AIN3",
|
||||
"V",
|
||||
ADS1X15_REG_CONFIG_MUX_DIFF_2_3,
|
||||
1,
|
||||
0,
|
||||
3
|
||||
},
|
||||
{
|
||||
"Single-ended reading from AIN0",
|
||||
false,
|
||||
"Single-ended AIN0",
|
||||
"V",
|
||||
ADS1X15_REG_CONFIG_MUX_SINGLE_0,
|
||||
1,
|
||||
0,
|
||||
3
|
||||
},
|
||||
{
|
||||
"Single-ended reading from AIN1",
|
||||
false,
|
||||
"Single-ended AIN1",
|
||||
"V",
|
||||
ADS1X15_REG_CONFIG_MUX_SINGLE_1,
|
||||
1,
|
||||
0,
|
||||
3
|
||||
},
|
||||
{
|
||||
"Single-ended reading from AIN2",
|
||||
false,
|
||||
"Single-ended AIN2",
|
||||
"V",
|
||||
ADS1X15_REG_CONFIG_MUX_SINGLE_2,
|
||||
1,
|
||||
0,
|
||||
3
|
||||
},
|
||||
{
|
||||
"Single-ended reading from AIN3",
|
||||
false,
|
||||
"Single-ended AIN3",
|
||||
"V",
|
||||
ADS1X15_REG_CONFIG_MUX_SINGLE_3,
|
||||
1,
|
||||
0,
|
||||
3
|
||||
},
|
||||
};
|
||||
float readings[channelsCount] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
unsigned long loopInterval = 1000;
|
||||
unsigned long lastTime = 0;
|
||||
|
||||
Adafruit_ADS1115 ads;
|
||||
uint8_t activeChannel;
|
||||
|
||||
bool isEnabled = false;
|
||||
bool isInitialized = false;
|
||||
|
||||
static float round(float value, uint8_t decimals) {
|
||||
return roundf(value * powf(10, decimals)) / powf(10, decimals);
|
||||
}
|
||||
|
||||
bool initChannel() {
|
||||
for (uint8_t i = 0; i < channelsCount; i++) {
|
||||
if (channelSettings[i].isEnabled) {
|
||||
activeChannel = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
activeChannel = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
void moveToNextChannel() {
|
||||
uint8_t oldActiveChannel = activeChannel;
|
||||
|
||||
do
|
||||
{
|
||||
if (++activeChannel >= channelsCount){
|
||||
activeChannel = 0;
|
||||
}
|
||||
}
|
||||
while (!channelSettings[activeChannel].isEnabled && oldActiveChannel != activeChannel);
|
||||
}
|
||||
|
||||
void startReading() {
|
||||
ads.startADCReading(channelSettings[activeChannel].mux, /*continuous=*/false);
|
||||
}
|
||||
|
||||
void updateResult() {
|
||||
int16_t results = ads.getLastConversionResults();
|
||||
readings[activeChannel] = ads.computeVolts(results);
|
||||
}
|
||||
};
|
||||
|
||||
static ADS1115Usermod ads1115_v2;
|
||||
REGISTER_USERMOD(ads1115_v2);
|
||||
15
usermods/ADS1115_v2/ChannelSettings.h
Normal file
15
usermods/ADS1115_v2/ChannelSettings.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "wled.h"
|
||||
|
||||
namespace ADS1115
|
||||
{
|
||||
struct ChannelSettings {
|
||||
const String settingName;
|
||||
bool isEnabled;
|
||||
String name;
|
||||
String units;
|
||||
const uint16_t mux;
|
||||
float multiplier;
|
||||
float offset;
|
||||
uint8_t decimals;
|
||||
};
|
||||
}
|
||||
8
usermods/ADS1115_v2/library.json
Normal file
8
usermods/ADS1115_v2/library.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "ADS1115_v2",
|
||||
"build": { "libArchive": false },
|
||||
"dependencies": {
|
||||
"Adafruit BusIO": "https://github.com/adafruit/Adafruit_BusIO#1.13.2",
|
||||
"Adafruit ADS1X15": "https://github.com/adafruit/Adafruit_ADS1X15#2.4.0"
|
||||
}
|
||||
}
|
||||
10
usermods/ADS1115_v2/readme.md
Normal file
10
usermods/ADS1115_v2/readme.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# ADS1115 16-Bit ADC with four inputs
|
||||
|
||||
This usermod will read from an ADS1115 ADC. The voltages are displayed in the Info section of the web UI.
|
||||
|
||||
Configuration is performed via the Usermod menu. There are no parameters to set in code!
|
||||
|
||||
## Installation
|
||||
|
||||
Add 'ADS1115' to `custom_usermods` in your platformio environment.
|
||||
|
||||
328
usermods/AHT10_v2/AHT10_v2.cpp
Normal file
328
usermods/AHT10_v2/AHT10_v2.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
#include "wled.h"
|
||||
#include <AHT10.h>
|
||||
|
||||
#define AHT10_SUCCESS 1
|
||||
|
||||
class UsermodAHT10 : public Usermod
|
||||
{
|
||||
private:
|
||||
static const char _name[];
|
||||
|
||||
unsigned long _lastLoopCheck = 0;
|
||||
|
||||
bool _settingEnabled : 1; // Enable the usermod
|
||||
bool _mqttPublish : 1; // Publish mqtt values
|
||||
bool _mqttPublishAlways : 1; // Publish always, regardless if there is a change
|
||||
bool _mqttHomeAssistant : 1; // Enable Home Assistant docs
|
||||
bool _initDone : 1; // Initialization is done
|
||||
|
||||
// Settings. Some of these are stored in a different format than they're user settings - so we don't have to convert at runtime
|
||||
uint8_t _i2cAddress = AHT10_ADDRESS_0X38;
|
||||
ASAIR_I2C_SENSOR _ahtType = AHT10_SENSOR;
|
||||
uint16_t _checkInterval = 60000; // milliseconds, user settings is in seconds
|
||||
float _decimalFactor = 100; // a power of 10 factor. 1 would be no change, 10 is one decimal, 100 is two etc. User sees a power of 10 (0, 1, 2, ..)
|
||||
|
||||
uint8_t _lastStatus = 0;
|
||||
float _lastHumidity = 0;
|
||||
float _lastTemperature = 0;
|
||||
|
||||
#ifndef WLED_MQTT_DISABLE
|
||||
float _lastHumiditySent = 0;
|
||||
float _lastTemperatureSent = 0;
|
||||
#endif
|
||||
|
||||
AHT10 *_aht = nullptr;
|
||||
|
||||
float truncateDecimals(float val)
|
||||
{
|
||||
return roundf(val * _decimalFactor) / _decimalFactor;
|
||||
}
|
||||
|
||||
void initializeAht()
|
||||
{
|
||||
if (_aht != nullptr)
|
||||
{
|
||||
delete _aht;
|
||||
}
|
||||
|
||||
_aht = new AHT10(_i2cAddress, _ahtType);
|
||||
|
||||
_lastStatus = 0;
|
||||
_lastHumidity = 0;
|
||||
_lastTemperature = 0;
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
void mqttInitialize()
|
||||
{
|
||||
// This is a generic "setup mqtt" function, So we must abort if we're not to do mqtt
|
||||
if (!WLED_MQTT_CONNECTED || !_mqttPublish || !_mqttHomeAssistant)
|
||||
return;
|
||||
|
||||
char topic[128];
|
||||
snprintf_P(topic, 127, "%s/temperature", mqttDeviceTopic);
|
||||
mqttCreateHassSensor(F("Temperature"), topic, F("temperature"), F("°C"));
|
||||
|
||||
snprintf_P(topic, 127, "%s/humidity", mqttDeviceTopic);
|
||||
mqttCreateHassSensor(F("Humidity"), topic, F("humidity"), F("%"));
|
||||
}
|
||||
|
||||
void mqttPublishIfChanged(const __FlashStringHelper *topic, float &lastState, float state, float minChange)
|
||||
{
|
||||
// Check if MQTT Connected, otherwise it will crash the 8266
|
||||
// Only report if the change is larger than the required diff
|
||||
if (WLED_MQTT_CONNECTED && _mqttPublish && (_mqttPublishAlways || fabsf(lastState - state) > minChange))
|
||||
{
|
||||
char subuf[128];
|
||||
snprintf_P(subuf, 127, PSTR("%s/%s"), mqttDeviceTopic, (const char *)topic);
|
||||
mqtt->publish(subuf, 0, false, String(state).c_str());
|
||||
|
||||
lastState = state;
|
||||
}
|
||||
}
|
||||
|
||||
// Create an MQTT Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
|
||||
void mqttCreateHassSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement)
|
||||
{
|
||||
String t = String(F("homeassistant/sensor/")) + mqttClientID + "/" + name + F("/config");
|
||||
|
||||
StaticJsonDocument<600> doc;
|
||||
|
||||
doc[F("name")] = name;
|
||||
doc[F("state_topic")] = topic;
|
||||
doc[F("unique_id")] = String(mqttClientID) + name;
|
||||
if (unitOfMeasurement != "")
|
||||
doc[F("unit_of_measurement")] = unitOfMeasurement;
|
||||
if (deviceClass != "")
|
||||
doc[F("device_class")] = deviceClass;
|
||||
doc[F("expire_after")] = 1800;
|
||||
|
||||
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
|
||||
device[F("name")] = serverDescription;
|
||||
device[F("identifiers")] = "wled-sensor-" + String(mqttClientID);
|
||||
device[F("manufacturer")] = F(WLED_BRAND);
|
||||
device[F("model")] = F(WLED_PRODUCT_NAME);
|
||||
device[F("sw_version")] = versionString;
|
||||
|
||||
String temp;
|
||||
serializeJson(doc, temp);
|
||||
DEBUG_PRINTLN(t);
|
||||
DEBUG_PRINTLN(temp);
|
||||
|
||||
mqtt->publish(t.c_str(), 0, true, temp.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
void setup()
|
||||
{
|
||||
initializeAht();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// if usermod is disabled or called during strip updating just exit
|
||||
// NOTE: on very long strips strip.isUpdating() may always return true so update accordingly
|
||||
if (!_settingEnabled || strip.isUpdating())
|
||||
return;
|
||||
|
||||
// do your magic here
|
||||
unsigned long currentTime = millis();
|
||||
|
||||
if (currentTime - _lastLoopCheck < _checkInterval)
|
||||
return;
|
||||
_lastLoopCheck = currentTime;
|
||||
|
||||
_lastStatus = _aht->readRawData();
|
||||
|
||||
if (_lastStatus == AHT10_ERROR)
|
||||
{
|
||||
// Perform softReset and retry
|
||||
DEBUG_PRINTLN(F("AHTxx returned error, doing softReset"));
|
||||
if (!_aht->softReset())
|
||||
{
|
||||
DEBUG_PRINTLN(F("softReset failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
_lastStatus = _aht->readRawData();
|
||||
}
|
||||
|
||||
if (_lastStatus == AHT10_SUCCESS)
|
||||
{
|
||||
float temperature = truncateDecimals(_aht->readTemperature(AHT10_USE_READ_DATA));
|
||||
float humidity = truncateDecimals(_aht->readHumidity(AHT10_USE_READ_DATA));
|
||||
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
// Push to MQTT
|
||||
|
||||
// We can avoid reporting if the change is insignificant. The threshold chosen is below the level of accuracy, but way above 0.01 which is the precision of the value provided.
|
||||
// The AHT10/15/20 has an accuracy of 0.3C in the temperature readings
|
||||
mqttPublishIfChanged(F("temperature"), _lastTemperatureSent, temperature, 0.1f);
|
||||
|
||||
// The AHT10/15/20 has an accuracy in the humidity sensor of 2%
|
||||
mqttPublishIfChanged(F("humidity"), _lastHumiditySent, humidity, 0.5f);
|
||||
#endif
|
||||
|
||||
// Store
|
||||
_lastTemperature = temperature;
|
||||
_lastHumidity = humidity;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
void onMqttConnect(bool sessionPresent)
|
||||
{
|
||||
mqttInitialize();
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_AHT10;
|
||||
}
|
||||
|
||||
void addToJsonInfo(JsonObject &root) override
|
||||
{
|
||||
// if "u" object does not exist yet wee need to create it
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull())
|
||||
user = root.createNestedObject("u");
|
||||
|
||||
#ifdef USERMOD_AHT10_DEBUG
|
||||
JsonArray temp = user.createNestedArray(F("AHT last loop"));
|
||||
temp.add(_lastLoopCheck);
|
||||
|
||||
temp = user.createNestedArray(F("AHT last status"));
|
||||
temp.add(_lastStatus);
|
||||
#endif
|
||||
|
||||
JsonArray jsonTemp = user.createNestedArray(F("Temperature"));
|
||||
JsonArray jsonHumidity = user.createNestedArray(F("Humidity"));
|
||||
|
||||
if (_lastLoopCheck == 0)
|
||||
{
|
||||
// Before first run
|
||||
jsonTemp.add(F("Not read yet"));
|
||||
jsonHumidity.add(F("Not read yet"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_lastStatus != AHT10_SUCCESS)
|
||||
{
|
||||
jsonTemp.add(F("An error occurred"));
|
||||
jsonHumidity.add(F("An error occurred"));
|
||||
return;
|
||||
}
|
||||
|
||||
jsonTemp.add(_lastTemperature);
|
||||
jsonTemp.add(F("°C"));
|
||||
|
||||
jsonHumidity.add(_lastHumidity);
|
||||
jsonHumidity.add(F("%"));
|
||||
}
|
||||
|
||||
void addToConfig(JsonObject &root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||
top[F("Enabled")] = _settingEnabled;
|
||||
top[F("I2CAddress")] = static_cast<uint8_t>(_i2cAddress);
|
||||
top[F("SensorType")] = _ahtType;
|
||||
top[F("CheckInterval")] = _checkInterval / 1000;
|
||||
top[F("Decimals")] = log10f(_decimalFactor);
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
top[F("MqttPublish")] = _mqttPublish;
|
||||
top[F("MqttPublishAlways")] = _mqttPublishAlways;
|
||||
top[F("MqttHomeAssistantDiscovery")] = _mqttHomeAssistant;
|
||||
#endif
|
||||
|
||||
DEBUG_PRINTLN(F("AHT10 config saved."));
|
||||
}
|
||||
|
||||
bool readFromConfig(JsonObject &root) override
|
||||
{
|
||||
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
||||
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
|
||||
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
|
||||
bool configComplete = !top.isNull();
|
||||
if (!configComplete)
|
||||
return false;
|
||||
|
||||
bool tmpBool = false;
|
||||
configComplete &= getJsonValue(top[F("Enabled")], tmpBool);
|
||||
if (configComplete)
|
||||
_settingEnabled = tmpBool;
|
||||
|
||||
configComplete &= getJsonValue(top[F("I2CAddress")], _i2cAddress);
|
||||
configComplete &= getJsonValue(top[F("CheckInterval")], _checkInterval);
|
||||
if (configComplete)
|
||||
{
|
||||
if (1 <= _checkInterval && _checkInterval <= 600)
|
||||
_checkInterval *= 1000;
|
||||
else
|
||||
// Invalid input
|
||||
_checkInterval = 60000;
|
||||
}
|
||||
|
||||
configComplete &= getJsonValue(top[F("Decimals")], _decimalFactor);
|
||||
if (configComplete)
|
||||
{
|
||||
if (0 <= _decimalFactor && _decimalFactor <= 5)
|
||||
_decimalFactor = pow10f(_decimalFactor);
|
||||
else
|
||||
// Invalid input
|
||||
_decimalFactor = 100;
|
||||
}
|
||||
|
||||
uint8_t tmpAhtType;
|
||||
configComplete &= getJsonValue(top[F("SensorType")], tmpAhtType);
|
||||
if (configComplete)
|
||||
{
|
||||
if (0 <= tmpAhtType && tmpAhtType <= 2)
|
||||
_ahtType = static_cast<ASAIR_I2C_SENSOR>(tmpAhtType);
|
||||
else
|
||||
// Invalid input
|
||||
_ahtType = ASAIR_I2C_SENSOR::AHT10_SENSOR;
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
configComplete &= getJsonValue(top[F("MqttPublish")], tmpBool);
|
||||
if (configComplete)
|
||||
_mqttPublish = tmpBool;
|
||||
|
||||
configComplete &= getJsonValue(top[F("MqttPublishAlways")], tmpBool);
|
||||
if (configComplete)
|
||||
_mqttPublishAlways = tmpBool;
|
||||
|
||||
configComplete &= getJsonValue(top[F("MqttHomeAssistantDiscovery")], tmpBool);
|
||||
if (configComplete)
|
||||
_mqttHomeAssistant = tmpBool;
|
||||
#endif
|
||||
|
||||
if (_initDone)
|
||||
{
|
||||
// Reloading config
|
||||
initializeAht();
|
||||
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
mqttInitialize();
|
||||
#endif
|
||||
}
|
||||
|
||||
_initDone = true;
|
||||
return configComplete;
|
||||
}
|
||||
|
||||
~UsermodAHT10()
|
||||
{
|
||||
delete _aht;
|
||||
_aht = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
const char UsermodAHT10::_name[] PROGMEM = "AHTxx";
|
||||
|
||||
static UsermodAHT10 aht10_v2;
|
||||
REGISTER_USERMOD(aht10_v2);
|
||||
30
usermods/AHT10_v2/README.md
Normal file
30
usermods/AHT10_v2/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Usermod AHT10
|
||||
This Usermod is designed to read a `AHT10`, `AHT15` or `AHT20` sensor and output the following:
|
||||
- Temperature
|
||||
- Humidity
|
||||
|
||||
Configuration is performed via the Usermod menu. The following settings can be configured in the Usermod Menu:
|
||||
- I2CAddress: The i2c address in decimal. Set it to either 56 (0x38, the default) or 57 (0x39).
|
||||
- SensorType, one of:
|
||||
- 0 - AHT10
|
||||
- 1 - AHT15
|
||||
- 2 - AHT20
|
||||
- CheckInterval: Number of seconds between readings
|
||||
- Decimals: Number of decimals to put in the output
|
||||
|
||||
Dependencies, These must be added under `lib_deps` in your `platform.ini` (or `platform_override.ini`).
|
||||
- Libraries
|
||||
- `enjoyneering/AHT10@~1.1.0` (by [enjoyneering](https://registry.platformio.org/libraries/enjoyneering/AHT10))
|
||||
- `Wire`
|
||||
|
||||
## Author
|
||||
[@LordMike](https://github.com/LordMike)
|
||||
|
||||
# Compiling
|
||||
|
||||
To enable, add 'AHT10' to `custom_usermods` in your platformio encrionment (e.g. in `platformio_override.ini`)
|
||||
```ini
|
||||
[env:aht10_example]
|
||||
extends = env:esp32dev
|
||||
custom_usermods = ${env:esp32dev.custom_usermods} AHT10
|
||||
```
|
||||
7
usermods/AHT10_v2/library.json
Normal file
7
usermods/AHT10_v2/library.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "AHT10_v2",
|
||||
"build": { "libArchive": false },
|
||||
"dependencies": {
|
||||
"enjoyneering/AHT10":"~1.1.0"
|
||||
}
|
||||
}
|
||||
5
usermods/AHT10_v2/platformio_override.ini
Normal file
5
usermods/AHT10_v2/platformio_override.ini
Normal file
@@ -0,0 +1,5 @@
|
||||
[env:aht10_example]
|
||||
extends = env:esp32dev
|
||||
build_flags =
|
||||
${common.build_flags} ${esp32.build_flags}
|
||||
; -D USERMOD_AHT10_DEBUG ; -- add a debug status to the info modal
|
||||
259
usermods/Analog_Clock/Analog_Clock.cpp
Normal file
259
usermods/Analog_Clock/Analog_Clock.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Usermod for analog clock
|
||||
*/
|
||||
extern Timezone* tz;
|
||||
|
||||
class AnalogClockUsermod : public Usermod {
|
||||
private:
|
||||
static constexpr uint32_t refreshRate = 50; // per second
|
||||
static constexpr uint32_t refreshDelay = 1000 / refreshRate;
|
||||
|
||||
struct Segment {
|
||||
// config
|
||||
int16_t firstLed = 0;
|
||||
int16_t lastLed = 59;
|
||||
int16_t centerLed = 0;
|
||||
|
||||
// runtime
|
||||
int16_t size;
|
||||
|
||||
Segment() {
|
||||
update();
|
||||
}
|
||||
|
||||
void validateAndUpdate() {
|
||||
if (firstLed < 0 || firstLed >= strip.getLengthTotal() ||
|
||||
lastLed < firstLed || lastLed >= strip.getLengthTotal()) {
|
||||
*this = {};
|
||||
return;
|
||||
}
|
||||
if (centerLed < firstLed || centerLed > lastLed) {
|
||||
centerLed = firstLed;
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void update() {
|
||||
size = lastLed - firstLed + 1;
|
||||
}
|
||||
};
|
||||
|
||||
// configuration (available in API and stored in flash)
|
||||
bool enabled = false;
|
||||
Segment mainSegment;
|
||||
bool hourMarksEnabled = true;
|
||||
uint32_t hourMarkColor = 0xFF0000;
|
||||
uint32_t hourColor = 0x0000FF;
|
||||
uint32_t minuteColor = 0x00FF00;
|
||||
bool secondsEnabled = true;
|
||||
Segment secondsSegment;
|
||||
uint32_t secondColor = 0xFF0000;
|
||||
bool blendColors = true;
|
||||
uint16_t secondsEffect = 0;
|
||||
|
||||
// runtime
|
||||
bool initDone = false;
|
||||
uint32_t lastOverlayDraw = 0;
|
||||
|
||||
void validateAndUpdate() {
|
||||
mainSegment.validateAndUpdate();
|
||||
secondsSegment.validateAndUpdate();
|
||||
if (secondsEffect < 0 || secondsEffect > 1) {
|
||||
secondsEffect = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t adjustToSegment(double progress, Segment const& segment) {
|
||||
int16_t led = segment.centerLed + progress * segment.size;
|
||||
return led > segment.lastLed
|
||||
? segment.firstLed + led - segment.lastLed - 1
|
||||
: led;
|
||||
}
|
||||
|
||||
void setPixelColor(uint16_t n, uint32_t c) {
|
||||
if (!blendColors) {
|
||||
strip.setPixelColor(n, c);
|
||||
} else {
|
||||
uint32_t oldC = strip.getPixelColor(n);
|
||||
strip.setPixelColor(n, qadd32(oldC, c));
|
||||
}
|
||||
}
|
||||
|
||||
String colorToHexString(uint32_t c) {
|
||||
char buffer[9];
|
||||
sprintf(buffer, "%06X", c);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool hexStringToColor(String const& s, uint32_t& c, uint32_t def) {
|
||||
char *ep;
|
||||
unsigned long long r = strtoull(s.c_str(), &ep, 16);
|
||||
if (*ep == 0) {
|
||||
c = r;
|
||||
return true;
|
||||
} else {
|
||||
c = def;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void secondsEffectSineFade(int16_t secondLed, Toki::Time const& time) {
|
||||
uint32_t ms = time.ms % 1000;
|
||||
uint8_t b0 = (cos8_t(ms * 64 / 1000) - 128) * 2;
|
||||
setPixelColor(secondLed, scale32(secondColor, b0));
|
||||
uint8_t b1 = (sin8_t(ms * 64 / 1000) - 128) * 2;
|
||||
setPixelColor(inc(secondLed, 1, secondsSegment), scale32(secondColor, b1));
|
||||
}
|
||||
|
||||
static inline uint32_t qadd32(uint32_t c1, uint32_t c2) {
|
||||
return RGBW32(
|
||||
qadd8(R(c1), R(c2)),
|
||||
qadd8(G(c1), G(c2)),
|
||||
qadd8(B(c1), B(c2)),
|
||||
qadd8(W(c1), W(c2))
|
||||
);
|
||||
}
|
||||
|
||||
static inline uint32_t scale32(uint32_t c, fract8 scale) {
|
||||
return RGBW32(
|
||||
scale8(R(c), scale),
|
||||
scale8(G(c), scale),
|
||||
scale8(B(c), scale),
|
||||
scale8(W(c), scale)
|
||||
);
|
||||
}
|
||||
|
||||
static inline int16_t dec(int16_t n, int16_t i, Segment const& seg) {
|
||||
return n - seg.firstLed >= i
|
||||
? n - i
|
||||
: seg.lastLed - seg.firstLed - i + n + 1;
|
||||
}
|
||||
|
||||
static inline int16_t inc(int16_t n, int16_t i, Segment const& seg) {
|
||||
int16_t r = n + i;
|
||||
if (r > seg.lastLed) {
|
||||
return seg.firstLed + n - seg.lastLed;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public:
|
||||
AnalogClockUsermod() {
|
||||
}
|
||||
|
||||
void setup() override {
|
||||
initDone = true;
|
||||
validateAndUpdate();
|
||||
}
|
||||
|
||||
void loop() override {
|
||||
if (millis() - lastOverlayDraw > refreshDelay) {
|
||||
strip.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
void handleOverlayDraw() override {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastOverlayDraw = millis();
|
||||
|
||||
auto time = toki.getTime();
|
||||
double secondP = second(localTime) / 60.0;
|
||||
double minuteP = minute(localTime) / 60.0;
|
||||
double hourP = (hour(localTime) % 12) / 12.0 + minuteP / 12.0;
|
||||
|
||||
if (hourMarksEnabled) {
|
||||
for (int Led = 0; Led <= 55; Led = Led + 5)
|
||||
{
|
||||
int16_t hourmarkled = adjustToSegment(Led / 60.0, mainSegment);
|
||||
setPixelColor(hourmarkled, hourMarkColor);
|
||||
}
|
||||
}
|
||||
|
||||
if (secondsEnabled) {
|
||||
int16_t secondLed = adjustToSegment(secondP, secondsSegment);
|
||||
|
||||
switch (secondsEffect) {
|
||||
case 0: // no effect
|
||||
setPixelColor(secondLed, secondColor);
|
||||
break;
|
||||
|
||||
case 1: // fading seconds
|
||||
secondsEffectSineFade(secondLed, time);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: move to secondsTrailEffect
|
||||
// for (uint16_t i = 1; i < secondsTrail + 1; ++i) {
|
||||
// uint16_t trailLed = dec(secondLed, i, secondsSegment);
|
||||
// uint8_t trailBright = 255 / (secondsTrail + 1) * (secondsTrail - i + 1);
|
||||
// setPixelColor(trailLed, scale32(secondColor, trailBright));
|
||||
// }
|
||||
}
|
||||
|
||||
setPixelColor(adjustToSegment(minuteP, mainSegment), minuteColor);
|
||||
setPixelColor(adjustToSegment(hourP, mainSegment), hourColor);
|
||||
}
|
||||
|
||||
void addToConfig(JsonObject& root) override {
|
||||
validateAndUpdate();
|
||||
|
||||
JsonObject top = root.createNestedObject(F("Analog Clock"));
|
||||
top[F("Overlay Enabled")] = enabled;
|
||||
top[F("First LED (Main Ring)")] = mainSegment.firstLed;
|
||||
top[F("Last LED (Main Ring)")] = mainSegment.lastLed;
|
||||
top[F("Center/12h LED (Main Ring)")] = mainSegment.centerLed;
|
||||
top[F("Hour Marks Enabled")] = hourMarksEnabled;
|
||||
top[F("Hour Mark Color (RRGGBB)")] = colorToHexString(hourMarkColor);
|
||||
top[F("Hour Color (RRGGBB)")] = colorToHexString(hourColor);
|
||||
top[F("Minute Color (RRGGBB)")] = colorToHexString(minuteColor);
|
||||
top[F("Show Seconds")] = secondsEnabled;
|
||||
top[F("First LED (Seconds Ring)")] = secondsSegment.firstLed;
|
||||
top[F("Last LED (Seconds Ring)")] = secondsSegment.lastLed;
|
||||
top[F("Center/12h LED (Seconds Ring)")] = secondsSegment.centerLed;
|
||||
top[F("Second Color (RRGGBB)")] = colorToHexString(secondColor);
|
||||
top[F("Seconds Effect (0-1)")] = secondsEffect;
|
||||
top[F("Blend Colors")] = blendColors;
|
||||
}
|
||||
|
||||
bool readFromConfig(JsonObject& root) override {
|
||||
JsonObject top = root[F("Analog Clock")];
|
||||
|
||||
bool configComplete = !top.isNull();
|
||||
|
||||
String color;
|
||||
configComplete &= getJsonValue(top[F("Overlay Enabled")], enabled, false);
|
||||
configComplete &= getJsonValue(top[F("First LED (Main Ring)")], mainSegment.firstLed, 0);
|
||||
configComplete &= getJsonValue(top[F("Last LED (Main Ring)")], mainSegment.lastLed, 59);
|
||||
configComplete &= getJsonValue(top[F("Center/12h LED (Main Ring)")], mainSegment.centerLed, 0);
|
||||
configComplete &= getJsonValue(top[F("Hour Marks Enabled")], hourMarksEnabled, false);
|
||||
configComplete &= getJsonValue(top[F("Hour Mark Color (RRGGBB)")], color, F("161616")) && hexStringToColor(color, hourMarkColor, 0x161616);
|
||||
configComplete &= getJsonValue(top[F("Hour Color (RRGGBB)")], color, F("0000FF")) && hexStringToColor(color, hourColor, 0x0000FF);
|
||||
configComplete &= getJsonValue(top[F("Minute Color (RRGGBB)")], color, F("00FF00")) && hexStringToColor(color, minuteColor, 0x00FF00);
|
||||
configComplete &= getJsonValue(top[F("Show Seconds")], secondsEnabled, true);
|
||||
configComplete &= getJsonValue(top[F("First LED (Seconds Ring)")], secondsSegment.firstLed, 0);
|
||||
configComplete &= getJsonValue(top[F("Last LED (Seconds Ring)")], secondsSegment.lastLed, 59);
|
||||
configComplete &= getJsonValue(top[F("Center/12h LED (Seconds Ring)")], secondsSegment.centerLed, 0);
|
||||
configComplete &= getJsonValue(top[F("Second Color (RRGGBB)")], color, F("FF0000")) && hexStringToColor(color, secondColor, 0xFF0000);
|
||||
configComplete &= getJsonValue(top[F("Seconds Effect (0-1)")], secondsEffect, 0);
|
||||
configComplete &= getJsonValue(top[F("Blend Colors")], blendColors, true);
|
||||
|
||||
if (initDone) {
|
||||
validateAndUpdate();
|
||||
}
|
||||
|
||||
return configComplete;
|
||||
}
|
||||
|
||||
uint16_t getId() override {
|
||||
return USERMOD_ID_ANALOG_CLOCK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static AnalogClockUsermod analog_clock;
|
||||
REGISTER_USERMOD(analog_clock);
|
||||
4
usermods/Analog_Clock/library.json
Normal file
4
usermods/Analog_Clock/library.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "Analog_Clock",
|
||||
"build": { "libArchive": false }
|
||||
}
|
||||
567
usermods/Animated_Staircase/Animated_Staircase.cpp
Normal file
567
usermods/Animated_Staircase/Animated_Staircase.cpp
Normal file
@@ -0,0 +1,567 @@
|
||||
/*
|
||||
* Usermod for detecting people entering/leaving a staircase and switching the
|
||||
* staircase on/off.
|
||||
*
|
||||
* Edit the Animated_Staircase_config.h file to compile this usermod for your
|
||||
* specific configuration.
|
||||
*
|
||||
* See the accompanying README.md file for more info.
|
||||
*/
|
||||
#include "wled.h"
|
||||
|
||||
class Animated_Staircase : public Usermod {
|
||||
private:
|
||||
|
||||
/* configuration (available in API and stored in flash) */
|
||||
bool enabled = false; // Enable this usermod
|
||||
unsigned long segment_delay_ms = 150; // Time between switching each segment
|
||||
unsigned long on_time_ms = 30000; // The time for the light to stay on
|
||||
int8_t topPIRorTriggerPin = -1; // disabled
|
||||
int8_t bottomPIRorTriggerPin = -1; // disabled
|
||||
int8_t topEchoPin = -1; // disabled
|
||||
int8_t bottomEchoPin = -1; // disabled
|
||||
bool useUSSensorTop = false; // using PIR or UltraSound sensor?
|
||||
bool useUSSensorBottom = false; // using PIR or UltraSound sensor?
|
||||
unsigned int topMaxDist = 50; // default maximum measured distance in cm, top
|
||||
unsigned int bottomMaxDist = 50; // default maximum measured distance in cm, bottom
|
||||
bool togglePower = false; // toggle power on/off with staircase on/off
|
||||
|
||||
/* runtime variables */
|
||||
bool initDone = false;
|
||||
|
||||
// Time between checking of the sensors
|
||||
const unsigned int scanDelay = 100;
|
||||
|
||||
// Lights on or off.
|
||||
// Flipping this will start a transition.
|
||||
bool on = false;
|
||||
|
||||
// Swipe direction for current transition
|
||||
#define SWIPE_UP true
|
||||
#define SWIPE_DOWN false
|
||||
bool swipe = SWIPE_UP;
|
||||
|
||||
// Indicates which Sensor was seen last (to determine
|
||||
// the direction when swiping off)
|
||||
#define LOWER false
|
||||
#define UPPER true
|
||||
bool lastSensor = LOWER;
|
||||
|
||||
// Time of the last transition action
|
||||
unsigned long lastTime = 0;
|
||||
|
||||
// Time of the last sensor check
|
||||
unsigned long lastScanTime = 0;
|
||||
|
||||
// Last time the lights were switched on or off
|
||||
unsigned long lastSwitchTime = 0;
|
||||
|
||||
// segment id between onIndex and offIndex are on.
|
||||
// controll the swipe by setting/moving these indices around.
|
||||
// onIndex must be less than or equal to offIndex
|
||||
byte onIndex = 0;
|
||||
byte offIndex = 0;
|
||||
|
||||
// The maximum number of configured segments.
|
||||
// Dynamically updated based on user configuration.
|
||||
byte maxSegmentId = 1;
|
||||
byte minSegmentId = 0;
|
||||
|
||||
// These values are used by the API to read the
|
||||
// last sensor state, or trigger a sensor
|
||||
// through the API
|
||||
bool topSensorRead = false;
|
||||
bool topSensorWrite = false;
|
||||
bool bottomSensorRead = false;
|
||||
bool bottomSensorWrite = false;
|
||||
bool topSensorState = false;
|
||||
bool bottomSensorState = false;
|
||||
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
static const char _name[];
|
||||
static const char _enabled[];
|
||||
static const char _segmentDelay[];
|
||||
static const char _onTime[];
|
||||
static const char _useTopUltrasoundSensor[];
|
||||
static const char _topPIRorTrigger_pin[];
|
||||
static const char _topEcho_pin[];
|
||||
static const char _useBottomUltrasoundSensor[];
|
||||
static const char _bottomPIRorTrigger_pin[];
|
||||
static const char _bottomEcho_pin[];
|
||||
static const char _topEchoCm[];
|
||||
static const char _bottomEchoCm[];
|
||||
static const char _togglePower[];
|
||||
|
||||
void publishMqtt(bool bottom, const char* state) {
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (WLED_MQTT_CONNECTED){
|
||||
char subuf[64];
|
||||
sprintf_P(subuf, PSTR("%s/motion/%d"), mqttDeviceTopic, (int)bottom);
|
||||
mqtt->publish(subuf, 0, false, state);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void updateSegments() {
|
||||
for (int i = minSegmentId; i < maxSegmentId; i++) {
|
||||
Segment &seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue; // skip gaps
|
||||
if (i >= onIndex && i < offIndex) {
|
||||
seg.setOption(SEG_OPTION_ON, true);
|
||||
// We may need to copy mode and colors from segment 0 to make sure
|
||||
// changes are propagated even when the config is changed during a wipe
|
||||
// seg.setMode(mainsegment.mode);
|
||||
// seg.setColor(0, mainsegment.colors[0]);
|
||||
} else {
|
||||
seg.setOption(SEG_OPTION_ON, false);
|
||||
}
|
||||
// Always mark segments as "transitional", we are animating the staircase
|
||||
//seg.setOption(SEG_OPTION_TRANSITIONAL, true); // not needed anymore as setOption() does it
|
||||
}
|
||||
strip.trigger(); // force strip refresh
|
||||
stateChanged = true; // inform external devices/UI of change
|
||||
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Detects if an object is within ultrasound range.
|
||||
* signalPin: The pin where the pulse is sent
|
||||
* echoPin: The pin where the echo is received
|
||||
* maxTimeUs: Detection timeout in microseconds. If an echo is
|
||||
* received within this time, an object is detected
|
||||
* and the function will return true.
|
||||
*
|
||||
* The speed of sound is 343 meters per second at 20 degrees Celsius.
|
||||
* Since the sound has to travel back and forth, the detection
|
||||
* distance for the sensor in cm is (0.0343 * maxTimeUs) / 2.
|
||||
*
|
||||
* For practical reasons, here are some useful distances:
|
||||
*
|
||||
* Distance = maxtime
|
||||
* 5 cm = 292 uS
|
||||
* 10 cm = 583 uS
|
||||
* 20 cm = 1166 uS
|
||||
* 30 cm = 1749 uS
|
||||
* 50 cm = 2915 uS
|
||||
* 100 cm = 5831 uS
|
||||
*/
|
||||
bool ultrasoundRead(int8_t signalPin, int8_t echoPin, unsigned int maxTimeUs) {
|
||||
if (signalPin<0 || echoPin<0) return false;
|
||||
digitalWrite(signalPin, LOW);
|
||||
delayMicroseconds(2);
|
||||
digitalWrite(signalPin, HIGH);
|
||||
delayMicroseconds(10);
|
||||
digitalWrite(signalPin, LOW);
|
||||
return pulseIn(echoPin, HIGH, maxTimeUs) > 0;
|
||||
}
|
||||
|
||||
bool checkSensors() {
|
||||
bool sensorChanged = false;
|
||||
|
||||
if ((millis() - lastScanTime) > scanDelay) {
|
||||
lastScanTime = millis();
|
||||
|
||||
bottomSensorRead = bottomSensorWrite ||
|
||||
(!useUSSensorBottom ?
|
||||
(bottomPIRorTriggerPin<0 ? false : digitalRead(bottomPIRorTriggerPin)) :
|
||||
ultrasoundRead(bottomPIRorTriggerPin, bottomEchoPin, bottomMaxDist*59) // cm to us
|
||||
);
|
||||
topSensorRead = topSensorWrite ||
|
||||
(!useUSSensorTop ?
|
||||
(topPIRorTriggerPin<0 ? false : digitalRead(topPIRorTriggerPin)) :
|
||||
ultrasoundRead(topPIRorTriggerPin, topEchoPin, topMaxDist*59) // cm to us
|
||||
);
|
||||
|
||||
if (bottomSensorRead != bottomSensorState) {
|
||||
bottomSensorState = bottomSensorRead; // change previous state
|
||||
sensorChanged = true;
|
||||
publishMqtt(true, bottomSensorState ? "on" : "off");
|
||||
DEBUG_PRINTLN(F("Bottom sensor changed."));
|
||||
}
|
||||
|
||||
if (topSensorRead != topSensorState) {
|
||||
topSensorState = topSensorRead; // change previous state
|
||||
sensorChanged = true;
|
||||
publishMqtt(false, topSensorState ? "on" : "off");
|
||||
DEBUG_PRINTLN(F("Top sensor changed."));
|
||||
}
|
||||
|
||||
// Values read, reset the flags for next API call
|
||||
topSensorWrite = false;
|
||||
bottomSensorWrite = false;
|
||||
|
||||
if (topSensorRead != bottomSensorRead) {
|
||||
lastSwitchTime = millis();
|
||||
|
||||
if (on) {
|
||||
lastSensor = topSensorRead;
|
||||
} else {
|
||||
if (togglePower && onIndex == offIndex && offMode) toggleOnOff(); // toggle power on if off
|
||||
// If the bottom sensor triggered, we need to swipe up, ON
|
||||
swipe = bottomSensorRead;
|
||||
|
||||
DEBUG_PRINT(F("ON -> Swipe "));
|
||||
DEBUG_PRINTLN(swipe ? F("up.") : F("down."));
|
||||
|
||||
if (onIndex == offIndex) {
|
||||
// Position the indices for a correct on-swipe
|
||||
if (swipe == SWIPE_UP) {
|
||||
onIndex = minSegmentId;
|
||||
} else {
|
||||
onIndex = maxSegmentId;
|
||||
}
|
||||
offIndex = onIndex;
|
||||
}
|
||||
on = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sensorChanged;
|
||||
}
|
||||
|
||||
void autoPowerOff() {
|
||||
if ((millis() - lastSwitchTime) > on_time_ms) {
|
||||
// if sensors are still on, do nothing
|
||||
if (bottomSensorState || topSensorState) return;
|
||||
|
||||
// Swipe OFF in the direction of the last sensor detection
|
||||
swipe = lastSensor;
|
||||
on = false;
|
||||
|
||||
DEBUG_PRINT(F("OFF -> Swipe "));
|
||||
DEBUG_PRINTLN(swipe ? F("up.") : F("down."));
|
||||
}
|
||||
}
|
||||
|
||||
void updateSwipe() {
|
||||
if ((millis() - lastTime) > segment_delay_ms) {
|
||||
lastTime = millis();
|
||||
|
||||
byte oldOn = onIndex;
|
||||
byte oldOff = offIndex;
|
||||
if (on) {
|
||||
// Turn on all segments
|
||||
onIndex = MAX(minSegmentId, onIndex - 1);
|
||||
offIndex = MIN(maxSegmentId, offIndex + 1);
|
||||
} else {
|
||||
if (swipe == SWIPE_UP) {
|
||||
onIndex = MIN(offIndex, onIndex + 1);
|
||||
} else {
|
||||
offIndex = MAX(onIndex, offIndex - 1);
|
||||
}
|
||||
}
|
||||
if (oldOn != onIndex || oldOff != offIndex) {
|
||||
updateSegments(); // reduce the number of updates to necessary ones
|
||||
if (togglePower && onIndex == offIndex && !offMode && !on) toggleOnOff(); // toggle power off for all segments off
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send sensor values to JSON API
|
||||
void writeSensorsToJson(JsonObject& staircase) {
|
||||
staircase[F("top-sensor")] = topSensorRead;
|
||||
staircase[F("bottom-sensor")] = bottomSensorRead;
|
||||
}
|
||||
|
||||
// allow overrides from JSON API
|
||||
void readSensorsFromJson(JsonObject& staircase) {
|
||||
bottomSensorWrite = bottomSensorState || (staircase[F("bottom-sensor")].as<bool>());
|
||||
topSensorWrite = topSensorState || (staircase[F("top-sensor")].as<bool>());
|
||||
}
|
||||
|
||||
void enable(bool enable) {
|
||||
if (enable) {
|
||||
DEBUG_PRINTLN(F("Animated Staircase enabled."));
|
||||
DEBUG_PRINT(F("Delay between steps: "));
|
||||
DEBUG_PRINT(segment_delay_ms);
|
||||
DEBUG_PRINT(F(" milliseconds.\nStairs switch off after: "));
|
||||
DEBUG_PRINT(on_time_ms / 1000);
|
||||
DEBUG_PRINTLN(F(" seconds."));
|
||||
|
||||
if (!useUSSensorBottom)
|
||||
pinMode(bottomPIRorTriggerPin, INPUT_PULLUP);
|
||||
else {
|
||||
pinMode(bottomPIRorTriggerPin, OUTPUT);
|
||||
pinMode(bottomEchoPin, INPUT);
|
||||
}
|
||||
|
||||
if (!useUSSensorTop)
|
||||
pinMode(topPIRorTriggerPin, INPUT_PULLUP);
|
||||
else {
|
||||
pinMode(topPIRorTriggerPin, OUTPUT);
|
||||
pinMode(topEchoPin, INPUT);
|
||||
}
|
||||
onIndex = minSegmentId = strip.getMainSegmentId(); // it may not be the best idea to start with main segment as it may not be the first one
|
||||
offIndex = maxSegmentId = strip.getLastActiveSegmentId() + 1;
|
||||
|
||||
// shorten the strip transition time to be equal or shorter than segment delay
|
||||
transitionDelay = segment_delay_ms;
|
||||
strip.setTransition(segment_delay_ms);
|
||||
strip.trigger();
|
||||
} else {
|
||||
if (togglePower && !on && offMode) toggleOnOff(); // toggle power on if off
|
||||
// Restore segment options
|
||||
for (int i = 0; i <= strip.getLastActiveSegmentId(); i++) {
|
||||
Segment &seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue; // skip vector gaps
|
||||
seg.setOption(SEG_OPTION_ON, true);
|
||||
}
|
||||
strip.trigger(); // force strip update
|
||||
stateChanged = true; // inform external devices/UI of change
|
||||
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
DEBUG_PRINTLN(F("Animated Staircase disabled."));
|
||||
}
|
||||
enabled = enable;
|
||||
}
|
||||
|
||||
public:
|
||||
void setup() {
|
||||
// standardize invalid pin numbers to -1
|
||||
if (topPIRorTriggerPin < 0) topPIRorTriggerPin = -1;
|
||||
if (topEchoPin < 0) topEchoPin = -1;
|
||||
if (bottomPIRorTriggerPin < 0) bottomPIRorTriggerPin = -1;
|
||||
if (bottomEchoPin < 0) bottomEchoPin = -1;
|
||||
// allocate pins
|
||||
PinManagerPinType pins[4] = {
|
||||
{ topPIRorTriggerPin, useUSSensorTop },
|
||||
{ topEchoPin, false },
|
||||
{ bottomPIRorTriggerPin, useUSSensorBottom },
|
||||
{ bottomEchoPin, false },
|
||||
};
|
||||
// NOTE: this *WILL* return TRUE if all the pins are set to -1.
|
||||
// this is *BY DESIGN*.
|
||||
if (!PinManager::allocateMultiplePins(pins, 4, PinOwner::UM_AnimatedStaircase)) {
|
||||
topPIRorTriggerPin = -1;
|
||||
topEchoPin = -1;
|
||||
bottomPIRorTriggerPin = -1;
|
||||
bottomEchoPin = -1;
|
||||
enabled = false;
|
||||
}
|
||||
enable(enabled);
|
||||
initDone = true;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (!enabled || strip.isUpdating()) return;
|
||||
minSegmentId = strip.getMainSegmentId(); // it may not be the best idea to start with main segment as it may not be the first one
|
||||
maxSegmentId = strip.getLastActiveSegmentId() + 1;
|
||||
checkSensors();
|
||||
if (on) autoPowerOff();
|
||||
updateSwipe();
|
||||
}
|
||||
|
||||
uint16_t getId() { return USERMOD_ID_ANIMATED_STAIRCASE; }
|
||||
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
/**
|
||||
* handling of MQTT message
|
||||
* topic only contains stripped topic (part after /wled/MAC)
|
||||
* topic should look like: /swipe with amessage of [up|down]
|
||||
*/
|
||||
bool onMqttMessage(char* topic, char* payload) {
|
||||
if (strlen(topic) == 6 && strncmp_P(topic, PSTR("/swipe"), 6) == 0) {
|
||||
String action = payload;
|
||||
if (action == "up") {
|
||||
bottomSensorWrite = true;
|
||||
return true;
|
||||
} else if (action == "down") {
|
||||
topSensorWrite = true;
|
||||
return true;
|
||||
} else if (action == "on") {
|
||||
enable(true);
|
||||
return true;
|
||||
} else if (action == "off") {
|
||||
enable(false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* subscribe to MQTT topic for controlling usermod
|
||||
*/
|
||||
void onMqttConnect(bool sessionPresent) {
|
||||
//(re)subscribe to required topics
|
||||
char subuf[64];
|
||||
if (mqttDeviceTopic[0] != 0) {
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat_P(subuf, PSTR("/swipe"));
|
||||
mqtt->subscribe(subuf, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void addToJsonState(JsonObject& root) {
|
||||
JsonObject staircase = root[FPSTR(_name)];
|
||||
if (staircase.isNull()) {
|
||||
staircase = root.createNestedObject(FPSTR(_name));
|
||||
}
|
||||
writeSensorsToJson(staircase);
|
||||
DEBUG_PRINTLN(F("Staircase sensor state exposed in API."));
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads configuration settings from the json API.
|
||||
* See void addToJsonState(JsonObject& root)
|
||||
*/
|
||||
void readFromJsonState(JsonObject& root) {
|
||||
if (!initDone) return; // prevent crash on boot applyPreset()
|
||||
bool en = enabled;
|
||||
JsonObject staircase = root[FPSTR(_name)];
|
||||
if (!staircase.isNull()) {
|
||||
if (staircase[FPSTR(_enabled)].is<bool>()) {
|
||||
en = staircase[FPSTR(_enabled)].as<bool>();
|
||||
} else {
|
||||
String str = staircase[FPSTR(_enabled)]; // checkbox -> off or on
|
||||
en = (bool)(str!="off"); // off is guaranteed to be present
|
||||
}
|
||||
if (en != enabled) enable(en);
|
||||
readSensorsFromJson(staircase);
|
||||
DEBUG_PRINTLN(F("Staircase sensor state read from API."));
|
||||
}
|
||||
}
|
||||
|
||||
void appendConfigData() {
|
||||
//oappend(F("dd=addDropdown('staircase','selectfield');"));
|
||||
//oappend(F("addOption(dd,'1st value',0);"));
|
||||
//oappend(F("addOption(dd,'2nd value',1);"));
|
||||
//oappend(F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Writes the configuration to internal flash memory.
|
||||
*/
|
||||
void addToConfig(JsonObject& root) {
|
||||
JsonObject staircase = root[FPSTR(_name)];
|
||||
if (staircase.isNull()) {
|
||||
staircase = root.createNestedObject(FPSTR(_name));
|
||||
}
|
||||
staircase[FPSTR(_enabled)] = enabled;
|
||||
staircase[FPSTR(_segmentDelay)] = segment_delay_ms;
|
||||
staircase[FPSTR(_onTime)] = on_time_ms / 1000;
|
||||
staircase[FPSTR(_useTopUltrasoundSensor)] = useUSSensorTop;
|
||||
staircase[FPSTR(_topPIRorTrigger_pin)] = topPIRorTriggerPin;
|
||||
staircase[FPSTR(_topEcho_pin)] = useUSSensorTop ? topEchoPin : -1;
|
||||
staircase[FPSTR(_useBottomUltrasoundSensor)] = useUSSensorBottom;
|
||||
staircase[FPSTR(_bottomPIRorTrigger_pin)] = bottomPIRorTriggerPin;
|
||||
staircase[FPSTR(_bottomEcho_pin)] = useUSSensorBottom ? bottomEchoPin : -1;
|
||||
staircase[FPSTR(_topEchoCm)] = topMaxDist;
|
||||
staircase[FPSTR(_bottomEchoCm)] = bottomMaxDist;
|
||||
staircase[FPSTR(_togglePower)] = togglePower;
|
||||
DEBUG_PRINTLN(F("Staircase config saved."));
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads the configuration to internal flash memory before setup() is called.
|
||||
*
|
||||
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
||||
*/
|
||||
bool readFromConfig(JsonObject& root) {
|
||||
bool oldUseUSSensorTop = useUSSensorTop;
|
||||
bool oldUseUSSensorBottom = useUSSensorBottom;
|
||||
int8_t oldTopAPin = topPIRorTriggerPin;
|
||||
int8_t oldTopBPin = topEchoPin;
|
||||
int8_t oldBottomAPin = bottomPIRorTriggerPin;
|
||||
int8_t oldBottomBPin = bottomEchoPin;
|
||||
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
if (top.isNull()) {
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||
return false;
|
||||
}
|
||||
|
||||
enabled = top[FPSTR(_enabled)] | enabled;
|
||||
|
||||
segment_delay_ms = top[FPSTR(_segmentDelay)] | segment_delay_ms;
|
||||
segment_delay_ms = (unsigned long) min((unsigned long)10000,max((unsigned long)10,(unsigned long)segment_delay_ms)); // max delay 10s
|
||||
|
||||
on_time_ms = top[FPSTR(_onTime)] | on_time_ms/1000;
|
||||
on_time_ms = min(900,max(10,(int)on_time_ms)) * 1000; // min 10s, max 15min
|
||||
|
||||
useUSSensorTop = top[FPSTR(_useTopUltrasoundSensor)] | useUSSensorTop;
|
||||
topPIRorTriggerPin = top[FPSTR(_topPIRorTrigger_pin)] | topPIRorTriggerPin;
|
||||
topEchoPin = top[FPSTR(_topEcho_pin)] | topEchoPin;
|
||||
|
||||
useUSSensorBottom = top[FPSTR(_useBottomUltrasoundSensor)] | useUSSensorBottom;
|
||||
bottomPIRorTriggerPin = top[FPSTR(_bottomPIRorTrigger_pin)] | bottomPIRorTriggerPin;
|
||||
bottomEchoPin = top[FPSTR(_bottomEcho_pin)] | bottomEchoPin;
|
||||
|
||||
topMaxDist = top[FPSTR(_topEchoCm)] | topMaxDist;
|
||||
topMaxDist = min(150,max(30,(int)topMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected)
|
||||
bottomMaxDist = top[FPSTR(_bottomEchoCm)] | bottomMaxDist;
|
||||
bottomMaxDist = min(150,max(30,(int)bottomMaxDist)); // max distance ~1.5m (a lag of 9ms may be expected)
|
||||
|
||||
togglePower = top[FPSTR(_togglePower)] | togglePower; // staircase toggles power on/off
|
||||
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
if (!initDone) {
|
||||
// first run: reading from cfg.json
|
||||
DEBUG_PRINTLN(F(" config loaded."));
|
||||
} else {
|
||||
// changing parameters from settings page
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
bool changed = false;
|
||||
if ((oldUseUSSensorTop != useUSSensorTop) ||
|
||||
(oldUseUSSensorBottom != useUSSensorBottom) ||
|
||||
(oldTopAPin != topPIRorTriggerPin) ||
|
||||
(oldTopBPin != topEchoPin) ||
|
||||
(oldBottomAPin != bottomPIRorTriggerPin) ||
|
||||
(oldBottomBPin != bottomEchoPin)) {
|
||||
changed = true;
|
||||
PinManager::deallocatePin(oldTopAPin, PinOwner::UM_AnimatedStaircase);
|
||||
PinManager::deallocatePin(oldTopBPin, PinOwner::UM_AnimatedStaircase);
|
||||
PinManager::deallocatePin(oldBottomAPin, PinOwner::UM_AnimatedStaircase);
|
||||
PinManager::deallocatePin(oldBottomBPin, PinOwner::UM_AnimatedStaircase);
|
||||
}
|
||||
if (changed) setup();
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !top[FPSTR(_togglePower)].isNull();
|
||||
}
|
||||
|
||||
/*
|
||||
* Shows the delay between steps and power-off time in the "info"
|
||||
* tab of the web-UI.
|
||||
*/
|
||||
void addToJsonInfo(JsonObject& root) {
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) {
|
||||
user = root.createNestedObject("u");
|
||||
}
|
||||
|
||||
JsonArray infoArr = user.createNestedArray(FPSTR(_name)); // name
|
||||
|
||||
String uiDomString = F("<button class=\"btn btn-xs\" onclick=\"requestJson({");
|
||||
uiDomString += FPSTR(_name);
|
||||
uiDomString += F(":{");
|
||||
uiDomString += FPSTR(_enabled);
|
||||
uiDomString += enabled ? F(":false}});\">") : F(":true}});\">");
|
||||
uiDomString += F("<i class=\"icons ");
|
||||
uiDomString += enabled ? "on" : "off";
|
||||
uiDomString += F("\"></i></button>");
|
||||
infoArr.add(uiDomString);
|
||||
}
|
||||
};
|
||||
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
const char Animated_Staircase::_name[] PROGMEM = "staircase";
|
||||
const char Animated_Staircase::_enabled[] PROGMEM = "enabled";
|
||||
const char Animated_Staircase::_segmentDelay[] PROGMEM = "segment-delay-ms";
|
||||
const char Animated_Staircase::_onTime[] PROGMEM = "on-time-s";
|
||||
const char Animated_Staircase::_useTopUltrasoundSensor[] PROGMEM = "useTopUltrasoundSensor";
|
||||
const char Animated_Staircase::_topPIRorTrigger_pin[] PROGMEM = "topPIRorTrigger_pin";
|
||||
const char Animated_Staircase::_topEcho_pin[] PROGMEM = "topEcho_pin";
|
||||
const char Animated_Staircase::_useBottomUltrasoundSensor[] PROGMEM = "useBottomUltrasoundSensor";
|
||||
const char Animated_Staircase::_bottomPIRorTrigger_pin[] PROGMEM = "bottomPIRorTrigger_pin";
|
||||
const char Animated_Staircase::_bottomEcho_pin[] PROGMEM = "bottomEcho_pin";
|
||||
const char Animated_Staircase::_topEchoCm[] PROGMEM = "top-dist-cm";
|
||||
const char Animated_Staircase::_bottomEchoCm[] PROGMEM = "bottom-dist-cm";
|
||||
const char Animated_Staircase::_togglePower[] PROGMEM = "toggle-on-off";
|
||||
|
||||
|
||||
static Animated_Staircase animated_staircase;
|
||||
REGISTER_USERMOD(animated_staircase);
|
||||
138
usermods/Animated_Staircase/README.md
Normal file
138
usermods/Animated_Staircase/README.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# Usermod Animated Staircase
|
||||
|
||||
This usermod makes your staircase look cool by illuminating it with an animation. It uses
|
||||
PIR or ultrasonic sensors at the top and bottom of your stairs to:
|
||||
|
||||
- Light up the steps in the direction you're walking.
|
||||
- Switch off the steps after you, in the direction of the last detected movement.
|
||||
- Always switch on when one of the sensors detects movement, even if an effect
|
||||
is still running. It can gracefully handle multiple people on the stairs.
|
||||
|
||||
The Animated Staircase can be controlled by the WLED API. Change settings such as
|
||||
speed, on/off time and distance by sending an HTTP request, see below.
|
||||
|
||||
## WLED integration
|
||||
|
||||
To include this usermod in your WLED setup, you have to be able to [compile WLED from source](https://kno.wled.ge/advanced/compiling-wled/).
|
||||
|
||||
Before compiling, you have to make the following modifications:
|
||||
|
||||
Edit your environment in `platformio_override.ini`
|
||||
|
||||
1. Open `platformio_override.ini`
|
||||
2. add `Animated_Staircase` to the `custom_usermods` line for your environment
|
||||
|
||||
You can configure usermod using the Usermods settings page.
|
||||
Please enter GPIO pins for PIR or ultrasonic sensors (trigger and echo).
|
||||
If you use PIR sensor enter -1 for echo pin.
|
||||
Maximum distance for ultrasonic sensor can be configured as the time needed for an echo (see below).
|
||||
|
||||
## Hardware installation
|
||||
|
||||
1. Attach the LED strip to each step of the stairs.
|
||||
2. Connect the ESP8266 pin D4 or ESP32 pin D2 to the first LED data pin at the bottom step.
|
||||
3. Connect the data-out pin at the end of each strip per step to the data-in pin on the next step, creating one large virtual LED strip.
|
||||
4. Mount sensors of choice at the bottom and top of the stairs and connect them to the ESP.
|
||||
5. To make sure all LEDs get enough power and have your staircase lighted evenly, power each
|
||||
step from one side, using at least AWG14 or 2.5mm^2 cable. Don't connect them serial as you
|
||||
do for the datacable!
|
||||
|
||||
You _may_ need to use 10k pull-down resistors on the selected PIR pins, depending on the sensor.
|
||||
|
||||
## WLED configuration
|
||||
|
||||
1. In the WLED UI, configure a segment for each step. The lowest step of the stairs is the lowest segment id.
|
||||
2. Save your segments into a preset.
|
||||
3. Ideally, add the preset in the config > LED setup menu to the "apply preset **n** at boot" setting.
|
||||
|
||||
## Changing behavior through API
|
||||
|
||||
The Staircase settings can be changed through the WLED JSON api.
|
||||
|
||||
**NOTE:** We are using [curl](https://curl.se/) to send HTTP POSTs to the WLED API.
|
||||
If you're using Windows and want to use the curl commands, replace the `\` with a `^`
|
||||
or remove them and put everything on one line.
|
||||
|
||||
| Setting | Description | Default |
|
||||
|------------------|---------------------------------------------------------------|---------|
|
||||
| enabled | Enable or disable the usermod | true |
|
||||
| bottom-sensor | Manually trigger a down to up animation via API | false |
|
||||
| top-sensor | Manually trigger an up to down animation via API | false |
|
||||
|
||||
|
||||
To read the current settings, open a browser to `http://xxx.xxx.xxx.xxx/json/state` (use your WLED
|
||||
device IP address). The device will respond with a json object containing all WLED settings.
|
||||
The staircase settings and sensor states are inside the WLED "state" element:
|
||||
|
||||
```json
|
||||
{
|
||||
"state": {
|
||||
"staircase": {
|
||||
"enabled": true,
|
||||
"bottom-sensor": false,
|
||||
"top-sensor": false
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Enable/disable the usermod
|
||||
|
||||
By disabling the usermod you will be able to keep the LED's on, independent from the sensor
|
||||
activity. This enables you to play with the lights without the usermod switching them on or off.
|
||||
|
||||
To disable the usermod:
|
||||
|
||||
```bash
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-d {"staircase":{"enabled":false}} \
|
||||
xxx.xxx.xxx.xxx/json/state
|
||||
```
|
||||
|
||||
To enable the usermod again, use `"enabled":true`.
|
||||
|
||||
Alternatively you can use _Usermod_ Settings page where you can change other parameters as well.
|
||||
|
||||
### Changing animation parameters and detection range of the ultrasonic HC-SR04 sensor
|
||||
|
||||
Using _Usermod_ Settings page you can define different usermod parameters, including sensor pins, delay between segment activation etc.
|
||||
|
||||
When an ultrasonic sensor is enabled you can enter maximum detection distance in centimeters separately for top and bottom sensors.
|
||||
|
||||
**Please note:** using an HC-SR04 sensor, particularly when detecting echos at longer
|
||||
distances creates delays in the WLED software, _might_ introduce timing hiccups in your animation or
|
||||
a less responsive web interface. It is therefore advised to keep the detection distance as short as possible.
|
||||
|
||||
### Animation triggering through the API
|
||||
|
||||
In addition to activation by one of the stair sensors, you can also trigger the animation manually
|
||||
via the API. To simulate triggering the bottom sensor, use:
|
||||
|
||||
```bash
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-d '{"staircase":{"bottom-sensor":true}}' \
|
||||
xxx.xxx.xxx.xxx/json/state
|
||||
```
|
||||
|
||||
Likewise, to trigger the top sensor:
|
||||
|
||||
```bash
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-d '{"staircase":{"top-sensor":true}}' \
|
||||
xxx.xxx.xxx.xxx/json/state
|
||||
```
|
||||
|
||||
**MQTT**
|
||||
You can publish a message with either `up` or `down` on topic `/swipe` to trigger animation.
|
||||
You can also use `on` or `off` for enabling or disabling the usermod.
|
||||
|
||||
Have fun with this usermod
|
||||
|
||||
`www.rolfje.com`
|
||||
|
||||
Modifications @blazoncek
|
||||
|
||||
## Change log
|
||||
|
||||
2021-04
|
||||
|
||||
- Adaptation for runtime configuration.
|
||||
4
usermods/Animated_Staircase/library.json
Normal file
4
usermods/Animated_Staircase/library.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "Animated_Staircase",
|
||||
"build": { "libArchive": false }
|
||||
}
|
||||
5
usermods/Artemis_reciever/readme.md
Normal file
5
usermods/Artemis_reciever/readme.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Usermod to allow WLED to receive via UDP port from RGB.NET (and therefore add as a device to be controlled within artemis on PC)
|
||||
|
||||
This is only a very simple code to support a single led strip, it does not support the full function of the RGB.NET sketch for esp8266 only what is needed to be used with Artemis. It will show as a ws281x device in artemis when you provide the correct hostname or ip. Artemis queries the number of LEDs via the web interface (/config) but communication to set the LEDs is all done via the UDP interface.
|
||||
|
||||
To install, copy the usermod.cpp file to wled00 folder and recompile
|
||||
93
usermods/Artemis_reciever/usermod.cpp
Normal file
93
usermods/Artemis_reciever/usermod.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* RGB.NET (artemis) receiver
|
||||
*
|
||||
* This works via the UDP, http is not supported apart from reporting LED count
|
||||
*
|
||||
*
|
||||
*/
|
||||
#include "wled.h"
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
WiFiUDP UDP;
|
||||
const unsigned int RGBNET_localUdpPort = 1872; // local port to listen on
|
||||
unsigned char RGBNET_packet[770];
|
||||
long lastTime = 0;
|
||||
int delayMs = 10;
|
||||
bool isRGBNETUDPEnabled;
|
||||
|
||||
void RGBNET_readValues() {
|
||||
|
||||
int RGBNET_packetSize = UDP.parsePacket();
|
||||
if (RGBNET_packetSize) {
|
||||
// receive incoming UDP packets
|
||||
int sequenceNumber = UDP.read();
|
||||
int channel = UDP.read();
|
||||
|
||||
//channel data is not used we only supports one channel
|
||||
int len = UDP.read(RGBNET_packet, strip.getLengthTotal()*3);
|
||||
if(len==0){
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i=i+3) {
|
||||
strip.setPixelColor(i/3, RGBNET_packet[i], RGBNET_packet[i+1], RGBNET_packet[i+2], 0);
|
||||
}
|
||||
//strip.show();
|
||||
}
|
||||
}
|
||||
|
||||
//update LED strip
|
||||
void RGBNET_show() {
|
||||
strip.show();
|
||||
lastTime = millis();
|
||||
}
|
||||
|
||||
//This function provides a json with info on the number of LEDs connected
|
||||
// it is needed by artemis to know how many LEDs to display on the surface
|
||||
void handleConfig(AsyncWebServerRequest *request)
|
||||
{
|
||||
String config = (String)"{\
|
||||
\"channels\": [\
|
||||
{\
|
||||
\"channel\": 1,\
|
||||
\"leds\": " + strip.getLengthTotal() + "\
|
||||
},\
|
||||
{\
|
||||
\"channel\": 2,\
|
||||
\"leds\": " + "0" + "\
|
||||
},\
|
||||
{\
|
||||
\"channel\": 3,\
|
||||
\"leds\": " + "0" + "\
|
||||
},\
|
||||
{\
|
||||
\"channel\": 4,\
|
||||
\"leds\": " + "0" + "\
|
||||
}\
|
||||
]\
|
||||
}";
|
||||
request->send(200, "application/json", config);
|
||||
}
|
||||
|
||||
|
||||
void userSetup()
|
||||
{
|
||||
server.on("/config", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
handleConfig(request);
|
||||
});
|
||||
}
|
||||
|
||||
void userConnected()
|
||||
{
|
||||
// new wifi, who dis?
|
||||
UDP.begin(RGBNET_localUdpPort);
|
||||
isRGBNETUDPEnabled = true;
|
||||
}
|
||||
|
||||
void userLoop()
|
||||
{
|
||||
RGBNET_readValues();
|
||||
if (millis()-lastTime > delayMs) {
|
||||
RGBNET_show();
|
||||
}
|
||||
}
|
||||
186
usermods/BH1750_v2/BH1750_v2.cpp
Normal file
186
usermods/BH1750_v2/BH1750_v2.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
// force the compiler to show a warning to confirm that this file is included
|
||||
#warning **** Included USERMOD_BH1750 ****
|
||||
|
||||
#include "wled.h"
|
||||
#include "BH1750_v2.h"
|
||||
|
||||
#ifdef WLED_DISABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
static bool checkBoundSensor(float newValue, float prevValue, float maxDiff)
|
||||
{
|
||||
return isnan(prevValue) || newValue <= prevValue - maxDiff || newValue >= prevValue + maxDiff || (newValue == 0.0 && prevValue > 0.0);
|
||||
}
|
||||
|
||||
void Usermod_BH1750::_mqttInitialize()
|
||||
{
|
||||
mqttLuminanceTopic = String(mqttDeviceTopic) + F("/brightness");
|
||||
|
||||
if (HomeAssistantDiscovery) _createMqttSensor(F("Brightness"), mqttLuminanceTopic, F("Illuminance"), F(" lx"));
|
||||
}
|
||||
|
||||
// Create an MQTT Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
|
||||
void Usermod_BH1750::_createMqttSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement)
|
||||
{
|
||||
String t = String(F("homeassistant/sensor/")) + mqttClientID + F("/") + name + F("/config");
|
||||
|
||||
StaticJsonDocument<600> doc;
|
||||
|
||||
doc[F("name")] = String(serverDescription) + " " + name;
|
||||
doc[F("state_topic")] = topic;
|
||||
doc[F("unique_id")] = String(mqttClientID) + name;
|
||||
if (unitOfMeasurement != "")
|
||||
doc[F("unit_of_measurement")] = unitOfMeasurement;
|
||||
if (deviceClass != "")
|
||||
doc[F("device_class")] = deviceClass;
|
||||
doc[F("expire_after")] = 1800;
|
||||
|
||||
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
|
||||
device[F("name")] = serverDescription;
|
||||
device[F("identifiers")] = "wled-sensor-" + String(mqttClientID);
|
||||
device[F("manufacturer")] = F(WLED_BRAND);
|
||||
device[F("model")] = F(WLED_PRODUCT_NAME);
|
||||
device[F("sw_version")] = versionString;
|
||||
|
||||
String temp;
|
||||
serializeJson(doc, temp);
|
||||
DEBUG_PRINTLN(t);
|
||||
DEBUG_PRINTLN(temp);
|
||||
|
||||
mqtt->publish(t.c_str(), 0, true, temp.c_str());
|
||||
}
|
||||
|
||||
void Usermod_BH1750::setup()
|
||||
{
|
||||
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
|
||||
sensorFound = lightMeter.begin();
|
||||
initDone = true;
|
||||
}
|
||||
|
||||
void Usermod_BH1750::loop()
|
||||
{
|
||||
if ((!enabled) || strip.isUpdating())
|
||||
return;
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
// check to see if we are due for taking a measurement
|
||||
// lastMeasurement will not be updated until the conversion
|
||||
// is complete the the reading is finished
|
||||
if (now - lastMeasurement < minReadingInterval)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool shouldUpdate = now - lastSend > maxReadingInterval;
|
||||
|
||||
float lux = lightMeter.readLightLevel();
|
||||
lastMeasurement = millis();
|
||||
getLuminanceComplete = true;
|
||||
|
||||
if (shouldUpdate || checkBoundSensor(lux, lastLux, offset))
|
||||
{
|
||||
lastLux = lux;
|
||||
lastSend = millis();
|
||||
|
||||
if (WLED_MQTT_CONNECTED)
|
||||
{
|
||||
if (!mqttInitialized)
|
||||
{
|
||||
_mqttInitialize();
|
||||
mqttInitialized = true;
|
||||
}
|
||||
mqtt->publish(mqttLuminanceTopic.c_str(), 0, true, String(lux).c_str());
|
||||
DEBUG_PRINTLN(F("Brightness: ") + String(lux) + F("lx"));
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_PRINTLN(F("Missing MQTT connection. Not publishing data"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Usermod_BH1750::addToJsonInfo(JsonObject &root)
|
||||
{
|
||||
JsonObject user = root[F("u")];
|
||||
if (user.isNull())
|
||||
user = root.createNestedObject(F("u"));
|
||||
|
||||
JsonArray lux_json = user.createNestedArray(F("Luminance"));
|
||||
if (!enabled) {
|
||||
lux_json.add(F("disabled"));
|
||||
} else if (!sensorFound) {
|
||||
// if no sensor
|
||||
lux_json.add(F("BH1750 "));
|
||||
lux_json.add(F("Not Found"));
|
||||
} else if (!getLuminanceComplete) {
|
||||
// if we haven't read the sensor yet, let the user know
|
||||
// that we are still waiting for the first measurement
|
||||
lux_json.add((USERMOD_BH1750_FIRST_MEASUREMENT_AT - millis()) / 1000);
|
||||
lux_json.add(F(" sec until read"));
|
||||
return;
|
||||
} else {
|
||||
lux_json.add(lastLux);
|
||||
lux_json.add(F(" lx"));
|
||||
}
|
||||
}
|
||||
|
||||
// (called from set.cpp) stores persistent properties to cfg.json
|
||||
void Usermod_BH1750::addToConfig(JsonObject &root)
|
||||
{
|
||||
// we add JSON object.
|
||||
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
|
||||
top[FPSTR(_enabled)] = enabled;
|
||||
top[FPSTR(_maxReadInterval)] = maxReadingInterval;
|
||||
top[FPSTR(_minReadInterval)] = minReadingInterval;
|
||||
top[FPSTR(_HomeAssistantDiscovery)] = HomeAssistantDiscovery;
|
||||
top[FPSTR(_offset)] = offset;
|
||||
|
||||
DEBUG_PRINTLN(F("BH1750 config saved."));
|
||||
}
|
||||
|
||||
// called before setup() to populate properties from values stored in cfg.json
|
||||
bool Usermod_BH1750::readFromConfig(JsonObject &root)
|
||||
{
|
||||
// we look for JSON object.
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
if (top.isNull())
|
||||
{
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
DEBUG_PRINT(F("BH1750"));
|
||||
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||
return false;
|
||||
}
|
||||
bool configComplete = !top.isNull();
|
||||
|
||||
configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled, false);
|
||||
configComplete &= getJsonValue(top[FPSTR(_maxReadInterval)], maxReadingInterval, 10000); //ms
|
||||
configComplete &= getJsonValue(top[FPSTR(_minReadInterval)], minReadingInterval, 500); //ms
|
||||
configComplete &= getJsonValue(top[FPSTR(_HomeAssistantDiscovery)], HomeAssistantDiscovery, false);
|
||||
configComplete &= getJsonValue(top[FPSTR(_offset)], offset, 1);
|
||||
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
if (!initDone) {
|
||||
DEBUG_PRINTLN(F(" config loaded."));
|
||||
} else {
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
}
|
||||
|
||||
return configComplete;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
const char Usermod_BH1750::_name[] PROGMEM = "BH1750";
|
||||
const char Usermod_BH1750::_enabled[] PROGMEM = "enabled";
|
||||
const char Usermod_BH1750::_maxReadInterval[] PROGMEM = "max-read-interval-ms";
|
||||
const char Usermod_BH1750::_minReadInterval[] PROGMEM = "min-read-interval-ms";
|
||||
const char Usermod_BH1750::_HomeAssistantDiscovery[] PROGMEM = "HomeAssistantDiscoveryLux";
|
||||
const char Usermod_BH1750::_offset[] PROGMEM = "offset-lx";
|
||||
|
||||
|
||||
static Usermod_BH1750 bh1750_v2;
|
||||
REGISTER_USERMOD(bh1750_v2);
|
||||
92
usermods/BH1750_v2/BH1750_v2.h
Normal file
92
usermods/BH1750_v2/BH1750_v2.h
Normal file
@@ -0,0 +1,92 @@
|
||||
|
||||
#pragma once
|
||||
#include "wled.h"
|
||||
#include <BH1750.h>
|
||||
|
||||
#ifdef WLED_DISABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
// the max frequency to check photoresistor, 10 seconds
|
||||
#ifndef USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL
|
||||
#define USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL 10000
|
||||
#endif
|
||||
|
||||
// the min frequency to check photoresistor, 500 ms
|
||||
#ifndef USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL
|
||||
#define USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL 500
|
||||
#endif
|
||||
|
||||
// how many seconds after boot to take first measurement, 10 seconds
|
||||
#ifndef USERMOD_BH1750_FIRST_MEASUREMENT_AT
|
||||
#define USERMOD_BH1750_FIRST_MEASUREMENT_AT 10000
|
||||
#endif
|
||||
|
||||
// only report if difference grater than offset value
|
||||
#ifndef USERMOD_BH1750_OFFSET_VALUE
|
||||
#define USERMOD_BH1750_OFFSET_VALUE 1
|
||||
#endif
|
||||
|
||||
class Usermod_BH1750 : public Usermod
|
||||
{
|
||||
private:
|
||||
int8_t offset = USERMOD_BH1750_OFFSET_VALUE;
|
||||
|
||||
unsigned long maxReadingInterval = USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL;
|
||||
unsigned long minReadingInterval = USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL;
|
||||
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL - USERMOD_BH1750_FIRST_MEASUREMENT_AT);
|
||||
unsigned long lastSend = UINT32_MAX - (USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL - USERMOD_BH1750_FIRST_MEASUREMENT_AT);
|
||||
// flag to indicate we have finished the first readLightLevel call
|
||||
// allows this library to report to the user how long until the first
|
||||
// measurement
|
||||
bool getLuminanceComplete = false;
|
||||
|
||||
// flag set at startup
|
||||
bool enabled = true;
|
||||
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
static const char _name[];
|
||||
static const char _enabled[];
|
||||
static const char _maxReadInterval[];
|
||||
static const char _minReadInterval[];
|
||||
static const char _offset[];
|
||||
static const char _HomeAssistantDiscovery[];
|
||||
|
||||
bool initDone = false;
|
||||
bool sensorFound = false;
|
||||
|
||||
// Home Assistant and MQTT
|
||||
String mqttLuminanceTopic;
|
||||
bool mqttInitialized = false;
|
||||
bool HomeAssistantDiscovery = true; // Publish Home Assistant Discovery messages
|
||||
|
||||
BH1750 lightMeter;
|
||||
float lastLux = -1000;
|
||||
|
||||
// set up Home Assistant discovery entries
|
||||
void _mqttInitialize();
|
||||
|
||||
// Create an MQTT Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
|
||||
void _createMqttSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement);
|
||||
|
||||
public:
|
||||
void setup();
|
||||
void loop();
|
||||
inline float getIlluminance() {
|
||||
return (float)lastLux;
|
||||
}
|
||||
|
||||
void addToJsonInfo(JsonObject &root);
|
||||
|
||||
// (called from set.cpp) stores persistent properties to cfg.json
|
||||
void addToConfig(JsonObject &root);
|
||||
|
||||
// called before setup() to populate properties from values stored in cfg.json
|
||||
bool readFromConfig(JsonObject &root);
|
||||
|
||||
inline uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_BH1750;
|
||||
}
|
||||
|
||||
};
|
||||
7
usermods/BH1750_v2/library.json
Normal file
7
usermods/BH1750_v2/library.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "BH1750_v2",
|
||||
"build": { "libArchive": false },
|
||||
"dependencies": {
|
||||
"claws/BH1750":"^1.2.0"
|
||||
}
|
||||
}
|
||||
46
usermods/BH1750_v2/readme.md
Normal file
46
usermods/BH1750_v2/readme.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# BH1750 usermod
|
||||
|
||||
This usermod will read from an ambient light sensor like the BH1750.
|
||||
The luminance is displayed in both the Info section of the web UI, as well as published to the `/luminance` MQTT topic if enabled.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Libraries
|
||||
- `claws/BH1750 @^1.2.0`
|
||||
- Data is published over MQTT - make sure you've enabled the MQTT sync interface.
|
||||
|
||||
## Compilation
|
||||
|
||||
To enable, compile with `BH1750` in `custom_usermods` (e.g. in `platformio_override.ini`)
|
||||
|
||||
### Configuration Options
|
||||
|
||||
The following settings can be set at compile-time but are configurable on the usermod menu (except First Measurement time):
|
||||
|
||||
- `USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL` - the max number of milliseconds between measurements, defaults to 10000ms
|
||||
- `USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL` - the min number of milliseconds between measurements, defaults to 500ms
|
||||
- `USERMOD_BH1750_OFFSET_VALUE` - the offset value to report on, defaults to 1
|
||||
- `USERMOD_BH1750_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 10000 ms
|
||||
|
||||
In addition, the Usermod screen allows you to:
|
||||
|
||||
- enable/disable the usermod
|
||||
- Enable Home Assistant Discovery of usermod
|
||||
- Configure the SCL/SDA pins
|
||||
|
||||
## API
|
||||
|
||||
The following method is available to interact with the usermod from other code modules:
|
||||
|
||||
- `getIlluminance` read the brightness from the sensor
|
||||
|
||||
## Change Log
|
||||
|
||||
Jul 2022
|
||||
|
||||
- Added Home Assistant Discovery
|
||||
- Implemented PinManager to register pins
|
||||
- Made pins configurable in usermod menu
|
||||
- Added API call to read luminance from other modules
|
||||
- Enhanced info-screen outputs
|
||||
- Updated `readme.md`
|
||||
483
usermods/BME280_v2/BME280_v2.cpp
Normal file
483
usermods/BME280_v2/BME280_v2.cpp
Normal file
@@ -0,0 +1,483 @@
|
||||
// force the compiler to show a warning to confirm that this file is included
|
||||
#warning **** Included USERMOD_BME280 version 2.0 ****
|
||||
|
||||
#include "wled.h"
|
||||
#include <Arduino.h>
|
||||
#include <BME280I2C.h> // BME280 sensor
|
||||
#include <EnvironmentCalculations.h> // BME280 extended measurements
|
||||
|
||||
#ifdef WLED_DISABLE_MQTT
|
||||
#error "This user mod requires MQTT to be enabled."
|
||||
#endif
|
||||
|
||||
class UsermodBME280 : public Usermod
|
||||
{
|
||||
private:
|
||||
|
||||
// NOTE: Do not implement any compile-time variables, anything the user needs to configure
|
||||
// should be configurable from the Usermod menu using the methods below
|
||||
// key settings set via usermod menu
|
||||
uint8_t TemperatureDecimals = 0; // Number of decimal places in published temperaure values
|
||||
uint8_t HumidityDecimals = 0; // Number of decimal places in published humidity values
|
||||
uint8_t PressureDecimals = 0; // Number of decimal places in published pressure values
|
||||
uint16_t TemperatureInterval = 5; // Interval to measure temperature (and humidity, dew point if available) in seconds
|
||||
uint16_t PressureInterval = 300; // Interval to measure pressure in seconds
|
||||
BME280I2C::I2CAddr I2CAddress = BME280I2C::I2CAddr_0x76; // i2c address, defaults to 0x76
|
||||
bool PublishAlways = false; // Publish values even when they have not changed
|
||||
bool UseCelsius = true; // Use Celsius for Reporting
|
||||
bool HomeAssistantDiscovery = false; // Publish Home Assistant Device Information
|
||||
bool enabled = true;
|
||||
|
||||
// set the default pins based on the architecture, these get overridden by Usermod menu settings
|
||||
#ifdef ESP8266
|
||||
//uint8_t RST_PIN = 16; // Un-comment for Heltec WiFi-Kit-8
|
||||
#endif
|
||||
bool initDone = false;
|
||||
|
||||
BME280I2C bme;
|
||||
|
||||
uint8_t sensorType;
|
||||
|
||||
// Measurement timers
|
||||
long timer;
|
||||
long lastTemperatureMeasure = 0;
|
||||
long lastPressureMeasure = 0;
|
||||
|
||||
// Current sensor values
|
||||
float sensorTemperature;
|
||||
float sensorHumidity;
|
||||
float sensorHeatIndex;
|
||||
float sensorDewPoint;
|
||||
float sensorPressure;
|
||||
String tempScale;
|
||||
// Track previous sensor values
|
||||
float lastTemperature;
|
||||
float lastHumidity;
|
||||
float lastHeatIndex;
|
||||
float lastDewPoint;
|
||||
float lastPressure;
|
||||
|
||||
// MQTT topic strings for publishing Home Assistant discovery topics
|
||||
bool mqttInitialized = false;
|
||||
|
||||
// strings to reduce flash memory usage (used more than twice)
|
||||
static const char _name[];
|
||||
static const char _enabled[];
|
||||
|
||||
// Read the BME280/BMP280 Sensor (which one runs depends on whether Celsius or Fahrenheit being set in Usermod Menu)
|
||||
void UpdateBME280Data(int SensorType)
|
||||
{
|
||||
float _temperature, _humidity, _pressure;
|
||||
|
||||
if (UseCelsius) {
|
||||
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
|
||||
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Celsius);
|
||||
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
||||
|
||||
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
|
||||
|
||||
sensorTemperature = _temperature;
|
||||
sensorHumidity = _humidity;
|
||||
sensorPressure = _pressure;
|
||||
tempScale = F("°C");
|
||||
if (sensorType == 1)
|
||||
{
|
||||
sensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
|
||||
sensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
|
||||
}
|
||||
} else {
|
||||
BME280::TempUnit tempUnit(BME280::TempUnit_Fahrenheit);
|
||||
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Fahrenheit);
|
||||
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
||||
|
||||
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
|
||||
|
||||
sensorTemperature = _temperature;
|
||||
sensorHumidity = _humidity;
|
||||
sensorPressure = _pressure;
|
||||
tempScale = F("°F");
|
||||
if (sensorType == 1)
|
||||
{
|
||||
sensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
|
||||
sensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Procedure to define all MQTT discovery Topics
|
||||
void _mqttInitialize()
|
||||
{
|
||||
char mqttTemperatureTopic[128];
|
||||
char mqttHumidityTopic[128];
|
||||
char mqttPressureTopic[128];
|
||||
char mqttHeatIndexTopic[128];
|
||||
char mqttDewPointTopic[128];
|
||||
snprintf_P(mqttTemperatureTopic, 127, PSTR("%s/temperature"), mqttDeviceTopic);
|
||||
snprintf_P(mqttPressureTopic, 127, PSTR("%s/pressure"), mqttDeviceTopic);
|
||||
snprintf_P(mqttHumidityTopic, 127, PSTR("%s/humidity"), mqttDeviceTopic);
|
||||
snprintf_P(mqttHeatIndexTopic, 127, PSTR("%s/heat_index"), mqttDeviceTopic);
|
||||
snprintf_P(mqttDewPointTopic, 127, PSTR("%s/dew_point"), mqttDeviceTopic);
|
||||
|
||||
if (HomeAssistantDiscovery) {
|
||||
_createMqttSensor(F("Temperature"), mqttTemperatureTopic, "temperature", tempScale);
|
||||
_createMqttSensor(F("Pressure"), mqttPressureTopic, "pressure", F("hPa"));
|
||||
_createMqttSensor(F("Humidity"), mqttHumidityTopic, "humidity", F("%"));
|
||||
_createMqttSensor(F("HeatIndex"), mqttHeatIndexTopic, "temperature", tempScale);
|
||||
_createMqttSensor(F("DewPoint"), mqttDewPointTopic, "temperature", tempScale);
|
||||
}
|
||||
}
|
||||
|
||||
// Create an MQTT Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
|
||||
void _createMqttSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement)
|
||||
{
|
||||
String t = String(F("homeassistant/sensor/")) + mqttClientID + F("/") + name + F("/config");
|
||||
|
||||
StaticJsonDocument<600> doc;
|
||||
|
||||
doc[F("name")] = String(serverDescription) + " " + name;
|
||||
doc[F("state_topic")] = topic;
|
||||
doc[F("unique_id")] = String(mqttClientID) + name;
|
||||
if (unitOfMeasurement != "")
|
||||
doc[F("unit_of_measurement")] = unitOfMeasurement;
|
||||
if (deviceClass != "")
|
||||
doc[F("device_class")] = deviceClass;
|
||||
doc[F("expire_after")] = 1800;
|
||||
|
||||
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
|
||||
device[F("name")] = serverDescription;
|
||||
device[F("identifiers")] = "wled-sensor-" + String(mqttClientID);
|
||||
device[F("manufacturer")] = F(WLED_BRAND);
|
||||
device[F("model")] = F(WLED_PRODUCT_NAME);
|
||||
device[F("sw_version")] = versionString;
|
||||
|
||||
String temp;
|
||||
serializeJson(doc, temp);
|
||||
DEBUG_PRINTLN(t);
|
||||
DEBUG_PRINTLN(temp);
|
||||
|
||||
mqtt->publish(t.c_str(), 0, true, temp.c_str());
|
||||
}
|
||||
|
||||
void publishMqtt(const char *topic, const char* state) {
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (WLED_MQTT_CONNECTED){
|
||||
char subuf[128];
|
||||
snprintf_P(subuf, 127, PSTR("%s/%s"), mqttDeviceTopic, topic);
|
||||
mqtt->publish(subuf, 0, false, state);
|
||||
}
|
||||
}
|
||||
|
||||
void initializeBmeComms()
|
||||
{
|
||||
BME280I2C::Settings settings{
|
||||
BME280::OSR_X16, // Temperature oversampling x16
|
||||
BME280::OSR_X16, // Humidity oversampling x16
|
||||
BME280::OSR_X16, // Pressure oversampling x16
|
||||
BME280::Mode_Forced,
|
||||
BME280::StandbyTime_1000ms,
|
||||
BME280::Filter_Off,
|
||||
BME280::SpiEnable_False,
|
||||
I2CAddress
|
||||
};
|
||||
|
||||
bme.setSettings(settings);
|
||||
|
||||
if (!bme.begin())
|
||||
{
|
||||
sensorType = 0;
|
||||
DEBUG_PRINTLN(F("Could not find BME280 I2C sensor!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (bme.chipModel())
|
||||
{
|
||||
case BME280::ChipModel_BME280:
|
||||
sensorType = 1;
|
||||
DEBUG_PRINTLN(F("Found BME280 sensor! Success."));
|
||||
break;
|
||||
case BME280::ChipModel_BMP280:
|
||||
sensorType = 2;
|
||||
DEBUG_PRINTLN(F("Found BMP280 sensor! No Humidity available."));
|
||||
break;
|
||||
default:
|
||||
sensorType = 0;
|
||||
DEBUG_PRINTLN(F("Found UNKNOWN sensor! Error!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void setup()
|
||||
{
|
||||
if (i2c_scl<0 || i2c_sda<0) { enabled = false; sensorType = 0; return; }
|
||||
|
||||
initializeBmeComms();
|
||||
initDone = true;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (!enabled || strip.isUpdating()) return;
|
||||
|
||||
// BME280 sensor MQTT publishing
|
||||
// Check if sensor present and Connected, otherwise it will crash the MCU
|
||||
if (sensorType != 0)
|
||||
{
|
||||
// Timer to fetch new temperature, humidity and pressure data at intervals
|
||||
timer = millis();
|
||||
|
||||
if (timer - lastTemperatureMeasure >= TemperatureInterval * 1000)
|
||||
{
|
||||
lastTemperatureMeasure = timer;
|
||||
|
||||
UpdateBME280Data(sensorType);
|
||||
|
||||
float temperature = roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
float humidity, heatIndex, dewPoint;
|
||||
|
||||
// If temperature has changed since last measure, create string populated with device topic
|
||||
// from the UI and values read from sensor, then publish to broker
|
||||
if (temperature != lastTemperature || PublishAlways)
|
||||
{
|
||||
publishMqtt("temperature", String(temperature, (unsigned) TemperatureDecimals).c_str());
|
||||
}
|
||||
|
||||
lastTemperature = temperature; // Update last sensor temperature for next loop
|
||||
|
||||
if (sensorType == 1) // Only if sensor is a BME280
|
||||
{
|
||||
humidity = roundf(sensorHumidity * powf(10, HumidityDecimals)) / powf(10, HumidityDecimals);
|
||||
heatIndex = roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
dewPoint = roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
|
||||
if (humidity != lastHumidity || PublishAlways)
|
||||
{
|
||||
publishMqtt("humidity", String(humidity, (unsigned) HumidityDecimals).c_str());
|
||||
}
|
||||
|
||||
if (heatIndex != lastHeatIndex || PublishAlways)
|
||||
{
|
||||
publishMqtt("heat_index", String(heatIndex, (unsigned) TemperatureDecimals).c_str());
|
||||
}
|
||||
|
||||
if (dewPoint != lastDewPoint || PublishAlways)
|
||||
{
|
||||
publishMqtt("dew_point", String(dewPoint, (unsigned) TemperatureDecimals).c_str());
|
||||
}
|
||||
|
||||
lastHumidity = humidity;
|
||||
lastHeatIndex = heatIndex;
|
||||
lastDewPoint = dewPoint;
|
||||
}
|
||||
}
|
||||
|
||||
if (timer - lastPressureMeasure >= PressureInterval * 1000)
|
||||
{
|
||||
lastPressureMeasure = timer;
|
||||
|
||||
float pressure = roundf(sensorPressure * powf(10, PressureDecimals)) / powf(10, PressureDecimals);
|
||||
|
||||
if (pressure != lastPressure || PublishAlways)
|
||||
{
|
||||
publishMqtt("pressure", String(pressure, (unsigned) PressureDecimals).c_str());
|
||||
}
|
||||
|
||||
lastPressure = pressure;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onMqttConnect(bool sessionPresent)
|
||||
{
|
||||
if (WLED_MQTT_CONNECTED && !mqttInitialized)
|
||||
{
|
||||
_mqttInitialize();
|
||||
mqttInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* API calls te enable data exchange between WLED modules
|
||||
*/
|
||||
inline float getTemperatureC() {
|
||||
if (UseCelsius) {
|
||||
return (float)roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
} else {
|
||||
return (float)roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) * 1.8f + 32;
|
||||
}
|
||||
}
|
||||
|
||||
inline float getTemperatureF() {
|
||||
if (UseCelsius) {
|
||||
return ((float)roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) -32) * 0.56f;
|
||||
} else {
|
||||
return (float)roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
}
|
||||
}
|
||||
|
||||
inline float getHumidity() {
|
||||
return (float)roundf(sensorHumidity * powf(10, HumidityDecimals));
|
||||
}
|
||||
|
||||
inline float getPressure() {
|
||||
return (float)roundf(sensorPressure * powf(10, PressureDecimals));
|
||||
}
|
||||
|
||||
inline float getDewPointC() {
|
||||
if (UseCelsius) {
|
||||
return (float)roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
} else {
|
||||
return (float)roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) * 1.8f + 32;
|
||||
}
|
||||
}
|
||||
|
||||
inline float getDewPointF() {
|
||||
if (UseCelsius) {
|
||||
return ((float)roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) -32) * 0.56f;
|
||||
} else {
|
||||
return (float)roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
}
|
||||
}
|
||||
|
||||
inline float getHeatIndexC() {
|
||||
if (UseCelsius) {
|
||||
return (float)roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
} else {
|
||||
return (float)roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) * 1.8f + 32;
|
||||
}
|
||||
}
|
||||
|
||||
inline float getHeatIndexF() {
|
||||
if (UseCelsius) {
|
||||
return ((float)roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) -32) * 0.56f;
|
||||
} else {
|
||||
return (float)roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||
}
|
||||
}
|
||||
|
||||
// Publish Sensor Information to Info Page
|
||||
void addToJsonInfo(JsonObject &root)
|
||||
{
|
||||
JsonObject user = root[F("u")];
|
||||
if (user.isNull()) user = root.createNestedObject(F("u"));
|
||||
|
||||
if (sensorType==0) //No Sensor
|
||||
{
|
||||
// if we sensor not detected, let the user know
|
||||
JsonArray temperature_json = user.createNestedArray(F("BME/BMP280 Sensor"));
|
||||
temperature_json.add(F("Not Found"));
|
||||
}
|
||||
else if (sensorType==2) //BMP280
|
||||
{
|
||||
JsonArray temperature_json = user.createNestedArray(F("Temperature"));
|
||||
JsonArray pressure_json = user.createNestedArray(F("Pressure"));
|
||||
temperature_json.add(roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals));
|
||||
temperature_json.add(tempScale);
|
||||
pressure_json.add(roundf(sensorPressure * powf(10, PressureDecimals)) / powf(10, PressureDecimals));
|
||||
pressure_json.add(F("hPa"));
|
||||
}
|
||||
else if (sensorType==1) //BME280
|
||||
{
|
||||
JsonArray temperature_json = user.createNestedArray(F("Temperature"));
|
||||
JsonArray humidity_json = user.createNestedArray(F("Humidity"));
|
||||
JsonArray pressure_json = user.createNestedArray(F("Pressure"));
|
||||
JsonArray heatindex_json = user.createNestedArray(F("Heat Index"));
|
||||
JsonArray dewpoint_json = user.createNestedArray(F("Dew Point"));
|
||||
temperature_json.add(roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals));
|
||||
temperature_json.add(tempScale);
|
||||
humidity_json.add(roundf(sensorHumidity * powf(10, HumidityDecimals)) / powf(10, HumidityDecimals));
|
||||
humidity_json.add(F("%"));
|
||||
pressure_json.add(roundf(sensorPressure * powf(10, PressureDecimals)) / powf(10, PressureDecimals));
|
||||
pressure_json.add(F("hPa"));
|
||||
heatindex_json.add(roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals));
|
||||
heatindex_json.add(tempScale);
|
||||
dewpoint_json.add(roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals));
|
||||
dewpoint_json.add(tempScale);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Save Usermod Config Settings
|
||||
void addToConfig(JsonObject& root)
|
||||
{
|
||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||
top[FPSTR(_enabled)] = enabled;
|
||||
top[F("I2CAddress")] = static_cast<uint8_t>(I2CAddress);
|
||||
top[F("TemperatureDecimals")] = TemperatureDecimals;
|
||||
top[F("HumidityDecimals")] = HumidityDecimals;
|
||||
top[F("PressureDecimals")] = PressureDecimals;
|
||||
top[F("TemperatureInterval")] = TemperatureInterval;
|
||||
top[F("PressureInterval")] = PressureInterval;
|
||||
top[F("PublishAlways")] = PublishAlways;
|
||||
top[F("UseCelsius")] = UseCelsius;
|
||||
top[F("HomeAssistantDiscovery")] = HomeAssistantDiscovery;
|
||||
DEBUG_PRINTLN(F("BME280 config saved."));
|
||||
}
|
||||
|
||||
// Read Usermod Config Settings
|
||||
bool readFromConfig(JsonObject& root)
|
||||
{
|
||||
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
||||
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
|
||||
|
||||
JsonObject top = root[FPSTR(_name)];
|
||||
if (top.isNull()) {
|
||||
DEBUG_PRINT(F(_name));
|
||||
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||
return false;
|
||||
}
|
||||
bool configComplete = !top.isNull();
|
||||
|
||||
configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled);
|
||||
// A 3-argument getJsonValue() assigns the 3rd argument as a default value if the Json value is missing
|
||||
uint8_t tmpI2cAddress;
|
||||
configComplete &= getJsonValue(top[F("I2CAddress")], tmpI2cAddress, 0x76);
|
||||
I2CAddress = static_cast<BME280I2C::I2CAddr>(tmpI2cAddress);
|
||||
|
||||
configComplete &= getJsonValue(top[F("TemperatureDecimals")], TemperatureDecimals, 1);
|
||||
configComplete &= getJsonValue(top[F("HumidityDecimals")], HumidityDecimals, 0);
|
||||
configComplete &= getJsonValue(top[F("PressureDecimals")], PressureDecimals, 0);
|
||||
configComplete &= getJsonValue(top[F("TemperatureInterval")], TemperatureInterval, 30);
|
||||
configComplete &= getJsonValue(top[F("PressureInterval")], PressureInterval, 30);
|
||||
configComplete &= getJsonValue(top[F("PublishAlways")], PublishAlways, false);
|
||||
configComplete &= getJsonValue(top[F("UseCelsius")], UseCelsius, true);
|
||||
configComplete &= getJsonValue(top[F("HomeAssistantDiscovery")], HomeAssistantDiscovery, false);
|
||||
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
if (!initDone) {
|
||||
// first run: reading from cfg.json
|
||||
DEBUG_PRINTLN(F(" config loaded."));
|
||||
} else {
|
||||
// changing parameters from settings page
|
||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||
|
||||
// Reset all known values
|
||||
sensorType = 0;
|
||||
sensorTemperature = 0;
|
||||
sensorHumidity = 0;
|
||||
sensorHeatIndex = 0;
|
||||
sensorDewPoint = 0;
|
||||
sensorPressure = 0;
|
||||
lastTemperature = 0;
|
||||
lastHumidity = 0;
|
||||
lastHeatIndex = 0;
|
||||
lastDewPoint = 0;
|
||||
lastPressure = 0;
|
||||
|
||||
initializeBmeComms();
|
||||
}
|
||||
|
||||
return configComplete;
|
||||
}
|
||||
|
||||
uint16_t getId() {
|
||||
return USERMOD_ID_BME280;
|
||||
}
|
||||
};
|
||||
|
||||
const char UsermodBME280::_name[] PROGMEM = "BME280/BMP280";
|
||||
const char UsermodBME280::_enabled[] PROGMEM = "enabled";
|
||||
|
||||
|
||||
static UsermodBME280 bme280_v2;
|
||||
REGISTER_USERMOD(bme280_v2);
|
||||
84
usermods/BME280_v2/README.md
Normal file
84
usermods/BME280_v2/README.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# Usermod BME280
|
||||
This Usermod is designed to read a `BME280` or `BMP280` sensor and output the following:
|
||||
- Temperature
|
||||
- Humidity (`BME280` only)
|
||||
- Pressure
|
||||
- Heat Index (`BME280` only)
|
||||
- Dew Point (`BME280` only)
|
||||
|
||||
Configuration is performed via the Usermod menu. There are no parameters to set in code! The following settings can be configured in the Usermod Menu:
|
||||
- The i2c address in decimal. Set it to either 118 (0x76, the default) or 119 (0x77).
|
||||
- Temperature Decimals (number of decimal places to output)
|
||||
- Humidity Decimals
|
||||
- Pressure Decimals
|
||||
- Temperature Interval (how many seconds between temperature and humidity measurements)
|
||||
- Pressure Interval
|
||||
- Publish Always (turn off to only publish changes, on to publish whether or not value changed)
|
||||
- Use Celsius (turn off to use Fahrenheit)
|
||||
- Home Assistant Discovery (turn on to sent MQTT Discovery entries for Home Assistant)
|
||||
- SCL/SDA GPIO Pins
|
||||
|
||||
Dependencies
|
||||
- Libraries
|
||||
- `BME280@~3.0.0` (by [finitespace](https://github.com/finitespace/BME280))
|
||||
- `Wire`
|
||||
- Data is published over MQTT - make sure you've enabled the MQTT sync interface.
|
||||
- This usermod also writes to serial (GPIO1 on ESP8266). Please make sure nothing else is listening to the serial TX pin or your board will get confused by log messages!
|
||||
|
||||
In addition to outputting via MQTT, you can read the values from the Info Screen on the dashboard page of the device's web interface.
|
||||
|
||||
Methods also exist to read the read/calculated values from other WLED modules through code.
|
||||
- `getTemperatureC()`
|
||||
- `getTemperatureF()`
|
||||
- `getHumidity()`
|
||||
- `getPressure()`
|
||||
- `getDewPointC()`
|
||||
- `getDewPointF()`
|
||||
- `getHeatIndexC()`
|
||||
- `getHeatIndexF()`
|
||||
|
||||
# Compiling
|
||||
|
||||
To enable, add `BME280_v2` to your `custom_usermods` (e.g. in `platformio_override.ini`)
|
||||
```ini
|
||||
[env:usermod_bme280_d1_mini]
|
||||
extends = env:d1_mini
|
||||
custom_usermods = ${env:d1_mini.custom_usermods} BME280_v2
|
||||
```
|
||||
|
||||
|
||||
# MQTT
|
||||
MQTT topics are as follows (`<deviceTopic>` is set in MQTT section of Sync Setup menu):
|
||||
Measurement type | MQTT topic
|
||||
--- | ---
|
||||
Temperature | `<deviceTopic>/temperature`
|
||||
Humidity | `<deviceTopic>/humidity`
|
||||
Pressure | `<deviceTopic>/pressure`
|
||||
Heat index | `<deviceTopic>/heat_index`
|
||||
Dew point | `<deviceTopic>/dew_point`
|
||||
|
||||
If you are using Home Assistant, and `Home Assistant Discovery` is turned on, Home Assistant should automatically detect a new device, provided you have the MQTT integration installed. The device is separate from the main WLED device and will contain sensors for Pressure, Humidity, Temperature, Dew Point and Heat Index.
|
||||
|
||||
# Revision History
|
||||
Jul 2022
|
||||
- Added Home Assistant Discovery
|
||||
- Added API interface to output data
|
||||
- Removed compile-time variables
|
||||
- Added usermod menu interface
|
||||
- Added value outputs to info screen
|
||||
- Updated `readme.md`
|
||||
- Registered usermod
|
||||
- Implemented PinManager for usermod
|
||||
- Implemented reallocation of pins without reboot
|
||||
|
||||
Apr 2021
|
||||
- Added `Publish Always` option
|
||||
|
||||
Dec 2020
|
||||
- Ported to V2 Usermod format
|
||||
- Customizable `measure intervals`
|
||||
- Customizable number of `decimal places` in published sensor values
|
||||
- Pressure measured in units of hPa instead of Pa
|
||||
- Calculation of heat index (apparent temperature) and dew point
|
||||
- `16x oversampling` of sensor during measurement
|
||||
- Values only published if they are different from the previous value
|
||||
7
usermods/BME280_v2/library.json
Normal file
7
usermods/BME280_v2/library.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "BME280_v2",
|
||||
"build": { "libArchive": false },
|
||||
"dependencies": {
|
||||
"finitespace/BME280":"~3.0.0"
|
||||
}
|
||||
}
|
||||
BIN
usermods/BME68X_v2/BME680.pdf
Normal file
BIN
usermods/BME68X_v2/BME680.pdf
Normal file
Binary file not shown.
1114
usermods/BME68X_v2/BME68X_v2.cpp
Normal file
1114
usermods/BME68X_v2/BME68X_v2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user