Compare commits

...

281 Commits

Author SHA1 Message Date
cschwinne
3a3948e74f Release of WLED v0.11.0 2020-11-29 22:07:12 +01:00
Def3nder
c01dd232c5 FIX IR_PIN to IRPIN (#1394)
...in cfg.cpp the if statement used "IRPIN" (which is consistent to all other PIN names), but on the declaration-side "IR_PIN" was used.

Changed all occurences of "IR_PIN" to "IRPIN".
2020-11-29 20:47:13 +01:00
Aircoookie
825cc096c0 Merge pull request #1393 from danecreekphotography/devcontainer
Add support for VSCode devcontainer development
2020-11-29 17:49:27 +01:00
Neil Enns
bcd574036e Add python devcontainer config 2020-11-29 14:33:59 +00:00
larrywal
e33a0bf940 Update custom32_LEDPIN_16 build config to use the right relay pin (#1385)
The Quin-Dig-Quad has the relay pin on IO19 (Q3).  However, it is on IO12 by default.  Update the build flags for the custom32_LEDPIN_16 build to also move the relay pin to IO19 so it works properly with the board.
2020-11-28 00:19:49 +01:00
cschwinne
fb91d9b2d4 Color order override macros 2020-11-27 23:59:00 +01:00
Aircoookie
ac010cd7b2 Merge pull request #1378 from andyshinn/feature/slider-value-display
Display tooltip with value on slider change
2020-11-26 23:17:13 +01:00
cschwinne
d0c94ba565 Center slider tooltips and hide on very small screens 2020-11-26 23:07:15 +01:00
cschwinne
adbeb4ae54 Add live property to state, allowing toggling of realtime (not incl. in state resp.) ( #1308 ) 2020-11-26 10:54:37 +01:00
Andy Shinn
c7e1b47c59 display tooltip on slider value change 2020-11-24 23:34:47 -06:00
Aircoookie
b25e22bca4 Merge pull request #1362 from broccoliboy/esp32_multistrip
ESP32 multiple data pin outputs
2020-11-23 01:01:51 +01:00
toto79
6cb6a8ee98 create stairway-wipe-for-usermod-v2 (#1359)
* create stairway-wipe-for-usermod-v2

* Update and rename stairway-wipe-usermod.h to stairway-wipe-usermod-v2.h
2020-11-23 01:00:02 +01:00
cschwinne
223bd969fd Version bump to 0.11.0 "Mirai"
Improved preset name sorting
Fixed Preset cycle not working beyond preset 16
2020-11-23 00:58:58 +01:00
cschwinne
ae46eeabef Fixed invalid save when modifying preset before refresh (might be related to #1361)
Fixed brightness factor ignored on realtime timeout (fixes #1363)
Fixed Phase and Chase effects with LED counts >256 (PR #1366)
2020-11-23 00:10:14 +01:00
Def3nder
79c83a96a0 Fix code for long LED strips (>256 LEDs long) (#1366)
* Alexa RGBW Support

When adding an RGBW device to Alexa and then selecting a white color tone, Alexa will send CT values to the device. Having a warm white or cold white strip should use 100% of that strip and then add the RGB colors to get either a warmer color or a colder one.

* 40 keys IR Remote 

Added IR remote with 40 keys to use with RGBW stripes.

* ESU8285 flash size corrected

* ESP32 fixes for Solid RGBW

...not implemented for ESP32 yet
ESP32 Solid RGBW defines

moved from env:esp32dev to env:esp32
ESP32 Solid RGBW defines

* Update readme.md

* Update readme.md

* Update readme.md
Update readme.md

* Use different IR remotes in the settings

To turn off IR remote use "0" in the settings, use 1 to 4 for different IR remote types.

* Use 5CH solid RGB stripes

adapt the logic to use CW and WW for different CT-values

* change from Opt-Out to Opt-In for solid (analoge) RGB stripes

Changed code from #define WLED_DISABLE_ANALOG_LEDS to #define WLED_USE_ANALOG_LEDS

* DEFINES for different devices added

* order of PINs alligned to hardware

* Update readme.md

* correct initialization of variable rgb[]

* SunRise Effect

NightLight used to brighten the light combined with fading from the actual (primary) color to the secondary color

* Fixed headline

RLYPIN definition dependant on WLED_USE_ANALOG_LEDS

Corrected list-item indents (readme.md)

updated to match upstream master (briLast in wled00.ino)

* Updates to adopt to upstream master

RLYPIN definition dependant on WLED_USE_ANALOG_LEDS

Fixed headline and corrected list-item indents (readme.md)

updated to match upstream master (briLast in wled00.ino)

* Sync with upstream master

* PIO ini correction

* sync of upstream readme.md

* FX intensity slider to desaturate Color in Colorloop FX

in default intensity (128) everything looks the same, decreasing the intensity will desaturate the color towards WHITE

* PIO changes

* adjusted linker scripts, debug settings etc.

* Override script updated accordingly

* ldscriipt for 1m0 adjusted

* backup files deleted

* deletion of wled00,ino.cpp

* remove travis build from PIO

* add custom builds to PIO

...to map the releases

* removed build_type = release (as this is default)

* updated to use espressif8266@2.3.3

...instead of espressif8266@2.3.2  (both on arduino 2.6.3)

* added more options to the PIO-override.ini

* analog, too

* build only 5 envs with Travis.CI

* should be include not exclude

* YAML correction

* next YAML

* UNDO

* some effects behave wrong with strips longer then 256 LEDs

This is particular true for the effects "Phased" and "Phased Noise" as well as for "Chase Rainbow".

The reason is that in this cases 256 is divided by SEGLEN and used in the formula, but with SEGLEN greater than 256 the integer result will always be ZERO.
2020-11-23 00:06:57 +01:00
Sam Martin
db33eb5b1f esp32_multistrip usermod enables driving up to 8 LED strips using RMT hardware accelerated pixel data pushing 2020-11-21 21:25:38 -06:00
cschwinne
bc45f8f1d8 Fixed Brightness slider beneath color wheel not working (fixes #1360)
Fixed invalid UI state after saving modified preset
2020-11-21 22:23:00 +01:00
Aircoookie
7875a96137 Merge pull request #1355 from Aircoookie/filesystem
The wait is almost over
2020-11-20 01:06:54 +01:00
cschwinne
4875f5e275 BTNPIN can now be disabled by setting to -1 (fixes #1237)
Added HEX color receiving to JSON API
Moved Kelvin color receiving in JSON API
2020-11-20 00:33:17 +01:00
Aircoookie
7f9da22626 Merge pull request #1356 from mcqn/fix-bug-with-mqtt-group-topics
Fix bug where messages sent to the group topic were incorrectly ignored
2020-11-19 11:47:47 +01:00
Adrian McEwen
78098e612d Fix bug where messages sent to the group topic were incorrectly ignored. Fixes #5 2020-11-19 00:01:21 +00:00
cschwinne
e19ab9a0d5 Add Hawaii time (resolves #1354 )
Platformio.ini updates and streamlining (PR #1266)
my_config.h custom compile settings system (not yet used for much, adapted from PR #1266)
Linebreak after 5 quick select buttons
2020-11-18 23:27:54 +01:00
Aircoookie
ace45516d9 Merge pull request #1352 from Aircoookie/1m_ota
Merge new platformio to FS branch
2020-11-18 10:52:30 +01:00
cschwinne
fe57bfce1b FS define 2020-11-18 09:45:07 +01:00
Aircoookie
453cc0cc05 Merge pull request #1353 from AbhiGulati/fix-hue-white
Fix Hue sync for RGBW white in XY color mode
2020-11-18 08:37:35 +01:00
Abhi Gulati
39009c482d Fix Hue sync for RGBW white in XY color mode 2020-11-17 23:18:30 -06:00
Aircoookie
6b942be1cd Merge branch 'filesystem' into 1m_ota 2020-11-18 01:05:51 +01:00
cschwinne
77aa2b6ba9 Streamline platformio.ini 2020-11-18 00:54:41 +01:00
cschwinne
074d53fa17 Fix a few compiler warnings 2020-11-17 22:46:17 +01:00
Jason2866
a839ec4832 Add gzip support for full OTA possibilitys for 1M build (#1266)
* delete history

* add firmware

Signed-off-by: Jason2866 <obermeier.johann@googlemail.com>

* Delete platformio_override.ini

* Update .gitignore

* Delete WLED_tasmota_1M.bin

* Delete WLED_tasmota_1M.bin.gz

* Update platformio.ini

* Core 2.7.4.5

* new override

* actual firmware

* Update user_config_override_sample.h

* Delete platformio_override.ini

* Delete WLED_tasmota_1M.bin

* Delete WLED_tasmota_1M.bin.gz

* core 2.7.4.7
2020-11-17 21:49:39 +01:00
cschwinne
5119799256 Fixed compilation when BTNPIN, IRPIN or RLYPIN not defined (fixes #1350 ) 2020-11-17 09:25:31 +01:00
cschwinne
176e18e4c0 Move Network class to src/dependencies (fixes #1349 ) 2020-11-17 08:57:05 +01:00
cschwinne
b697df35c6 A few more small fixes 2020-11-15 22:52:59 +01:00
cschwinne
5236625485 A few small fixes 2020-11-15 20:58:04 +01:00
cschwinne
f36073f5cd Add new 404 page 2020-11-15 16:37:09 +01:00
cschwinne
595fd9377c Remove FS defines
Increase boot preset max. to 250
Update changelog
Update readme
2020-11-15 15:45:51 +01:00
Aircoookie
76f4c49e22 Merge pull request #1341 from Aircoookie/mergefs-201115
Merge ethernet support to FS branch
2020-11-15 14:01:47 +01:00
Aircoookie
8c0592cdb7 Merge branch 'filesystem' into mergefs-201115 2020-11-15 13:21:56 +01:00
cschwinne
0c73ecf6a8 Added Pin Manager 2020-11-15 12:41:51 +01:00
tbnobody
c365fd9d74 Ethernet Support (#1316)
Ethernet Support
2020-11-13 18:25:13 +01:00
Aircoookie
aa8c587ac8 Merge pull request #1332 from Aircoookie/mergefs-201112
Update FS branch
2020-11-12 11:26:30 +01:00
Aircoookie
e9d9760e16 Merge branch 'filesystem' into mergefs-201112 2020-11-12 11:12:10 +01:00
cschwinne
560f72a320 Add JSON receiving to MQTT /api 2020-11-12 09:13:08 +01:00
cschwinne
3425f2bf34 Add Playlist feature 2020-11-11 23:48:14 +01:00
cschwinne
e28dbb3b93 Usermod callbacks for custom settings 2020-11-11 15:50:15 +01:00
Aircoookie
1b3ed80d37 Replace readme tutorials with link to tutorial overview wiki page 2020-11-10 23:36:28 +01:00
Aircoookie
89a2e15cfb Merge pull request #1302 from catlee/nightlight-remaining
Return remaining nightlight time in json API
2020-11-10 21:16:54 +01:00
Aircoookie
99b1282e98 Merge pull request #1317 from jsloyer/patch-1
correct the copyright year and add a link to the license
2020-11-10 13:47:56 +01:00
cschwinne
ed753b590c Add copyright and license link to .htm 2020-11-10 13:30:42 +01:00
Aircoookie
bda095b0ec Merge pull request #1325 from e850205/patch-1
Update readme.md
2020-11-10 13:27:12 +01:00
cschwinne
9d7f1d230c Only add 16 to macros if they are not 0 2020-11-09 20:48:44 +01:00
e850205
bdf0458780 Update readme.md 2020-11-09 13:14:24 -06:00
cschwinne
7f973ad131 Unaccessible wsec.json and preset loading fix 2020-11-09 11:09:47 +01:00
cschwinne
1f42070104 A few fixes 2020-11-09 00:50:13 +01:00
cschwinne
98e4ac6b27 FS working for ESP8266 2020-11-08 23:44:10 +01:00
Chris AtLee
8d318e7206 Return remaining nightlight time in json API
This returns the number of seconds remaining in the nightlight in the
"rem" field of the nightlight ("nl") state. If there is no nightlight
active, it returns -1.
2020-11-08 10:44:25 -05:00
cschwinne
362156c8ab F() 2020-11-07 23:54:56 +01:00
cschwinne
3ff23ade8b Done in principle 2020-11-06 22:12:48 +01:00
cschwinne
d9050dd8b9 Progress with parsers 2020-11-05 22:54:13 +01:00
Jeff Sloyer
bcee2c37d7 correct the copyright year and add a link to the license 2020-11-05 14:54:57 -05:00
cschwinne
b8fcab29ac Inversed Rain direction (fixes #1147) 2020-11-04 23:20:34 +01:00
cschwinne
8ddae6bba0 wsec start 2020-11-04 17:17:54 +01:00
cschwinne
fc9255cdc4 Added new file for JSON cfg parsing code 2020-11-04 11:04:40 +01:00
cschwinne
f725506df0 Settings deserialization 2020-11-03 00:35:04 +01:00
cschwinne
aa27b85538 Re added old C9 palette 2020-11-01 20:54:35 +01:00
Aircoookie
afe75f8a89 Merge pull request #1309 from herm/usermod_mqtt_switch
Usermod mqtt switch
2020-11-01 20:29:50 +01:00
Hermann Kraus
b725d66ee3 Add options for inverted switches and default values. 2020-11-01 18:08:30 +01:00
Hermann Kraus
fe3fb622ee New usermod: MQTT switches.
This user mod adds a function to toggle output pins via MQTT.
2020-11-01 16:27:23 +01:00
Aircoookie
e8bd114c01 Merge pull request #1307 from herm/mqtt_topic
Fix MQTT topic parsing.
2020-11-01 12:13:21 +01:00
Hermann Kraus
b694bcf62a Fix MQTT topic parsing.
The previous code only looked for certain keywords in the topic instead of comparing it completely.
For example if mqttDeviceTopic is set to "lights/colorRGB" the MQTT interface is unusable because
the search for "/col" will always return a match and therefore any MQTT command is interpreted as
a color.
The new code checks the full topic.
2020-11-01 02:23:37 +01:00
Aircoookie
b0f933c926 Merge pull request #1306 from Aircoookie/master
Update FS branch (yes, it is necessary)
2020-10-31 23:53:29 +01:00
Lech Perczak
2d12bc01de Change SP501A -> SP501E build configuration (#1305)
Fix a typo in previous commit. Correct board name is SP501E.

Signed-off-by: Lech Perczak <lech.perczak@gmail.com>
2020-10-31 23:51:52 +01:00
Lech Perczak
17b4ff7a1f Add build configuration for SP501A controller (#1303)
This controller uses ESP8285 with 2MB built-in flash.
Features:
- LED string is connected to GPIO3,
- On/off button connected to GPIO1,
- Built-in transistors to drive non-addressable R-G-B-Wc-Ww strips
  (by default not connected, only pads are present).

Signed-off-by: Lech Perczak <lech.perczak@gmail.com>
2020-10-31 21:41:44 +01:00
Aircoookie
6aff9f91d5 Merge pull request #1304 from Aircoookie/mergefs-201031
Update FS branch (again)
2020-10-31 21:33:59 +01:00
Aircoookie
cac8fd93e4 Merge branch 'filesystem' into mergefs-201031 2020-10-31 21:21:32 +01:00
Miha Frangež
f046abefbc Mention analog strips in README (#1297) 2020-10-29 20:29:15 +01:00
Aircoookie
b34e060b17 Merge pull request #1287 from huksley/html-es6
Use html-minifer-terser for ES6+ support
2020-10-29 16:59:43 +01:00
cschwinne
907be77ef4 Include minified JS 2020-10-29 10:14:21 +01:00
cschwinne
373d12be64 Realtime max. brightness now honors brightness factor (fixes #1271)
- Colorful effect now supports palettes
- Added C9 2 palette (#1291)
- Improved C9 palette brightness by 12%
- Disable onboard LED if LEDs are off (PR #1245)
- Added optional status LED (PR #1264)
- Realtime max. brightness now honors brightness factor (fixes #1271)
- Updated ArduinoJSON to 6.17.0
2020-10-29 01:23:04 +01:00
Ruslan Gainutdinov
bf45d55b4a Use html-minifer-terser for ES6+ support 2020-10-26 23:31:35 +02:00
cschwinne
2525429070 deEEP for presets 2020-10-23 17:48:01 +02:00
Aircoookie
2513bcf2c6 Merge pull request #1270 from Aircoookie/mergefs-201019
Update FS branch
2020-10-19 23:37:29 +02:00
Aircoookie
bbffb6d901 Merge branch 'filesystem' into mergefs-201019 2020-10-19 23:37:18 +02:00
cschwinne
3b7f5a1397 Merge branch 'master' of https://github.com/Aircoookie/WLED 2020-10-19 23:30:07 +02:00
cschwinne
600e949628 Update ArduinoJson-v6.h 2020-10-19 23:30:02 +02:00
Jeff Rescignano
235c123ad0 Add status led (#1264)
* Add status led

* Shorten code

* Fix "Shorten code"

* Change ledStatusType to an unsigned short
2020-10-19 18:08:45 +02:00
guilhermebera
dcea584a9a Update readme.md (#1257) 2020-10-17 12:13:41 +02:00
cschwinne
d583adb958 New quota calculation 2020-10-16 23:59:34 +02:00
Aircoookie
0d96a0fb7c Merge pull request #1255 from guilhermebera/patch-1
Update usermod_PIR_sensor_switch.h
2020-10-14 13:58:38 +02:00
guilhermebera
fb6b2cbfa2 Update usermod_PIR_sensor_switch.h
Current: If I disable PIR after it switch strip on, it'll switch off by timer.
Update: If I disable PIR after it switch strip on, it'll keep strip on.
2020-10-14 01:07:20 -03:00
cschwinne
eb65eafbe0 Working API commands 2020-10-13 01:39:34 +02:00
Jeff Rescignano
13f18492ad Disable onboard LED when LEDs are not in use (#1245)
* Disable onboard LED when LEDs are not in use

* Remove unused variable

* Only disable onboard LED if LEDPIN == LED_BUILTIN

* Change LEDPIN to LED_BUILTIN
2020-10-12 20:13:13 +02:00
Aircoookie
3d04541ee3 Merge pull request #1239 from rawframe/patch-1
Usermod PIR with Highlight & Standby modes and more control. (branched from Gegus PIR_sensor_switch)
2020-10-09 15:51:31 +02:00
Jeff Rescignano
6ded0cce12 [ImgBot] Optimize images (#1238)
*Total -- 2,546.93kb -> 2,358.92kb (7.38%)

/images/wled_logo_clean.png -- 2.48kb -> 0.59kb (76.3%)
/usermods/Enclosure_with_OLED_temp_ESP07/assets/pcb.png -- 235.03kb -> 201.10kb (14.43%)
/images/wled_logo.png -- 46.43kb -> 40.20kb (13.41%)
/images/wled_logo_akemi.png -- 24.41kb -> 21.60kb (11.5%)
/usermods/TTGO-T-Display/assets/ttgo_hardware1.png -- 685.48kb -> 613.17kb (10.55%)
/usermods/Enclosure_with_OLED_temp_ESP07/assets/controller.jpg -- 149.82kb -> 136.31kb (9.02%)
/usermods/battery_keypad_controller/assets/bat-key-ctrl-1.jpg -- 318.82kb -> 298.56kb (6.36%)
/usermods/battery_keypad_controller/assets/bat-key-ctrl-3.jpg -- 343.93kb -> 322.75kb (6.16%)
/usermods/battery_keypad_controller/assets/bat-key-ctrl-2.jpg -- 250.06kb -> 235.49kb (5.83%)
/images/macbook-pro-space-gray-on-the-wooden-table.jpg -- 490.48kb -> 489.15kb (0.27%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>

Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com>
2020-10-09 12:48:19 +02:00
rawframe
1ecbaf2c7f Create PIR_Highlight_Standby
* Rawframe edit:
 * - TESTED ON WLED VS.0.10.1 - WHERE ONLY PRESET 16 SAVES SEGMENTS - some macros may not be needed if this changes.
 * - Code has been modified as my usage changed, as such it has poor use of functions vs if thens, but feel free to change it for me :)
 * 
 * Edited to SWITCH between two lighting scenes/modes : STANDBY and HIGHLIGHT
 * 
 * Usage:
 *  - Standby is the default mode and Highlight is activated when the PIR detects activity.
 *  - PIR delay now set to same value as Nightlight feature on boot but otherwise controlled as normal.
 *  - Standby and Highlight brightness can be set on the fly (default values set on boot via macros calling presets).
 *  - Macros are used to set Standby and Highlight states (macros can load saved presets etc).
 * 
 *    - Macro short button press   =  Highlight state default (used on boot only and sets default brightness).
 *    - Macro double button press  =  Standby state default   (used on boot only and sets default brightness).
 *    - Macro long button press    =  Highlight state         (after boot).
 *    - Macro 16                   =  Standby state           (after boot).
 *
 *    ! It is advised not to set 'Apply preset at boot' or a boot macro (that activates a preset) as we will call our own macros on boot.
 * 
 *  - When the strip is off before PIR activates the strip will return to off for Standby mode, and vice versa.
 *  - When the strip is turned off while in Highlight mode, it will return to standby mode. (This behaviour could be changed easily if for some reason you wanted the lights to go out when the pir is activated).
 *  - Macros can be chained so you could do almost anything, such as have standby mode also turn on the nightlight function with a new time delay.
 * 
 * Segment Notes:
 * - It's easier to save the segment selections in preset than apply via macro while we a limited to preset 16. (Ie, instead of selecting sections at the point of activating standby/highlight modes). 
 * - Because only preset 16 saves segments, for now we are having to use additional macros to control segments where they are involved. Macros can be chained so this works but it would be better if macros also accepted json-api commands. (Testing http api segment behaviour of SS with SB left me a little confused).
 * 
 * Future:
 *  - Maybe a second timer/timetable that turns on/off standby mode also after set inactivity period / date & times. For now this can be achieved others ways so may not be worth eating more processing power.
2020-10-08 23:42:32 +01:00
cschwinne
b0828a6280 Bigger buffer testing 2020-10-08 00:52:15 +02:00
cschwinne
d2ffb3ca9d FQ quota and info 2020-10-07 17:48:22 +02:00
cschwinne
606cd18dc4 Working deletion
Added HTTP API support to JSON API
2020-10-03 00:29:36 +02:00
Aircoookie
8a713b2bbb Merge pull request #1218 from Aircoookie/mergefs-201002
Update FS branch
2020-10-02 13:49:13 +02:00
Aircoookie
c68f31a11c Merge branch 'filesystem' into mergefs-201002 2020-10-02 13:39:25 +02:00
cschwinne
3107943af8 Fixed interaction of T and NL HTTP API commands (#1214) 2020-10-02 12:30:17 +02:00
Aircoookie
bf9360f374 Merge pull request #1217 from Landrash/master
Add shield for license in Readme.md
2020-10-02 08:58:32 +02:00
cschwinne
f66c28a1bc Fix MQTT bootloop (no F() macro, #1199 ) 2020-09-29 21:41:52 +02:00
Aircoookie
5d6e214e0e Merge pull request #1213 from Aircoookie/ddp-protocol
DDP protocol
2020-09-29 01:18:05 +02:00
cschwinne
ee8596d175 DDP working 2020-09-29 01:13:29 +02:00
Landrash
3c900814be Add shield for license 2020-09-29 00:08:12 +02:00
cschwinne
52df963be9 DDP Support 2020-09-28 16:29:01 +02:00
Aircoookie
8c513c2aad Merge pull request #1208 from Phunkafizer/master
Added washing machine FX
2020-09-27 14:57:40 +02:00
cschwinne
1e3834dc3d Move tristate_square8 to FX_fcn.cpp 2020-09-27 14:42:14 +02:00
cschwinne
386b10a004 Update CHANGELOG.md 2020-09-27 11:53:24 +02:00
Aircoookie
f697f3d7ad Merge pull request #1209 from Aircoookie/merge-loxone
Merge loxone support
2020-09-27 11:49:08 +02:00
cschwinne
8d3ff16037 Add udpNotifier2 (JSON+HTTP, closes #1205 )
Added Loxone defines
Fix missing timezones (#1201)
2020-09-27 11:43:28 +02:00
m0fa
b10ab358da Loxone support added (#1185)
* A separate socket for UDP api has been added. This uses the same API as HTML. Commands for Loxone were added to the API.

* html files for udp api newly generated

* codm pixel controller board configurations added to platformio.ini file

* Parser for LX/LY commands adapted. Calculation of the values corrected. Segment handling for LX/LY removed.

* Lox parser moved to own file. Lox parser added to the JSON api. Within a segment LX and LY are now supported.

* serial port removed

* F() macro added

Co-authored-by: Marius Groos <marius.groos@codm.de>
2020-09-27 11:37:16 +02:00
S. Seegel
2cc6edd868 Added washing machine FX 2020-09-27 01:58:21 +02:00
Aircoookie
cac974b8e1 Merge pull request #1200 from Joeboyc2/patch-2
Add the ability to override R,G,B,WPIN values
2020-09-23 18:47:48 +02:00
Joeboyc2
2c02e27197 Add the ability to override R,G,B,WPIN values
Enable the ability to use the -D option in the platform_override.ini to set the pin numbers outside of the file
2020-09-23 16:49:55 +01:00
Aircoookie
85c0002a78 Merge pull request #1193 from Aircoookie/merge-fs2
Update FS branch
2020-09-22 08:34:23 +02:00
Aircoookie
bd65bf2175 Merge branch 'filesystem' into merge-fs2 2020-09-21 19:48:12 +02:00
cschwinne
d70332f2a2 Fixed LPD8806 compilation (#971) 2020-09-20 22:21:29 +02:00
cschwinne
35b54e2f88 Add CY=2 for cycle toggling (closes #1174) 2020-09-20 16:40:32 +02:00
Jake
a3e1af72ab Add ESP32 touch sensors as button alternative (#1190)
* Add touch option to button handler

* Check if touch is pressed in setup

* Add TOUCHPIN build env and override example

Co-authored-by: Aircoookie <dev.aircoookie@gmail.com>
2020-09-20 16:12:46 +02:00
Peter
1313a44ba3 ESP8266: Allow auto modem sleep if power off and sleep permitted (#1184)
* Allow modem sleep if power off and sleep permitted

* Only add auto modem sleep handling for ESP8266

* Add comment and remove redundant condition

Co-authored-by: Aircoookie <cschwinne@gmail.com>
2020-09-20 16:00:24 +02:00
cschwinne
edbe8131ab Reduce heap usage by 4kB 2020-09-20 01:18:31 +02:00
cschwinne
ff55a305cd Merge branch 'master' of https://github.com/Aircoookie/WLED 2020-09-17 10:40:36 +02:00
cschwinne
10c22efbb5 Fixed 170th pixel dark in E1.31 2020-09-17 10:40:32 +02:00
Aircoookie
118bbfbcf7 Merge pull request #1186 from antoni-k/patch-1
Fix typo
2020-09-17 09:35:24 +02:00
NeariX67
e7709d8463 Upload TouchBrightnessControl Usermod for ESP32 (#1183)
* Upload Usermod

* Fix missing : public Usermod

* Increased default threshold, added touchPin #define

Co-authored-by: Aircoookie <cschwinne@gmail.com>
2020-09-16 21:21:26 +02:00
Antoni K
d70e421db3 Fix typo
Added an "l" to Compatible PC RGB...
2020-09-16 12:39:45 +08:00
Andreas Perhab
0028c3c640 enable sliders with a different max value (#1156)
* enable sliders with a different max value

* Only change in index.htm for now

Co-authored-by: cschwinne <dev.aircoookie@gmail.com>
2020-09-15 21:59:12 +02:00
cschwinne
2594cb23c4 Merge branch 'filesystem' of https://github.com/Aircoookie/WLED into filesystem 2020-09-15 21:28:51 +02:00
cschwinne
d975f6e23a Update ArduinoJson to 6.16.1
Add fsinfo to JSON info
2020-09-15 21:28:43 +02:00
Aircoookie
5e46975c63 Merge pull request #1182 from Aircoookie/merge-200914
Merge master into filesystem
2020-09-14 17:00:10 +02:00
Aircoookie
16f41fc4b4 Merge branch 'filesystem' into merge-200914 2020-09-14 16:32:31 +02:00
cschwinne
1263f5e046 Presets work 2020-09-14 00:31:38 +02:00
cschwinne
96713ef383 LittleFS by default 2020-09-13 22:00:47 +02:00
Jeff Rescignano
26a8686a54 Firefox Custom Scrollbar (#1163)
* Firefox custom scrollbar

* Put Firefox scrollbar css in first body tag

Co-authored-by: cschwinne <dev.aircoookie@gmail.com>
2020-09-13 21:29:36 +02:00
Phil Bolduc
57421d2392 Async temperature usermod (#1178)
* Change Temperature usermod to use async reading to avoid blocking

* Fix comparison on wait time

* Add

* Simplify logic in the loop method

* Optimize calls to minimize latency, inform user how long till first measurement

* disable usermod if sensor not found

* Added debug statements on init, update readme

* fix spelling error of celsius
2020-09-13 19:26:27 +02:00
Jeff Rescignano
63d92381ee New WLED logo on the welcome screen (#1164)
* Akemi on the welcome screen

* Move style element to CSS

* Use smaller Akemi image, improve margin, rounded buttons

* New WLED logo on welcome page

Co-authored-by: cschwinne <dev.aircoookie@gmail.com>
2020-09-12 21:16:31 +02:00
cschwinne
2716f4cbe9 Fixed passwords not clearable 2020-09-10 11:01:05 +02:00
cschwinne
6ef4582ebd Fix write with string 2020-09-09 10:21:56 +02:00
cschwinne
649ebb8a4e Add previously unsaved changes 2020-09-09 09:54:58 +02:00
cschwinne
b1acf6088f Presets in FS function 2020-09-09 09:51:04 +02:00
Aircoookie
78f5d80c5b Merge @WoodyLetsCode Open releases in new tab (#1152)
* New Segments are now initialized with default speed and intensity

* Open releases in new tab (#1152)

* open releases in new tab

* Revert "open releases in new tab"

This reverts commit 6e3940c8eb.

* open releases in new tab

Co-authored-by: Woody <>

Co-authored-by: Woody <27882680+WoodyLetsCode@users.noreply.github.com>
2020-09-07 21:17:29 +02:00
Woody
5896b1eb71 Open releases in new tab (#1152)
* open releases in new tab

* Revert "open releases in new tab"

This reverts commit 6e3940c8eb.

* open releases in new tab

Co-authored-by: Woody <>
2020-09-07 21:04:21 +02:00
Aircoookie
559891ac43 New Segments are now initialized with default speed and intensity (#1158) 2020-09-07 21:02:02 +02:00
cschwinne
1fbe1d1855 New Segments are now initialized with default speed and intensity 2020-09-07 21:01:10 +02:00
cschwinne
71473fd5c4 Saving progress 2020-09-07 20:39:12 +02:00
Aircoookie
c7beacf3b9 Merge pull request #1139 from Aircoookie/master-to-fs
Merge master to filesystem branch
2020-09-03 21:08:14 +02:00
Aircoookie
3dc55ff8b5 Update platformio.ini 2020-09-03 17:36:14 +02:00
Aircoookie
b6789e0011 Merge branch 'filesystem' into master-to-fs 2020-09-03 15:02:17 +02:00
cschwinne
2f2bebe506 Fixed bootloop if mDNS is used on builds without OTA support 2020-09-03 14:04:33 +02:00
cschwinne
503b8cbf34 Release of WLED v0.10.2 2020-08-31 17:03:07 +02:00
Phil Bolduc
916356afad Use maximum gzip compression (#1126)
* Use maximum gzip compression

* Revert extra changes

* Remove extra code used when testing brotli compression

* Remove extra space on unrelated changes
2020-08-31 10:57:17 +02:00
cschwinne
41a84160ec 0.10.2-rc 2020-08-30 23:31:58 +02:00
Aircoookie
55f071e4a0 Merge pull request #1125 from CyberLine/master
make PCARS usermod compatible with WLED > 0.10.0
2020-08-30 22:01:09 +02:00
Alexander Over
0afe0f8fbd make PCARS usermod compatible with WLED > 0.10.0 2020-08-30 21:27:52 +02:00
Aircoookie
427b5bd126 Merge pull request #1108 from xxv/xxv-dancing-shadows
Add Dancing Shadows effect
2020-08-30 11:45:00 +02:00
cschwinne
20f6378a3e Move blendPixelColor() to FX_fcn.cpp 2020-08-30 10:57:42 +02:00
cschwinne
36e0a1eb23 Individual LED control via JSON (closes #226 ) 2020-08-29 22:26:39 +02:00
cschwinne
ac9a567e1f Pacifica better speed 2020-08-25 17:23:17 +02:00
bwente
33cd52cddd design updates (#1112)
* initial word clock usermod

Based on code provided by Aircoookie I added my code to create a word clock using a 8x8 RGB matrix

* construction source files

files for laser or 3d printing enclosures

* Update word-clock-matrix.cpp

fixed missed localTime var and removed brightness schedule to use timed macros

Co-authored-by: Aircoookie <dev.aircoookie@gmail.com>
2020-08-25 10:33:47 +02:00
Aircoookie
d543ba82ac Add CLKPIN/DATAPIN to PIO override (as suggested in #1109) 2020-08-25 10:32:32 +02:00
Aircoookie
5a98993df9 Merge pull request #1109 from xxv/xxv-override-clkdata
Allow overriding CLKPIN/DATAPIN
2020-08-25 10:30:24 +02:00
Steve Pomeroy
aee9c4a193 Add Dancing Shadows effect 2020-08-23 17:06:11 -04:00
Steve Pomeroy
0262f89bb0 Allow overriding CLKPIN/DATAPIN 2020-08-22 14:57:44 -04:00
Aircoookie
a8c530a3a9 Merge pull request #1101 from droloff/fix-npe
check payload to avoid npe
2020-08-20 08:44:09 +02:00
Aircoookie
7dc1240c18 Merge pull request #1100 from mickabrig7/master
Improve TPM2.NET code
2020-08-20 08:43:22 +02:00
Dirk Roloff
3b4bccd0a7 check payload to avoid npe 2020-08-20 00:13:06 +02:00
cschwinne
39a80f8dc7 Add easy segment mirroring (closes #1010) 2020-08-20 00:04:02 +02:00
mickabrig7
ce446dac92 Improve TPM2.NET code
Add support for receiving TPM2.NET packets out of order, and hopefully prevent crashes if faced with protocol errors
2020-08-19 10:40:16 +02:00
cschwinne
b1c9dbd0a5 Removed verbose live mode info from HTTP API
Add logo without background tags
2020-08-19 09:10:47 +02:00
Aircoookie
a5c57d7fb0 Create readme.md 2020-08-19 08:53:54 +02:00
Aircoookie
0a349e5298 Merge pull request #1099 from bwente/usermod-word-clock-matrix
initial word clock matrix usermod
2020-08-19 08:48:20 +02:00
Aircoookie
dc7d7150cd Refactor local to localTime
(variable name in latest master)
2020-08-19 08:47:16 +02:00
Brian Wente
7c4aa4441f initial word clock matrix usermod
Based on code provided by Aircoookie I added my code to create a word clock using a 8x8 RGB matrix
2020-08-18 16:22:22 -04:00
Aircoookie
62a795bd3b Merge pull request #1092 from JeffResc/arduino-framework
Bump espressif8266 to v2.6.2
2020-08-16 12:47:34 +02:00
Aircoookie
c583ab4f1a Merge pull request #1097 from peacepenguin/master
Add PC RGB notes
2020-08-16 10:33:37 +02:00
Ben
45a2970307 Add PC RGB notes
add info for pc argb enthusiasts to know they can use WLED as an alternative to the motherboard controller.
2020-08-15 13:16:07 -06:00
cschwinne
5a4b719995 Fixed Auto White mode setting (fixes #1088) 2020-08-10 23:35:18 +02:00
Aircoookie
34a4a89bc9 Merge pull request #1091 from garyd9/fix-for-UTC-rollover
couple of bug fixes for usermod_SunRiseAndSet
2020-08-10 10:27:33 +02:00
Jeff Rescignano
02989f65ff Bump espressif8266 to v2.6.2 2020-08-10 00:44:01 -04:00
garyd9
1da539ef05 couple of bug fixes
Fix a typo in one of the json vars
Fix an odd issue that would occur if sunrise or sunset occurs in the first hour after midnight UTC.  (The Dusk2Dawn lib would return a value greater than 1440.)
2020-08-09 21:58:27 -04:00
Aircoookie
38d6fbd3d3 Merge pull request #1089 from garyd9/UserMod_SunRiseAndSet
Add sunrise/set times to json state (for sunrise/set usermod)
2020-08-09 21:51:28 +02:00
garyd9
39682a4cf1 add more vars to json state 2020-08-09 13:55:40 -04:00
garyd9
993a5805cd Add sunrise/set times to json state 2020-08-09 13:40:12 -04:00
Aircoookie
09cf528cc6 Merge pull request #1085 from garyd9/UserMod_SunRiseAndSet
create "sunrise and sunset" WLED usermod.
2020-08-09 19:19:11 +02:00
garyd9
18ab2b3ab5 #if0 out a debug block that can be used to validate the sunrise/sunset times. 2020-08-07 15:21:45 -04:00
garyd9
655fbf91e2 create "sunrise and sunset" WLED usermod. 2020-08-07 15:14:55 -04:00
cschwinne
980794ea43 Fix filetype in usermod documentation 2020-08-07 16:06:54 +02:00
cschwinne
c1cab30daf Added mi property to APIs 2020-08-07 00:50:19 +02:00
twlare
b50e798d55 Add segment mirror option
* Add segment mirror option (#1010)

* Update new pull with playlist and palette changes

* Revert "Update new pull with playlist and palette changes"

This reverts commit 9802a7c4e2.
2020-08-04 18:50:16 +02:00
Aircoookie
230e3ef842 Merge pull request #1078 from garyd9/global-local-to-localTime
rename global var "local" to "localTime"
2020-08-04 17:34:14 +02:00
garyd9
2635a3edd0 rename global var "local" to "localTime" 2020-08-04 09:32:54 -04:00
jbucky86
47f24ac151 dmx_htm_fixes (#1070)
* Update cdata.js

* Update html_settings.h

* Update settings.htm

* Update settings_dmx.htm

* Add %DMXMENU% to cdata.js

* Fix single % being treated as template in settings.htm

Co-authored-by: cschwinne <dev.aircoookie@gmail.com>
2020-08-03 18:37:25 +02:00
Aircoookie
42397a01bf Merge pull request #1076 from tschundler/master
Fix multi-universe ArtNet output
2020-08-03 12:48:57 +02:00
cschwinne
7730a00dbb Rename local ledCount 2020-08-03 12:27:16 +02:00
Ted Schundler
3a4f4c8c34 Fix multi-universe ArtNet output
The existing code was very buggy - a 512 channel ArtNet packet sent data to
171 LEDs, not 170. Also the second ArtNet universe was off-by-one.

The math was very confusing with so many branches. The reduces the
amount of code and amount of branching.

Tested with Resolume + my own ArtNet software + 252 LEDs for ArtNet.
Tested with LedFx for e1.31
2020-08-02 17:48:47 -07:00
Aircoookie
a0d88b0cbe Merge pull request #1064 from garyd9/issue-1063
Fix for power on (T=1) resetting brightness.
2020-07-27 19:21:37 +02:00
Aircoookie
bb0419837b Merge pull request #1069 from juanesf/master
Add useful links to readme.md
2020-07-27 07:30:37 +02:00
juanesf
35098c474c Update readme.md
- add link to Hyperion.NG
- add link to WLED App (Android & iOS)
2020-07-27 00:32:32 -04:00
garyd9
0ca6535345 Fix for power on (T=1) resetting brightness.
In particular, if parsing T=1, and the brightness is already non-0,
don't do anything.
Resolves presets set from macros don't restore brightness #1063
2020-07-24 23:33:50 -04:00
Aircoookie
ec6a243e3e Hostname alphanumeric (#1048)
* Use string derived from serverDescription for wifi.hostname()

The code was sending illegal hostname strings to WiFi.hostname() (which is then submitted to DHCP and often times to DNS.)  A valid hostname contains only alphanumeric characters and hyphens (though it can't start with a hypen.)  This change simply alters the value passed to wifi.hostname() by replacing all non alphanum chars with hyphens while ensuring the first char is never a hyphen.  If the resulting hostname is empty, it uses the escapedMac value (which I'm assuming is initialized by the time this code executes.)

This change would result issue #1033

* replace string with char array
prefix wled
improve documentation

Co-authored-by: garyd9 <garyd9@hotmail.com>
Co-authored-by: Gary Dezern <gdezern@internal.youforgot.net>
2020-07-19 16:24:26 +02:00
Aircoookie
2cd8ee4a13 Merge pull request #1043 from calebmah/sensor-usermods
Photoresistor and PIR sensor MQTT usermods
2020-07-19 10:34:54 +02:00
Caleb Mah
432755e05d Use MQTT_TOPIC 2020-07-17 00:54:52 +08:00
Caleb Mah
51a7c2adc5 PIR sensor usermod 2020-07-16 23:32:23 +08:00
Caleb Mah
5c1f793887 photoresister sensor usermod 2020-07-16 23:29:06 +08:00
Aircoookie
e5dc473ced Merge pull request #1031 from THATDONFC/patch-1
Remove ESPAsyncUDP version requirement
2020-07-07 20:43:14 +02:00
THATDONFC
e57a518b34 Remove ESPAsyncUDP version requirement
The version requirement for the ESPAsyncUDP lib_dep has been causing failed builds in platformio and Travis-CI since 7/6/2020. Removing the version requirement fixes this issue. 
Please see the error below:
`Looking for ESPAsyncUDP library in registry
Found: https://platformio.org/lib/show/359/ESPAsyncUDP
LibraryManager: Installing id=359 @ 697c75a025
UndefinedPackageVersion: Could not find a version that satisfies the requirement '697c75a025' for your system 'linux_x86_64':`
2020-07-07 09:13:32 -07:00
Aircoookie
533f86c035 Merge pull request #1023 from Aircoookie/websockets
Merge Websockets branch
2020-07-02 11:25:38 +02:00
cschwinne
9947c51af7 Fix lightning effect never using last 2 LEDs
Disable Websockets by default (temporarily)
2020-07-02 00:49:37 +02:00
cschwinne
409303d0f5 Merge branch 'master' into websockets 2020-06-29 22:00:21 +02:00
cschwinne
10a1275a52 Added SV=2 to HTTP API, allow selecting single segment only 2020-06-26 23:30:13 +02:00
cschwinne
5464cbc2ed Fix Alexa not turning off white channel (fixes #1012) 2020-06-26 23:09:19 +02:00
cschwinne
3b3f8e6f43 WebSockets
Better TwinkleFox speed regulation
2020-06-26 17:28:35 +02:00
Aircoookie
2d4d7bf937 Merge pull request #1007 from axlan/mpu6050-usermod
Usermod adding Mpu6050 IMU driver
2020-06-22 15:04:11 +02:00
Aircoookie
652651668f Update MPU usermod ID 2020-06-22 15:03:37 +02:00
cschwinne
e57d5d86f3 Merge branch 'master' of https://github.com/Aircoookie/WLED 2020-06-22 12:30:35 +02:00
cschwinne
4f7dc5be34 Added Sunrise nightlight mode and more UI features
-   Added Sunrise nightlight mode
-   Added Chunchun effect
-   Added `LO` (live override) command to HTTP API
-   Added `mode` to `nl` object of JSON state API, deprecating `fade`
-   Added light color scheme support to web UI (click sun next to brightness slider)
-   Added option to hide labels in web UI (click flame icon next to intensity slider)
-   Added hex color input (click palette icon next to palette select) (resolves #506)
-   Added support for RGB sliders (need to set in localstorage)
-   Added support for custom background color or image (need to set in localstorage)
-   Added option to hide bottom tab bar in PC mode (need to set in localstorage)
-   Fixed transition lag with multiple segments (fixes #985)
-   Changed Nightlight wording (resolves #940)
2020-06-22 12:30:31 +02:00
Jonathan Diamond
b2c656940b Added link for video and blog 2020-06-21 17:32:39 -07:00
Aircoookie
f8266d9811 Create CODE_OF_CONDUCT.md 2020-06-22 00:09:00 +02:00
Aircoookie
5c03550a8a Update issue templates 2020-06-22 00:03:24 +02:00
Axlan
ed5491a480 Added usermod for connecting MPU6050 IMU 2020-06-20 19:44:29 -07:00
Woody
e8371f403b images to jpg (#1004)
* images to jpg

* Delete macbook-pro-space-gray-on-the-wooden-table.png

* Delete walking-with-iphone-x.png

* Update readme.md
2020-06-19 22:57:24 +02:00
Aircoookie
373cffb261 Merge pull request #1002 from WoodyLetsCode/master
replace .webp images with .png images in README
2020-06-18 19:03:14 +02:00
Woody
2bf22766eb Update readme.md 2020-06-18 18:02:20 +02:00
Woody
83530fcaf1 Delete walking-with-iphone-x.webp 2020-06-18 18:01:41 +02:00
Woody
6a41123209 Delete macbook-pro-space-gray-on-the-wooden-table.webp 2020-06-18 18:01:34 +02:00
Woody
c895c5c16e add png images 2020-06-18 18:01:22 +02:00
Aircoookie
9ab4b3f3f4 Merge pull request #992 from gegu/master
Usermods: PIR sensor switch, v2 unreachable net services
2020-06-14 21:11:54 +02:00
gegu
b93dd47a01 Changed PIR sensor switch timeout 2020-06-14 13:02:04 +02:00
gegu
69a826f896 Usermods: PIR sensor switch, v2 unreachable net services 2020-06-14 12:54:35 +02:00
Aircoookie
60c7ec5aca Merge pull request #921 from huksley/codegen-html
Automatic UI codegeneration
2020-06-10 18:24:17 +02:00
cschwinne
888eacb574 Minor changes to auto UI code generation
Replace outdated CSS in HTML by style.css import
Fix missing button double press in time settings
FIx missing meta utf-8 in WiFi and UI settings
Modify cdata.js to add an info header to the top of auto-generated files
2020-06-10 12:45:44 +02:00
Woody
4def582ab1 smaller discord banner in readme (#976)
* smaller discord banner

* added dicord link to banner
2020-06-08 22:30:35 +02:00
Ruslan Gainutdinov
ee6f25cc47 Replace repo url and version automatically in HTML 2020-06-08 20:59:40 +03:00
Ruslan Gainutdinov
f5d6383f50 adds support for 9-key remote and intensity/speed repeat actions 2020-06-08 19:54:10 +03:00
Ruslan Gainutdinov
00f00b8198 Merge remote-tracking branch 'origin/master' into codegen-html 2020-06-08 19:43:03 +03:00
Woody
3d1f883465 New readme design (#973)
* nicer readme

- added emojis
- changed the first sentence (information about WS2801)

* added new images

* moved main image

* Delete wled_logo.png

* mail to image

* Some design changes in readme

- added images
- added discord banner
- replaced email with image (protection for spam bots)

* removed mail image

* Delete mail.png

* Added compatible LED Strips table

I added this, because I thought for a long time that WLED doesn't support WS2801.
I didn't read the wiki. And so I think this could be useful for many other people.

* Added emojy for Compatible LED Strips

* compressed images

* Changed path to compressed images

* Delete macbook-pro-space-gray-on-the-wooden-table.jpg

* Delete walking-with-iphone-x.jpg
2020-06-08 10:55:37 +02:00
Aircoookie
8613a89931 Merge pull request #969 from WoodyLetsCode/master
Centered images in readme
2020-06-07 21:47:12 +02:00
Aircoookie
dd1485a66a Merge pull request #970 from steveway/patch-1
v2 based usermod which allows changing color and brightness
2020-06-07 20:41:24 +02:00
Stefan Murawski
4198954d46 Create usermode_rotary_set.h 2020-06-07 19:25:58 +02:00
Woody
e56caa8959 Update readme.md 2020-06-07 14:51:13 +02:00
Woody
de7c72d5a7 Update readme.md 2020-06-07 14:50:25 +02:00
cschwinne
18a4a43f8a Merge branch 'master' of https://github.com/Aircoookie/WLED 2020-06-06 00:57:39 +02:00
cschwinne
70c73d2e0e Lots of new effects! 2020-06-06 00:57:34 +02:00
Aircoookie
2049e8b8df Merge pull request #964 from kareem613/master
adds support for 9-key remote and intensity/speed repeat actions
2020-06-05 14:24:40 +02:00
spiff72
41da889a09 Updated Readme.md file (#965)
* Adding new usermod for TTGO T-DIsplay.

* Finalizing the code

* Modified and cleaned up readme.md file

* Fixes to platformio.ini to restore back to previous state

* Cleaned up comments in usermod file

* Updated readme with clarifications on how to modify the library files.  Saving the platformio.ini file after uncommenting the line to add the TFT_eSPI library should download the necessary library files without needing to build (and fail) first.

* Cleanup

* Readme cleanup

* corrected error in commenting platformio.ini
2020-06-05 14:22:03 +02:00
Kareem Sultan
0a1bbca321 adds support for 9-key remote and intensity/speed repeat actions 2020-06-04 08:24:55 -04:00
spiff72
7e01d113d8 New usermod to support the TTGO T-Display (ESP32 based board with integrated TFT display) (#957)
* Adding new usermod for TTGO T-DIsplay.

* Finalizing the code

* Modified and cleaned up readme.md file

* Fixes to platformio.ini to restore back to previous state

* Cleaned up comments in usermod file
2020-05-30 09:22:31 +02:00
Aircoookie
6e49cc54ac Merge pull request #954 from psi-4ward/feature/esp_rgbww_controller_pins
Add PWN Pins for esp_rgbww_controller
2020-05-29 14:07:57 +02:00
Christoph Wiechert
487a95eb79 Add PWM pins - to use with esp_rgbww_controller
from patrickjahns/pljakobs (https://github.com/pljakobs/esp_rgbww_controller)
2020-05-29 13:51:20 +02:00
cschwinne
696e438df7 Added v2 usermods API 2020-05-28 02:20:02 +02:00
Aircoookie
a4e093159e Merge pull request #941 from gegu/master
Usermod: fix unreachable network services
2020-05-24 19:34:28 +02:00
gegu
23986579bb Usermod: fix unreachable network services 2020-05-24 10:07:00 +02:00
cschwinne
0fc099926f Fixed TPM2 2020-05-23 16:09:49 +02:00
cschwinne
06b9b66272 Added TPM2 protocol support via Serial (#933) 2020-05-22 23:30:55 +02:00
cschwinne
fec8343f45 Added TPM2.NET protocol support 2020-05-18 16:36:31 +02:00
Ruslan Gainutdinov
2d8f2593f0 Remove hardcoded IP address if any 2020-05-17 23:22:42 +03:00
Ruslan Gainutdinov
ab0a03a420 Sync htm and fix js errors 2020-05-17 22:39:57 +03:00
Ruslan Gainutdinov
3ef30a42be Fix settings sync page JS 2020-05-17 22:18:23 +03:00
Ruslan Gainutdinov
034687163f Fix dynamic replacements for other pages 2020-05-17 21:59:00 +03:00
Ruslan Gainutdinov
190db80c28 Automatic UI codegeneration 2020-05-17 21:14:56 +03:00
Aircoookie
579f355852 Merge pull request #910 from Aircoookie/merge-dmx-proxy
Merge dmx proxy
2020-05-11 12:08:35 +02:00
cschwinne
d9104433a8 Remove proxy setting from sync settings file 2020-05-11 12:07:33 +02:00
Aircoookie
c6059f9bf6 Merge pull request #858 from pille/travis_all_features
travis: add own build targets that enable all features
2020-05-11 11:58:52 +02:00
cschwinne
fd06ff08c7 Move DMX proxy setting from sync to DMX settings 2020-05-11 11:51:11 +02:00
Aircoookie
afd990bd71 Merge pull request #862 from pille/DMX-proxy
implement DMX proxy mode via MAX485
2020-05-11 11:40:11 +02:00
cschwinne
8333c4b48d Travis environment selection in platformio.ini 2020-05-11 11:18:07 +02:00
Aircoookie
30c4f501fc Merge pull request #591 from tpmodding/patch-1
WS2801 Color Order Fix
2020-05-11 10:57:54 +02:00
Aircoookie
3b96eef2ad Merge branch 'master' into travis_all_features 2020-05-11 10:57:32 +02:00
Aircoookie
a769ab6cff Merge branch 'master' into patch-1 2020-05-11 10:46:18 +02:00
cschwinne
ef1f835e57 Update to Espalexa v2.4.6
(+1.6kB free heap memory)
-   Added `m5atom` PlatformIO environment
2020-05-10 23:58:50 +02:00
cschwinne
329b2ba275 Fixed Preset Slot 16 always indicating as empty (fixes #891) 2020-05-09 00:29:42 +02:00
Aircoookie
98383ef19b Merge pull request #898 from 8none1/master
Add new mode "Solid Glitter".
2020-05-08 23:10:16 +02:00
cschwinne
8bb70fb1b0 Filesystem Tests 2020-05-08 22:53:59 +02:00
Will Cooke
72cca365e5 Add new mode "Solid Glitter".
Gives a solid, static background colour as selected from the colour picker and overlays "glitter" (as per Rainbow Glitter, only without the rainbow).
2020-05-06 14:28:16 +01:00
cschwinne
dfc99faea8 First preset progress 2020-05-05 09:01:09 +02:00
pille
69a2ac8de1 Merge branch 'master' into travis_all_features 2020-04-25 20:01:03 +02:00
pille
8bfae2fa74 implement DMX proxy mode via MAX485
output a configurable universe (E1.31 or ArtNet) via MAX485 module that connects its DI to D4 on d1_mini.
as this function competes with DMX output for the same hardware, the universe to proxy acts as a switch.
0       = DMX OUTPUT (of configured WLED LEDs, which is the classic behaviour)
1-63999 = DMX PROXY  (selected universe, ArtNet is limited up to 32768)
2020-04-21 22:56:14 +02:00
pille
2788dd1ada travis: add own build targets that enable all features 2020-04-20 13:26:09 +02:00
Serhan
8048bb85fb Update NpbWrapper.h
Fixes the WS2801 Color Order
2020-01-14 15:58:14 +01:00
144 changed files with 22087 additions and 8408 deletions

22
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1,22 @@
# 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/vscode/devcontainers/python:0-${VARIANT}
# [Option] Install Node.js
ARG INSTALL_NODE="true"
ARG NODE_VERSION="lts/*"
RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
# [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

View File

@@ -0,0 +1,46 @@
{
"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",
// Options
"INSTALL_NODE": "true",
"NODE_VERSION": "lts/*"
}
},
// Set *default* container specific settings.json values on container create.
"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"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-python.python"
],
// 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": "pip3 install --user -r requirements.txt",
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
}

27
.github/ISSUE_TEMPLATE/bug.md vendored Normal file
View File

@@ -0,0 +1,27 @@
---
name: Bug
about: Noticed an issue with your lights?
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is. Please quickly search existing issues first!
**To Reproduce**
Steps to reproduce the behavior, if consistently possible
**Expected behavior**
A clear and concise description of what you expected to happen.
**WLED version**
- Board: [e.g. Wemos D1, ESP32 dev]
- Version [e.g. 0.10.0, dev200603]
- Format [e.g. Binary, self-compiled]
**Additional context**
Anything else you'd like to say about the problem?
Thank you for your help!

View 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!

19
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@@ -0,0 +1,19 @@
---
name: Question
about: Have a question about using WLED?
title: ''
labels: question
assignees: ''
---
**Take a look at the wiki and FAQ, perhaps your question is already answered!**
[FAQ](https://github.com/Aircoookie/WLED/wiki/FAQ)
**Please consider asking your question on the WLED forum or Discord**
[Forum](https://wled.discourse.group/)
[Discord](https://discord.gg/KuqP7NE)
[What to post where?](https://github.com/Aircoookie/WLED/issues/658)
**If you do not like to use these platforms, delete this template and ask away!**
Please keep in mind though that the issue section is generally not the preferred place for general questions.

4
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.pio
.cache
.pioenvs
.piolibdeps
.vscode
@@ -6,6 +7,9 @@
/wled00/Release
/wled00/extLibs
/platformio_override.ini
/wled00/my_config.h
/build_output
.DS_Store
.gitignore
.clang-format
node_modules

5
.gitpod.Dockerfile vendored Normal file
View File

@@ -0,0 +1,5 @@
FROM gitpod/workspace-full
USER gitpod
RUN pip3 install -U platformio

12
.gitpod.yml Normal file
View File

@@ -0,0 +1,12 @@
tasks:
- command: platformio run
image:
file: .gitpod.Dockerfile
vscode:
extensions:
- ms-vscode.cpptools@0.26.3:u3GsZ5PK12Ddr79vh4TWgQ==
- eamodio.gitlens@10.2.1:e0IYyp0efFqVsrZwsIe8CA==
- Atishay-Jain.All-Autocomplete@0.0.23:fbZNfSpnd8XkAHGfAPS2rA==
- 2gua.rainbow-brackets@0.0.6:Tbu8dTz0i+/bgcKQTQ5b8g==

View File

@@ -40,4 +40,4 @@ install:
- platformio update
script:
# - platformio ci --project-conf=./platformio.ini
- platformio run
- platformio run

Binary file not shown.

View File

@@ -1,5 +1,299 @@
## WLED changelog
### WLED version 0.11.0
#### Build 2011290
- Release of WLED 0.11.0 "Mirai"
- Workaround for weird empty %f Espalexa issue
- Fixed crash on saving preset with HTTP API `PS`
- Improved performance for color changes in non-main segment
#### Build 2011270
- Added tooltips for speed and intensity sliders (PR #1378)
- Moved color order to NpbWrapper.h
- Added compile time define to override the color order for a specific range
#### Build 2011260
- Add `live` property to state, allowing toggling of realtime (not incl. in state resp.)
- PIO environment changes
#### Build 2011230
- Version bump to 0.11.0 "Mirai"
- Improved preset name sorting
- Fixed Preset cycle not working beyond preset 16
### Development versions between 0.10.2 and 0.11.0 releases
#### Build 2011220
- Fixed invalid save when modifying preset before refresh (might be related to #1361)
- Fixed brightness factor ignored on realtime timeout (fixes #1363)
- Fixed Phase and Chase effects with LED counts >256 (PR #1366)
#### Build 2011210
- Fixed Brightness slider beneath color wheel not working (fixes #1360)
- Fixed invalid UI state after saving modified preset
#### Build 2011200
- Added HEX color receiving to JSON API with `"col":["RRGGBBWW"]` format
- Moved Kelvin color receiving in JSON API from `"col":[[val]]` to `"col":[val]` format
_Notice:_ This is technically a breaking change. Since no release was made since the introduction and the Kelvin property was not previously documented in the wiki,
impact should be minimal.
- BTNPIN can now be disabled by setting to -1 (fixes #1237)
#### Build 2011180
- Platformio.ini updates and streamlining (PR #1266)
- my_config.h custom compile settings system (not yet used for much, adapted from PR #1266)
- Added Hawaii timezone (HST)
- Linebreak after 5 quick select buttons
#### Build 2011154
- Fixed RGBW saved incorrectly
- Fixed pmt caching requesting /presets.json too often
- Fixed deEEP not copying the first segment of EEPROM preset 16
#### Build 2011153
- Fixed an ESP32 end-of-file issue
- Fixed useRGBW not read from cfg.json
#### Build 2011152
- Version bump to 0.11.0p "Mirai"
- Increased max. num of segments to 12 (ESP8266) / 16 (ESP32)
- Up to 250 presets stored in the `presets.json` file in filesystem
- Complete overhaul of the Presets UI tab
- Updated iro.js to v5 (fixes black color wheel)
- Added white temperature slider to color wheel
- Add JSON settings serialization/deserialization to cfg.json and wsec.json
- Added deEEP to convert the EEPROM settings and presets to files
- Playlist support - JSON only for now
- New v2 usermod methods `addToConfig()` and `readFromConfig()` (see EXAMPLE_v2 for doc)
- Added Ethernet support for ESP32 (PR #1316)
- IP addresses are now handled by the `Network` class
- New `esp32_poe` PIO environment
- Use EspAsyncWebserver Aircoookie fork v.2.0.0 (hiding wsec.json)
- Removed `WLED_DISABLE_FILESYSTEM` and `WLED_ENABLE_FS_SERVING` defines as they are now required
- Added pin manager
- UI performance improvements (no drop shadows)
- More explanatory error messages in UI
- Improved candle brightness
- Return remaining nightlight time `nl.rem` in JSON API (PR #1302)
- UI sends timestamp with every command, allowing for timed presets without using NTP
- Added gamma calculation (yet unused)
- Added LED type definitions to const.h (yet unused)
- Added nicer 404 page
- Removed `NP` and `MS=` macro HTTP API commands
- Removed macros from Time settings
#### Build 2011120
- Added the ability for the /api MQTT topic to receive JSON API payloads
#### Build 2011040
- Inversed Rain direction (fixes #1147)
#### Build 2011010
- Re-added previous C9 palette
- Renamed new C9 palette
#### Build 2010290
- Colorful effect now supports palettes
- Added C9 2 palette (#1291)
- Improved C9 palette brightness by 12%
- Disable onboard LED if LEDs are off (PR #1245)
- Added optional status LED (PR #1264)
- Realtime max. brightness now honors brightness factor (fixes #1271)
- Updated ArduinoJSON to 6.17.0
#### Build 2010020
- Fixed interaction of `T` and `NL` HTTP API commands (#1214)
- Fixed an issue where Sunrise mode nightlight does not activate if toggled on simultaneously
#### Build 2009291
- Fixed MQTT bootloop (no F() macro, #1199)
#### Build 2009290
- Added basic DDP protocol support
- Added Washing Machine effect (PR #1208)
#### Build 2009260
- Added Loxone parser (PR #1185)
- Added support for kelvin input via `K=` HTTP and `"col":[[val]]` JSON API calls
_Notice:_ `"col":[[val]]` removed in build 2011200, use `"col":[val]`
- Added supplementary UDP socket (#1205)
- TMP2.net receivable by default
- UDP sockets accept HTTP and JSON API commands
- Fixed missing timezones (#1201)
#### Build 2009202
- Fixed LPD8806 compilation
#### Build 2009201
- Added support for preset cycle toggling using CY=2
- Added ESP32 touch pin support (#1190)
- Fixed modem sleep on ESP8266 (#1184)
#### Build 2009200
- Increased available heap memory by 4kB
- Use F() macro for the majority of strings
- Restructure timezone code
- Restructured settings saved code
- Updated ArduinoJSON to 6.16.1
#### Build 2009170
- New WLED logo on Welcome screen (#1164)
- Fixed 170th pixel dark in E1.31
#### Build 2009100
- Fixed sunrise mode not reinitializing
- Fixed passwords not clearable
#### Build 2009070
- New Segments are now initialized with default speed and intensity
#### Build 2009030
- Fixed bootloop if mDNS is used on builds without OTA support
### WLED version 0.10.2
#### Build 2008310
- Added new logo
- Maximum GZIP compression (#1126)
- Enable WebSockets by default
### Development versions between 0.10.0 and 0.10.2 releases
#### Build 2008300
- Added new UI customization options to UI settings
- Added Dancing Shadows effect (#1108)
- Preset cycle is now paused if lights turned off or nightlight active
- Removed `esp01` and `esp01_ota` envs from travis build (need too much flash)
#### Build 2008290
- Added individual LED control support to JSON API
- Added internal Segment Freeze/Pause option
#### Build 2008250
- Made `platformio_override.ini` example easier to use by including the `default_envs` property
- FastLED uses `now` as timer, so effects using e.g. `beatsin88()` will sync correctly
- Extended the speed range of Pacifica effect
- Improved TPM2.net receiving (#1100)
- Fixed exception on empty MQTT payload (#1101)
#### Build 2008200
- Added segment mirroring to web UI
- Fixed segment mirroring when in reverse mode
#### Build 2008140
- Removed verbose live mode info from `<ds>` in HTTP API response
#### Build 2008100
- Fixed Auto White mode setting (fixes #1088)
#### Build 2008070
- Added segment mirroring (`mi` property) (#1017)
- Fixed DMX settings page not displayed (#1070)
- Fixed ArtNet multi universe and improve code style (#1076)
- Renamed global var `local` to `localTime` (#1078)
#### Build 2007190
- Fixed hostname containing illegal characters (#1035)
#### Build 2006251
- Added `SV=2` to HTTP API, allow selecting single segment only
#### Build 2006250
- Fix Alexa not turning off white channel (fixes #1012)
#### Build 2006220
- Added Sunrise nightlight mode
- Added Chunchun effect
- Added `LO` (live override) command to HTTP API
- Added `mode` to `nl` object of JSON state API, deprecating `fade`
- Added light color scheme support to web UI (click sun next to brightness slider)
- Added option to hide labels in web UI (click flame icon next to intensity slider)
- Added hex color input (click palette icon next to palette select) (resolves #506)
- Added support for RGB sliders (need to set in localstorage)
- Added support for custom background color or image (need to set in localstorage)
- Added option to hide bottom tab bar in PC mode (need to set in localstorage)
- Fixed transition lag with multiple segments (fixes #985)
- Changed Nightlight wording (resolves #940)
#### Build 2006060
- Added five effects by Andrew Tuline (Phased, Phased Noise, Sine, Noise Pal and Twinkleup)
- Added two new effects by Aircoookie (Sunrise and Flow)
- Added US-style sequence to traffic light effect
- Merged pull request #964 adding 9 key IR remote
#### Build 2005280
- Added v2 usermod API
- Added v2 example usermod `usermod_v2_example` in the usermods folder as prelimary documentation
- Added DS18B20 Temperature usermod with Info page support
- Disabled MQTT on ESP01 build to make room in flash
#### Build 2005230
- Fixed TPM2
#### Build 2005220
- Added TPM2.NET protocol support (need to set WLED broadcast UDP port to 65506)
- Added TPM2 protocol support via Serial
- Support up to 6553 seconds preset cycle durations (backend, NOT yet in UI)
- Merged pull request #591 fixing WS2801 color order
- Merged pull request #858 adding fully featured travis builds
- Merged pull request #862 adding DMX proxy feature
#### Build 2005100
- Update to Espalexa v2.4.6 (+1.6kB free heap memory)
- Added `m5atom` PlatformIO environment
#### Build 2005090
- Default to ESP8266 Arduino core v2.7.1 in PlatformIO
- Fixed Preset Slot 16 always indicating as empty (#891)
- Disabled Alexa emulation by default (causes bootloop for some users)
- Added BWLT11 and SHOJO_PCB defines to NpbWrapper
- Merged pull request #898 adding Solid Glitter effect
### WLED version 0.10.0
#### Build 2005030

76
CODE_OF_CONDUCT.md Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 KiB

BIN
images/wled_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
images/wled_logo_akemi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
images/wled_logo_clean.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

2312
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

31
package.json Normal file
View File

@@ -0,0 +1,31 @@
{
"name": "wled",
"version": "0.11.0",
"description": "Tools for WLED project",
"main": "tools/cdata.js",
"directories": {
"lib": "lib",
"test": "test"
},
"scripts": {
"build": "node tools/cdata.js",
"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/Aircoookie/WLED.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/Aircoookie/WLED/issues"
},
"homepage": "https://github.com/Aircoookie/WLED#readme",
"dependencies": {
"clean-css": "^4.2.3",
"html-minifier-terser": "^5.1.1",
"inliner": "^1.13.1",
"nodemon": "^2.0.4",
"zlib": "^1.0.5"
}
}

23
pio/gzip-firmware.py Normal file
View File

@@ -0,0 +1,23 @@
Import('env')
import os
import shutil
import gzip
OUTPUT_DIR = "build_output{}".format(os.path.sep)
def bin_gzip(source, target, env):
variant = str(target[0]).split(os.path.sep)[2]
# create string with location and file names based on variant
bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant)
gzip_file = "{}firmware{}{}.bin.gz".format(OUTPUT_DIR, os.path.sep, variant)
# check if new target files exist and remove if necessary
if os.path.isfile(gzip_file): os.remove(gzip_file)
# write gzip firmware file
with open(bin_file,"rb") as fp:
with gzip.open(gzip_file, "wb", compresslevel = 9) as f:
shutil.copyfileobj(fp, f)
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_gzip])

34
pio/name-firmware.py Normal file
View File

@@ -0,0 +1,34 @@
Import('env')
import os
import shutil
OUTPUT_DIR = "build_output{}".format(os.path.sep)
def bin_rename_copy(source, target, env):
variant = str(target[0]).split(os.path.sep)[2]
# check if output directories exist and create if necessary
if not os.path.isdir(OUTPUT_DIR):
os.mkdir(OUTPUT_DIR)
for d in ['firmware', 'map']:
if not os.path.isdir("{}{}".format(OUTPUT_DIR, d)):
os.mkdir("{}{}".format(OUTPUT_DIR, d))
# create string with location and file names based on variant
map_file = "{}map{}{}.map".format(OUTPUT_DIR, os.path.sep, variant)
bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant)
# check if new target files exist and remove if necessary
for f in [map_file, bin_file]:
if os.path.isfile(f):
os.remove(f)
# copy firmware.bin to firmware/<variant>.bin
shutil.copy(str(target[0]), bin_file)
# copy firmware.map to map/<variant>.map
if os.path.isfile("firmware.map"):
shutil.move("firmware.map", map_file)
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_rename_copy])

9
pio/obj-dump.py Normal file
View File

@@ -0,0 +1,9 @@
# Little convenience script to get an object dump
Import('env')
def obj_dump_after_elf(source, target, env):
print("Create firmware.asm")
env.Execute("xtensa-lx106-elf-objdump "+ "-D " + str(target[0]) + " > "+ "${PROGNAME}.asm")
env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", [obj_dump_after_elf])

15
pio/strip-floats.py Normal file
View 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/user_config_copy.py Normal file
View 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")

View File

@@ -2,24 +2,17 @@
; Please visit documentation: https://docs.platformio.org/page/projectconf.html
[platformio]
src_dir = ./wled00
data_dir = ./wled00/data
lib_dir = ./wled00/src
build_cache_dir = ~/.buildcache
extra_configs =
platformio_override.ini
# ------------------------------------------------------------------------------
# ENVIRONMENTS
#
# Please uncomment one of the lines below to select your board(s)
# ------------------------------------------------------------------------------
# Travis CI binaries (comment this out when building for single board)
default_envs = d1_mini, esp01, esp01_1m_ota, esp32dev
# Travis CI binaries (comment this out with a ';' when building for your own board)
default_envs = travis_esp8266, travis_esp32
# Release binaries
; default_envs = nodemcuv2, esp01, esp01_1m_ota, esp01_1m_full, esp32dev, custom_WS2801, custom_APA102, custom_LEDPIN_16, custom_LEDPIN_4, custom32_LEDPIN_16
; default_envs = nodemcuv2, esp01_1m_full, esp32dev, custom_WS2801, custom_APA102, custom_LEDPIN_16, custom_LEDPIN_4, custom_LEDPIN_3, custom32_LEDPIN_16, custom32_APA102
# Single binaries (uncomment your board)
; default_envs = nodemcuv2
@@ -38,40 +31,34 @@ default_envs = d1_mini, esp01, esp01_1m_ota, esp32dev
; default_envs = esp8285_5CH_H801
; default_envs = d1_mini_5CH_Shojo_PCB
; default_envs = wemos_shield_esp32
; default_envs = m5atom
; default_envs = esp32_poe
src_dir = ./wled00
data_dir = ./wled00/data
build_cache_dir = ~/.buildcache
extra_configs =
platformio_override.ini
[common]
# ------------------------------------------------------------------------------
# PLATFORM:
# !! DO NOT confuse platformio's ESP8266 development platform with Arduino core for ESP8266
#
# arduino core 2.3.0 = platformIO 1.5.0
# arduino core 2.4.0 = platformIO 1.6.0
# arduino core 2.4.1 = platformIO 1.7.3
# arduino core 2.4.2 = platformIO 1.8.0
# arduino core 2.5.0 = platformIO 2.0.4
# arduino core 2.5.1 = platformIO 2.1.1
# arduino core 2.5.2 = platformIO 2.2.3
# arduino core 2.6.1 = platformIO 2.3.0
# arduino core 2.6.2 = platformIO 2.3.1
# arduino core 2.6.3 = platformIO 2.3.2
# arduino core 2.7.0 = platformIO 2.5.0
# ------------------------------------------------------------------------------
arduino_core_2_3_0 = espressif8266@1.5.0
arduino_core_2_4_0 = espressif8266@1.6.0
arduino_core_2_4_1 = espressif8266@1.7.3
arduino_core_2_4_2 = espressif8266@1.8.0
arduino_core_2_5_0 = espressif8266@2.0.4
arduino_core_2_5_1 = espressif8266@2.1.1
arduino_core_2_5_2 = espressif8266@2.2.3
arduino_core_2_6_1 = espressif8266@2.3.0
arduino_core_2_6_2 = espressif8266@2.3.1
arduino_core_2_6_3 = espressif8266@2.3.3
arduino_core_2_7_4 = espressif8266@2.6.2
# Development platforms
arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop
arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage
platform = ${common.arduino_core_2_4_2}
platform_latest = ${common.arduino_core_2_6_3}
# Platform to use for ESP8266
platform_wled_default = ${common.arduino_core_2_7_4}
# We use 2.7.4.7 for all, includes PWM flicker fix and Wstring optimization
platform_packages = tasmota/framework-arduinoespressif8266 @ 3.20704.7
# ------------------------------------------------------------------------------
# FLAGS: DEBUG
@@ -82,7 +69,7 @@ debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT
#-DDEBUG_ESP_CORE is not working right now
# ------------------------------------------------------------------------------
# FLAGS: ldscript
# FLAGS: ldscript (available ldscripts at https://github.com/esp8266/Arduino/tree/master/tools/sdk/ld)
# ldscript_512k ( 512 KB) = 487 KB sketch, 4 KB eeprom, no spiffs, 16 KB reserved
# ldscript_1m0m (1024 KB) = 999 KB sketch, 4 KB eeprom, no spiffs, 16 KB reserved
# ldscript_2m1m (2048 KB) = 1019 KB sketch, 4 KB eeprom, 1004 KB spiffs, 16 KB reserved
@@ -93,6 +80,7 @@ debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT
# -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
@@ -105,26 +93,81 @@ debug_flags = -D DEBUG=1 -D WLED_DEBUG -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT
# TLS_RSA_WITH_AES_256_CBC_SHA / AES256-SHA
# This reduces the OTA size with ~45KB, so it's especially useful on low memory boards (512k/1m).
# ------------------------------------------------------------------------------
build_flags = -g -w -DMQTT_MAX_PACKET_SIZE=1024 -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH
-DSECURE_CLIENT=SECURE_CLIENT_BEARSSL -DBEARSSL_SSL_BASIC
#build_flags for the IRremoteESP8266 library (enabled decoders have to appear here)
build_flags =
-Wno-switch
-Wno-deprecated-declarations
-Wno-write-strings
-Wno-unused-variable
-Wno-unused-value
-Wno-sign-compare
-Wno-unused-but-set-variable
-Wno-return-type
-Wno-sequence-point
-Wno-narrowing
-Wno-reorder
-DMQTT_MAX_PACKET_SIZE=1024
-DSECURE_CLIENT=SECURE_CLIENT_BEARSSL
-DBEARSSL_SSL_BASIC
-D CORE_DEBUG_LEVEL=0
-D NDEBUG
#build_flags for the IRremoteESP8266 library (enabled decoders have to appear here)
-D _IR_ENABLE_DEFAULT_=false
-D DECODE_HASH=true
-D DECODE_NEC=true
-D DECODE_SONY=true
-D DECODE_SAMSUNG=true
-D DECODE_LG=true
build_flags_esp8266 = ${common.build_flags} -DESP8266
build_flags_esp32 = ${common.build_flags} -DARDUINO_ARCH_ESP32
-DWLED_USE_MY_CONFIG
build_unflags =
-Wall
-Wdeprecated-declarations
# enables all features for travis CI
build_flags_all_features =
-D WLED_USE_ANALOG_LED
-D WLED_USE_H801
-D WLED_ENABLE_5CH_LEDS
-D WLED_ENABLE_ADALIGHT
-D WLED_ENABLE_DMX
-D WLED_ENABLE_MQTT
-D WLED_ENABLE_WEBSOCKETS
build_flags_esp8266 = ${common.build_flags} ${esp8266.build_flags}
build_flags_esp32 = ${common.build_flags} ${esp32.build_flags}
ldscript_512k = eagle.flash.512k.ld ;for older versions change this to eagle.flash.512k0.ld
ldscript_1m0m = eagle.flash.1m.ld ;for older versions change this to eagle.flash.1m0.ld
ldscript_1m128k = eagle.flash.1m128.ld
ldscript_2m512k = eagle.flash.2m512.ld
ldscript_2m1m = eagle.flash.2m1m.ld
ldscript_4m1m = eagle.flash.4m1m.ld
ldscript_4m3m = eagle.flash.4m3m.ld
shared_libdeps_dir = ./wled00/src
[esp8266]
build_flags =
-DESP8266
-DFP_IN_IROM
; 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
[esp32]
build_flags = -w -g
-DARDUINO_ARCH_ESP32
-DCONFIG_LITTLEFS_FOR_IDF_3_2
[scripts_defaults]
extra_scripts = pio/name-firmware.py
pio/gzip-firmware.py
pio/strip-floats.py
pio/user_config_copy.py
# ------------------------------------------------------------------------------
# COMMON SETTINGS:
@@ -134,8 +177,6 @@ framework = arduino
board_build.flash_mode = dout
monitor_speed = 115200
upload_speed = 115200
lib_extra_dirs =
${common.shared_libdeps_dir}
# ------------------------------------------------------------------------------
# LIBRARIES: required dependencies
@@ -147,105 +188,151 @@ lib_extra_dirs =
lib_compat_mode = strict
lib_deps =
FastLED@3.3.2
NeoPixelBus@2.5.7
NeoPixelBus@2.6.0
ESPAsyncTCP@1.2.0
ESPAsyncUDP@697c75a025
ESPAsyncUDP
AsyncTCP@1.0.3
Esp Async WebServer@1.2.0
IRremoteESP8266@2.7.3
https://github.com/lorol/LITTLEFS.git
https://github.com/Aircoookie/ESPAsyncWebServer.git@~2.0.0
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
#TFT_eSPI
#For use SSD1306 OLED display uncomment following
#U8g2@~2.27.2
#For Dallas sensor uncomment following 2 lines
#OneWire@~2.3.5
#milesburton/DallasTemperature@^3.9.0
#For BME280 sensor uncomment following
#BME280@~3.0.0
lib_ignore =
AsyncTCP
extra_scripts = ${scripts_defaults.extra_scripts}
# ------------------------------------------------------------------------------
# WLED BUILDS
# ------------------------------------------------------------------------------
[env:nodemcuv2]
board = nodemcuv2
platform = ${common.platform_latest}
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}
# Unsupported environment due to insufficient flash
[env:esp01]
board = esp01
platform = ${common.platform_latest}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_512k}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK
-D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
-D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED -D WLED_DISABLE_MQTT -D WLED_DISABLE_WEBSOCKETS
# Unsupported environment due to insufficient flash
[env:esp01_1m_ota]
board = esp01_1m
platform = ${common.platform_latest}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m0m}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK -D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK -D WLED_DISABLE_CRONIXIE
-D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED -D WLED_DISABLE_MQTT -D WLED_DISABLE_WEBSOCKETS
[env:esp01_1m_full]
board = esp01_1m
platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_1m0m}
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} -D WLED_DISABLE_OTA
[env:esp07]
board = esp07
platform = ${common.platform_latest}
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}
[env:d1_mini]
board = d1_mini
platform = ${common.platform_latest}
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}
monitor_filters = esp8266_exception_decoder
[env:heltec_wifi_kit_8]
board = d1_mini
platform = ${common.platform_latest}
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}
[env:h803wf]
board = d1_mini
platform = ${common.platform_latest}
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} -D LEDPIN=1 -D WLED_DISABLE_INFRARED
[env:esp32dev]
board = esp32dev
platform = espressif32@1.11.2
platform = espressif32@2.0
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32}
lib_ignore =
ESPAsyncTCP
ESPAsyncUDP
[env:esp32_poe]
board = esp32-poe
platform = espressif32@2.0
upload_speed = 921600
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D RLYPIN=-1 -D WLED_USE_ETHERNET
lib_ignore =
ESPAsyncTCP
ESPAsyncUDP
[env:esp8285_4CH_MagicHome]
board = esp8285
platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_1m0m}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ANALOG_LEDS
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} -D WLED_DISABLE_OTA -D WLED_USE_ANALOG_LEDS
[env:esp8285_4CH_H801]
board = esp8285
platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_1m0m}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801
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} -D WLED_DISABLE_OTA -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801
[env:esp8285_5CH_H801]
board = esp8285
platform = ${common.platform_latest}
board_build.ldscript = ${common.ldscript_1m0m}
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801 -D WLED_ENABLE_5CH_LEDS
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} -D WLED_DISABLE_OTA -D WLED_USE_ANALOG_LEDS -D WLED_USE_H801 -D WLED_ENABLE_5CH_LEDS
[env:d1_mini_5CH_Shojo_PCB]
board = d1_mini
platform = ${common.platform_latest}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D SHOJO_PCB -D WLED_ENABLE_5CH_LEDS
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D WLED_USE_SHOJO_PCB -D WLED_ENABLE_5CH_LEDS
# ------------------------------------------------------------------------------
# DEVELOPMENT BOARDS
@@ -254,8 +341,10 @@ build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D SHOJO_PCB
[env:d1_mini_debug]
board = d1_mini
build_type = debug
platform = ${common.platform_latest}
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} ${common.debug_flags}
[env:d1_mini_ota]
@@ -263,8 +352,10 @@ board = d1_mini
upload_protocol = espota
# exchange for your WLED IP
upload_port = "10.10.1.27"
platform = ${common.platform_latest}
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}
# ------------------------------------------------------------------------------
@@ -273,43 +364,163 @@ build_flags = ${common.build_flags_esp8266}
[env:custom_LEDPIN_4]
board = d1_mini
platform = ${common.platform_latest}
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} -D LEDPIN=4 -D IRPIN=5
[env:custom_LEDPIN_16]
board = d1_mini
platform = ${common.platform_latest}
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} -D LEDPIN=16
[env:custom_LEDPIN_3]
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} -D LEDPIN=3
[env:custom_APA102]
board = d1_mini
platform = ${common.platform_latest}
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} -D USE_APA102
[env:custom_WS2801]
board = d1_mini
platform = ${common.platform_latest}
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} -D USE_WS2801
[env:custom32_LEDPIN_16]
board = esp32dev
platform = espressif32@1.11.2
build_flags = ${common.build_flags_esp32} -D LEDPIN=16
platform = espressif32@2.0
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D LEDPIN=16 -D RLYPIN=19
lib_ignore =
ESPAsyncTCP
ESPAsyncUDP
[env:custom32_APA102]
board = esp32dev
platform = espressif32@2.0
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D USE_APA102
lib_ignore =
ESPAsyncTCP
ESPAsyncUDP
[env:custom32_TOUCHPIN_T0]
board = esp32dev
platform = espressif32@2.0
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D TOUCHPIN=T0
lib_ignore =
ESPAsyncTCP
ESPAsyncUDP
[env:wemos_shield_esp32]
board = esp32dev
platform = espressif32@1.11.2
platform = espressif32@2.0
upload_port = /dev/cu.SLAB_USBtoUART
monitor_port = /dev/cu.SLAB_USBtoUART
upload_speed = 460800
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D LEDPIN=16 -D RLYPIN=19 -D BTNPIN=17
lib_ignore =
ESPAsyncTCP
ESPAsyncUDP
[env:m5atom]
board = esp32dev
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} -D LEDPIN=27 -D BTNPIN=39
lib_ignore =
ESPAsyncTCP
ESPAsyncUDP
platform = espressif32@2.0
[env:sp501e]
board = esp_wroom_02
platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_2m512k}
build_flags = ${common.build_flags_esp8266} -D LEDPIN=3 -D BTNPIN=1
# ------------------------------------------------------------------------------
# travis test board configurations
# ------------------------------------------------------------------------------
[env:travis_esp8266]
extends = env:d1_mini
build_type = debug
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266} ${common.debug_flags} ${common.build_flags_all_features}
[env:travis_esp32]
extends = env:esp32dev
; build_type = debug
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp32} ${common.debug_flags} ${common.build_flags_all_features}
# ------------------------------------------------------------------------------
# codm pixel controller board configurations
# ------------------------------------------------------------------------------
[env:codm-controller-0.4]
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} -D LEDPIN=3
[env:codm-controller-0.4-WS2801]
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} -D USE_WS2801 -D CLKPIN=13 -D DATAPIN=3
[env:codm-controller-0.4-APA102]
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} -D USE_APA102 -D CLKPIN=13 -D DATAPIN=3
[env:codm-controller-0.5]
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}
[env:codm-controller-0.5-WS2801]
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} -D USE_WS2801 #-D CLKPIN=0 -D DATAPIN=2
[env:codm-controller-0.5-APA102]
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} -D USE_APA102 #-D CLKPIN=0 -D DATAPIN=2

View File

@@ -4,30 +4,44 @@
# ------------------------------------------------------------------------------
# Please visit documentation: https://docs.platformio.org/page/projectconf.html
[env:esp8266_1m_custom]
[platformio]
default_envs = WLED_tasmota_1M
[env:WLED_tasmota_1M]
board = esp01_1m
platform = ${common.arduino_core_2_4_2}
platform = ${common.platform_wled_default}
platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_1m0m}
build_flags = ${common.build_flags_esp8266}
-D WLED_DISABLE_OTA
-D WLED_DISABLE_ALEXA
-D WLED_DISABLE_BLYNK
-D WLED_DISABLE_CRONIXIE
-D WLED_DISABLE_HUESYNC
-D WLED_DISABLE_INFRARED
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266}
; *********************************************************************
; *** Use custom settings from file my_config.h
-DWLED_USE_MY_CONFIG
; *********************************************************************
; -D WLED_DISABLE_OTA
; -D WLED_DISABLE_ALEXA
; -D WLED_DISABLE_BLYNK
; -D WLED_DISABLE_CRONIXIE
; -D WLED_DISABLE_HUESYNC
; -D WLED_DISABLE_INFRARED
; -D WLED_DISABLE_WEBSOCKETS
; PIN defines - uncomment and change, if needed:
; -D LEDPIN=2
; -D BTNPIN=0
; -D IR_PIN=4
; -D TOUCHPIN=T0
; -D IRPIN=4
; -D RLYPIN=12
; -D RLYMDE=1
; digital LED strip types - uncomment only one ! - this will disable WS281x / SK681x support
; -D USE_APA102
; -D USE_WS2801
; -D USE_LPD8806
; PIN defines for 2 wire LEDs
-D CLKPIN=0
-D DATAPIN=2
; to drive analog LED strips (aka 5050), uncomment the following
; PWM pins 5,12,13,15 are used with Magic Home LED Controller (default)
; -D WLED_USE_ANALOG_LEDS
-D WLED_USE_ANALOG_LEDS
; for the H801 controller (PINs 15,13,12,14 (W2 = 04)) uncomment this
; -D WLED_USE_H801
; for the BW-LT11 controller (PINs 12,4,14,5 ) uncomment this

View File

@@ -1,16 +1,20 @@
![WLED logo](https://raw.githubusercontent.com/Aircoookie/WLED/master/wled_logo.png)
<p align="center">
<img src="/images/wled_logo_akemi.png">
<a href="https://github.com/Aircoookie/WLED/releases"><img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a>
<a href="https://raw.githubusercontent.com/Aircoookie/WLED/master/LICENSE"><img src="https://img.shields.io/github/license/Aircoookie/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/KuqP7NE"><img src="https://img.shields.io/discord/473448917040758787.svg?colorB=blue&label=discord&style=flat-square"></a>
<a href="https://github.com/Aircoookie/WLED/wiki"><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/Aircoookie/WLED"><img src="https://img.shields.io/badge/Gitpod-ready--to--code-blue?style=flat-square&logo=gitpod"></a>
[![](https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square)](https://github.com/Aircoookie/WLED/releases)
[![](https://img.shields.io/discourse/topics?colorB=blue&label=forum&server=https%3A%2F%2Fwled.discourse.group%2F&style=flat-square)](https://wled.discourse.group)
[![](https://img.shields.io/discord/473448917040758787.svg?colorB=blue&label=discord&style=flat-square)](https://discord.gg/KuqP7NE)
[![](https://img.shields.io/badge/quick_start-wiki-blue.svg?style=flat-square)](https://github.com/Aircoookie/WLED/wiki)
[![](https://img.shields.io/badge/app-wled-blue.svg?style=flat-square)](https://github.com/Aircoookie/WLED-App)
</p>
# Welcome to my project WLED! ✨
## Welcome to my project WLED!
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102!
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812, APA102) LEDs!
### Features:
## ⚙️ Features
- WS2812FX library integrated for over 100 special effects
- FastLED noise effects and 50 palettes
- Modern UI with color, effect and segment controls
@@ -18,56 +22,79 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
- Settings page - configuration over network
- Access Point and station mode - automatic failsafe AP
- Support for RGBW strips
- 16 user presets to save and load colors/effects easily, supports cycling through them.
- Macro functions to automatically execute API calls
- 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
- 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=com.aircoookie.WLED) and [iOS](https://apps.apple.com/us/app/wled/id1475695033)
- JSON and HTTP request APIs
- MQTT
- Blynk IoT
- E1.31
- Hyperion
- E1.31, Art-Net, DDP and TPM2.net
- [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)!
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://github.com/Aircoookie/WLED/wiki/Learning-the-ropes) you can find excellent tutorials made by the community and helpful tools to help you get your new lamp 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!
## 🖼️ Images
<img src="/images/macbook-pro-space-gray-on-the-wooden-table.jpg" width="50%"><img src="/images/walking-with-iphone-x.jpg" width="50%">
Russian speakers, check out the videos by Room31:
[WLED Firmware Overview: Interface and Settings](https://youtu.be/h7lKsczEI7E)
[ESP8266 based LED controller for WS2812b strip. WLED Firmware + OpenHAB](https://youtu.be/K4ioTt3XvGc)
## 💾 Compatible LED Strips
Type | Voltage | Comments
|---|---|---|
WS2812B | 5v |
WS2813 | 5v |
SK6812 | 5v | RGBW
APA102 | 5v | C/D
WS2801 | 5v | C/D
LPD8806 | 5v | C/D
TM1814 | 12v | RGBW
WS2811 | 12v | 3-LED segments
WS2815 | 12v |
GS8208 | 12v |
Analog/non-addressable | any | Requires additional circuitry
### Other
## 🧊 Compatible PC RGB Fans and ARGB accessories
Brand | Model | Comments
|---|---|---|
Corsair | HD120 Fan | Uses WS2812B, data-in only
PCCOOLER | Moonlight 5-pack Fans | Uses WS2812B, includes Data-out connector to keep each fan uniquely addressable if wired in series like traditional LED strips
Any | 5v 3-pin ARGB for PC | Any PC RGB device that supports the 5v 3-pin ARGB motherboard header should work fine with WLED. All the major motherboard vendors support the Corsair HD120 and PCCOOLER fans listed, so we can safely assume any device that supports motherboard ARGB 5V 3-Pin standard will work with WLED.
## ✌️ Other
Licensed under the MIT license
Credits [here](https://github.com/Aircoookie/WLED/wiki/Contributors-&-About)!
Uses Linearicons by Perxis!
Join the Discord [server](https://discord.gg/KuqP7NE) to discuss everything about WLED!
Join the Discord server to discuss everything about WLED!
<a href="https://discord.gg/KuqP7NE"><img src="https://discordapp.com/api/guilds/473448917040758787/widget.png?style=banner2" width="25%"></a>
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://img.shields.io/badge/send%20me%20a%20small%20gift-paypal-blue.svg?style=flat-square)](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.
*Disclaimer:*
If you are sensitive to photosensitive epilepsy 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.

404
tools/cdata.js Normal file
View File

@@ -0,0 +1,404 @@
/**
* Writes compressed C arrays of data files (web interface)
* How to use it?
*
* 1) Install Node 11+ 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("fs");
const packageJson = require("../package.json");
/**
*
*/
function hexdump(buffer) {
let lines = [];
for (let i = 0; i < buffer.length; i += 16) {
let block = buffer.slice(i, i + 16); // cut buffer into blocks of 16
let hexArray = [];
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");
}
const inliner = require("inliner");
const zlib = require("zlib");
function strReplace(str, search, replacement) {
return str.split(search).join(replacement);
}
function adoptVersionAndRepo(html) {
let repoUrl = packageJson.repository ? packageJson.repository.url : undefined;
if (repoUrl) {
repoUrl = repoUrl.replace(/^git\+/, "");
repoUrl = repoUrl.replace(/\.git$/, "");
// Replace we
html = strReplace(html, "https://github.com/atuline/WLED", repoUrl);
html = strReplace(html, "https://github.com/Aircoookie/WLED", repoUrl);
}
let version = packageJson.version;
if (version) {
html = strReplace(html, "##VERSION##", version);
}
return html;
}
function writeHtmlGzipped(sourceFile, resultFile) {
console.info("Reading " + sourceFile);
new inliner(sourceFile, function (error, html) {
console.info("Inlined " + html.length + " characters");
if (error) {
console.warn(error);
throw error;
}
html = adoptVersionAndRepo(html);
zlib.gzip(html, { level: zlib.constants.Z_BEST_COMPRESSION }, function (error, result) {
if (error) {
console.warn(error);
throw error;
}
console.info("Compressed " + result.length + " bytes");
const array = hexdump(result);
const src = `/*
* Binary array for the Web UI.
* gzip is used for smaller size and improved speeds.
*
* Please see https://github.com/Aircoookie/WLED/wiki/Add-own-functionality#web-ui
* to find out how to easily modify the web UI source!
*/
// Autogenerated from ${sourceFile}, do not edit!!
const uint16_t PAGE_index_L = ${result.length};
const uint8_t PAGE_index[] PROGMEM = {
${array}
};
`;
console.info("Writing " + resultFile);
fs.writeFileSync(resultFile, src);
});
});
}
const CleanCSS = require("clean-css");
const MinifyHTML = require("html-minifier-terser").minify;
function filter(str, type) {
str = adoptVersionAndRepo(str);
if (type === undefined) {
return str;
} else if (type == "css-minify") {
return new CleanCSS({}).minify(str).styles;
} else if (type == "html-minify") {
return MinifyHTML(str, {
collapseWhitespace: true,
maxLineLength: 80,
minifyCSS: true,
minifyJS: true,
continueOnParseError: false,
removeComments: true,
});
} else {
console.warn("Unknown filter: " + type);
return str;
}
}
function specToChunk(srcDir, s) {
if (s.method == "plaintext") {
const buf = fs.readFileSync(srcDir + "/" + s.file);
const str = buf.toString("ascii");
const chunk = `
// Autogenerated from ${srcDir}/${s.file}, do not edit!!
const char ${s.name}[] PROGMEM = R"${s.prepend || ""}${filter(str, s.filter)}${
s.append || ""
}";
`;
return s.mangle ? s.mangle(chunk) : chunk;
} else if (s.method == "binary") {
const buf = fs.readFileSync(srcDir + "/" + s.file);
const result = hexdump(buf);
const chunk = `
// Autogenerated from ${srcDir}/${s.file}, do not edit!!
const uint16_t ${s.name}_length = ${result.length};
const uint8_t ${s.name}[] PROGMEM = {
${result}
};
`;
return s.mangle ? s.mangle(chunk) : chunk;
} else {
console.warn("Unknown method: " + s.method);
return undefined;
}
}
function writeChunks(srcDir, specs, resultFile) {
let src = `/*
* More web UI HTML source arrays.
* This file is auto generated, please don't make any changes manually.
* Instead, see https://github.com/Aircoookie/WLED/wiki/Add-own-functionality#web-ui
* to find out how to easily modify the web UI source!
*/
`;
specs.forEach((s) => {
try {
console.info("Reading " + srcDir + "/" + s.file + " as " + s.name);
src += specToChunk(srcDir, s);
} catch (e) {
console.warn(
"Failed " + s.name + " from " + srcDir + "/" + s.file,
e.message.length > 60 ? e.message.substring(0, 60) : e.message
);
}
});
console.info("Writing " + src.length + " characters into " + resultFile);
fs.writeFileSync(resultFile, src);
}
writeHtmlGzipped("wled00/data/index.htm", "wled00/html_ui.h");
writeChunks(
"wled00/data",
[
{
file: "style.css",
name: "PAGE_settingsCss",
prepend: "=====(<style>",
append: "</style>)=====",
method: "plaintext",
filter: "css-minify",
},
{
file: "settings.htm",
name: "PAGE_settings",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: (str) =>
str
.replace("%", "%%")
.replace(/User Interface\<\/button\>\<\/form\>/gms, "User Interface\<\/button\>\<\/form\>%DMXMENU%"),
},
{
file: "settings_wifi.htm",
name: "PAGE_settings_wifi",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: (str) =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
.replace(
/function GetV().*\<\/script\>/gms,
"function GetV() {var d=document;\n"
),
},
{
file: "settings_leds.htm",
name: "PAGE_settings_leds",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: (str) =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
.replace(
/function GetV().*\<\/script\>/gms,
"function GetV() {var d=document;\n"
),
},
{
file: "settings_dmx.htm",
name: "PAGE_settings_dmx",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: (str) => {
const nocss = str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
.replace(
/function GetV().*\<\/script\>/gms,
"function GetV() {var d=document;\n"
);
return `
#ifdef WLED_ENABLE_DMX
${nocss}
#else
const char PAGE_settings_dmx[] PROGMEM = R"=====()=====";
#endif
`;
},
},
{
file: "settings_ui.htm",
name: "PAGE_settings_ui",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: (str) =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
.replace(
/function GetV().*\<\/script\>/gms,
"function GetV() {var d=document;\n"
),
},
{
file: "settings_sync.htm",
name: "PAGE_settings_sync",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: (str) =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
.replace(/function GetV().*\<\/script\>/gms, "function GetV() {\n"),
},
{
file: "settings_time.htm",
name: "PAGE_settings_time",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: (str) =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
.replace(/function GetV().*\<\/script\>/gms, "function GetV() {\n"),
},
{
file: "settings_sec.htm",
name: "PAGE_settings_sec",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: (str) =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
.replace(
/function GetV().*\<\/script\>/gms,
"function GetV() {var d=document;\n"
),
},
],
"wled00/html_settings.h"
);
writeChunks(
"wled00/data",
[
{
file: "usermod.htm",
name: "PAGE_usermod",
prepend: "=====(",
append: ")=====",
method: "plaintext",
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",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
},
{
file: "welcome.htm",
name: "PAGE_welcome",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
},
{
file: "liveview.htm",
name: "PAGE_liveview",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
},
{
file: "404.htm",
name: "PAGE_404",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
},
{
file: "favicon.ico",
name: "favicon",
method: "binary",
},
],
"wled00/html_other.h"
);

View File

@@ -0,0 +1,19 @@
# ESP32 Touch Brightness Control
Toggle On/Off with a long press (800ms)
Switch through 5 brightness levels (defined in usermod_touchbrightness.h, values 0-255) with a short (100ms) touch
## Installation
Copy 'usermod_touchbrightness.h' to the wled00 directory.
in 'usermod_list.cpp' add this:
> #include "usermod_touchbrightness.h"
above "void registerUsermods()"
and
> usermods.add(new TouchBrightnessControl());
inside the "registerUsermods()" function

View File

@@ -0,0 +1,89 @@
//
// usermod_touchbrightness.h
// github.com/aircoookie/WLED
//
// Created by Justin Kühner on 14.09.2020.
// Copyright © 2020 NeariX. All rights reserved.
// https://github.com/NeariX67/
// Discord: @NeariX#4799
#pragma once
#include "wled.h"
#define threshold 40 //Increase value if touches falsely accur. Decrease value if actual touches are not recognized
#define touchPin T0 //T0 = D4 / GPIO4
//Define the 5 brightness levels
//Long press to turn off / on
#define brightness1 51
#define brightness2 102
#define brightness3 153
#define brightness4 204
#define brightness5 255
#ifdef ESP32
class TouchBrightnessControl : public Usermod {
private:
unsigned long lastTime = 0; //Interval
unsigned long lastTouch = 0; //Timestamp of last Touch
unsigned long lastRelease = 0; //Timestamp of last Touch release
boolean released = true; //current Touch state (touched/released)
uint16_t touchReading = 0; //sensor reading, maybe use uint8_t???
uint16_t touchDuration = 0; //duration of last touch
public:
void setup() {
lastTouch = millis();
lastRelease = millis();
lastTime = millis();
}
void loop() {
if (millis() - lastTime >= 50) { //Check every 50ms if a touch occurs
lastTime = millis();
touchReading = touchRead(touchPin); //Read touch sensor on pin T0 (GPIO4 / D4)
if(touchReading < threshold && released) { //Touch started
released = false;
lastTouch = millis();
}
else if(touchReading >= threshold && !released) { //Touch released
released = true;
lastRelease = millis();
touchDuration = lastRelease - lastTouch; //Calculate duration
}
//Serial.println(touchDuration);
if(touchDuration >= 800 && released) { //Toggle power if button press is longer than 800ms
touchDuration = 0; //Reset touch duration to avoid multiple actions on same touch
toggleOnOff();
colorUpdated(2); //Refresh values
}
else if(touchDuration >= 100 && released) { //Switch to next brightness if touch is between 100 and 800ms
touchDuration = 0; //Reset touch duration to avoid multiple actions on same touch
if(bri < brightness1) {
bri = brightness1;
} else if(bri >= brightness1 && bri < brightness2) {
bri = brightness2;
} else if(bri >= brightness2 && bri < brightness3) {
bri = brightness3;
} else if(bri >= brightness3 && bri < brightness4) {
bri = brightness4;
} else if(bri >= brightness4 && bri < brightness5) {
bri = brightness5;
} else if(bri >= brightness5) {
bri = brightness1;
}
colorUpdated(2); //Refresh values
}
}
}
};
#endif

View File

@@ -0,0 +1,10 @@
# Usermods API v2 example usermod
In this usermod file you can find the documentation on how to take advantage of the new version 2 usermods!
## Installation
Copy `usermod_v2_example.h` to the wled00 directory.
Uncomment the corresponding lines in `usermods_list.cpp` and compile!
_(You shouldn't need to actually install this, it does nothing useful)_

View File

@@ -0,0 +1,155 @@
#pragma once
#include "wled.h"
/*
* Usermods allow you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
*
* This is an example for a v2 usermod.
* v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example.
* Multiple v2 usermods can be added to one compilation easily.
*
* Creating a usermod:
* This file serves as an example. If you want to create a usermod, it is recommended to use usermod_v2_empty.h from the usermods folder as a template.
* Please remember to rename the class and file to a descriptive name.
* You may also use multiple .h and .cpp files.
*
* Using a usermod:
* 1. Copy the usermod into the sketch folder (same folder as wled00.ino)
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
*/
//class name. Use something descriptive and leave the ": public Usermod" part :)
class MyExampleUsermod : public Usermod {
private:
//Private class members. You can declare variables and functions only accessible to your usermod here
unsigned long lastTime = 0;
public:
//Functions called by WLED
/*
* setup() is called once at boot. WiFi is not yet connected at this point.
* You can use it to initialize variables, sensors or similar.
*/
void setup() {
//Serial.println("Hello from my usermod!");
}
/*
* connected() is called every time the WiFi is (re)connected
* Use it to initialize network interfaces
*/
void connected() {
//Serial.println("Connected to WiFi!");
}
/*
* loop() is called continuously. Here you can check for events, read sensors, etc.
*
* Tips:
* 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection.
* Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker.
*
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
* Instead, use a timer check as shown here.
*/
void loop() {
if (millis() - lastTime > 1000) {
//Serial.println("I'm alive!");
lastTime = millis();
}
}
/*
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
* Below it is shown how this could be used for e.g. a light sensor
*/
/*
void addToJsonInfo(JsonObject& root)
{
int reading = 20;
//this code adds "u":{"Light":[20," lux"]} to the info object
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray lightArr = user.createNestedArray("Light"); //name
lightArr.add(reading); //value
lightArr.add(" lux"); //unit
}
*/
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void addToJsonState(JsonObject& root)
{
//root["user0"] = userVar0;
}
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void readFromJsonState(JsonObject& root)
{
userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
}
/*
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
* If you want to force saving the current state, use serializeConfig() in your loop().
*
* CAUTION: serializeConfig() will initiate a filesystem write operation.
* It might cause the LEDs to stutter and will cause flash wear if called too often.
* Use it sparingly and always in the loop, never in network callbacks!
*
* addToConfig() will also not yet add your setting to one of the settings pages automatically.
* To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
*
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
*/
void addToConfig(JsonObject& root)
{
JsonObject top = root.createNestedObject("exampleUsermod");
top["great"] = userVar0; //save this var persistently whenever settings are saved
}
/*
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
* This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
*
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
*/
void readFromConfig(JsonObject& root)
{
JsonObject top = root["top"];
userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot)
}
/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
* This could be used in the future for the system to determine whether your usermod is installed.
*/
uint16_t getId()
{
return USERMOD_ID_EXAMPLE;
}
//More methods can be added in the future, this example will then be extended.
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 KiB

After

Width:  |  Height:  |  Size: 201 KiB

View File

@@ -0,0 +1,54 @@
# Fix unreachable net services V2
This usermod-v2 modification performs a ping request to the local IP address every 60 seconds. By this procedure the net services of WLED remains accessible in some problematic WLAN environments.
The modification works with static or DHCP IP address configuration.
**Webinterface**: The number of pings and reconnects is displayed on the info page in the web interface.
_Story:_
Unfortunately, with all ESP projects where a web server or other network services are running, I have the problem that after some time the web server is no longer accessible. Now I found out that the connection is at least reestablished when a ping request is executed by the device.
With this modification, in the worst case, the network functions are not available for 60 seconds until the next ping request.
## Installation
1. Copy the file `usermod_Fix_unreachable_netservices.h` to the `wled00` directory.
2. Register the usermod by adding `#include "usermod_Fix_unreachable_netservices.h"` in the top and `registerUsermod(new FixUnreachableNetServices());` in the bottom of `usermods_list.cpp`.
Example **usermods_list.cpp**:
```cpp
#include "wled.h"
/*
* Register your v2 usermods here!
* (for v1 usermods using just usermod.cpp, you can ignore this file)
*/
/*
* Add/uncomment your usermod filename here (and once more below)
* || || ||
* \/ \/ \/
*/
//#include "usermod_v2_example.h"
//#include "usermod_temperature.h"
//#include "usermod_v2_empty.h"
#include "usermod_Fix_unreachable_netservices.h"
void registerUsermods()
{
/*
* Add your usermod class name here
* || || ||
* \/ \/ \/
*/
//usermods.add(new MyExampleUsermod());
//usermods.add(new UsermodTemperature());
//usermods.add(new UsermodRenameMe());
usermods.add(new FixUnreachableNetServices());
}
```
Hopefully I can help someone with that - @gegu

View File

@@ -0,0 +1,138 @@
#pragma once
#include "wled.h"
#include <ping.h>
/*
* This usermod performs a ping request to the local IP address every 60 seconds.
* By this procedure the net services of WLED remains accessible in some problematic WLAN environments.
*
* Usermods allow you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
*
* v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example.
* Multiple v2 usermods can be added to one compilation easily.
*
* Creating a usermod:
* This file serves as an example. If you want to create a usermod, it is recommended to use usermod_v2_empty.h from the usermods folder as a template.
* Please remember to rename the class and file to a descriptive name.
* You may also use multiple .h and .cpp files.
*
* Using a usermod:
* 1. Copy the usermod into the sketch folder (same folder as wled00.ino)
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
*/
class FixUnreachableNetServices : public Usermod {
private:
//Private class members. You can declare variables and functions only accessible to your usermod here
unsigned long m_lastTime = 0;
// desclare required variables
const unsigned int PingDelayMs = 60000;
unsigned long m_connectedWiFi = 0;
ping_option m_pingOpt;
unsigned int m_pingCount = 0;
public:
//Functions called by WLED
/*
* setup() is called once at boot. WiFi is not yet connected at this point.
* You can use it to initialize variables, sensors or similar.
*/
void setup() {
//Serial.println("Hello from my usermod!");
}
/*
* connected() is called every time the WiFi is (re)connected
* Use it to initialize network interfaces
*/
void connected() {
//Serial.println("Connected to WiFi!");
++m_connectedWiFi;
// initialize ping_options structure
memset(&m_pingOpt, 0, sizeof(struct ping_option));
m_pingOpt.count = 1;
m_pingOpt.ip = WiFi.localIP();
}
/*
* loop() is called continuously. Here you can check for events, read sensors, etc.
*
* Tips:
* 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection.
* Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker.
*
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
* Instead, use a timer check as shown here.
*/
void loop() {
if (m_connectedWiFi > 0 && millis()-m_lastTime > PingDelayMs)
{
ping_start(&m_pingOpt);
m_lastTime = millis();
++m_pingCount;
}
}
/*
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
* Below it is shown how this could be used for e.g. a light sensor
*/
void addToJsonInfo(JsonObject& root)
{
//this code adds "u":{"&#x26A1; Ping fix pings": m_pingCount} to the info object
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray infoArr = user.createNestedArray("&#x26A1; Ping fix pings"); //name
infoArr.add(m_pingCount); //value
//this code adds "u":{"&#x26A1; Reconnects": m_connectedWiFi - 1} to the info object
infoArr = user.createNestedArray("&#x26A1; Reconnects"); //name
infoArr.add(m_connectedWiFi - 1); //value
}
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void addToJsonState(JsonObject& root)
{
//root["user0"] = userVar0;
}
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void readFromJsonState(JsonObject& root)
{
//userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
}
/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
* This could be used in the future for the system to determine whether your usermod is installed.
*/
uint16_t getId()
{
return USERMOD_ID_FIXNETSERVICES;
}
//More methods can be added in the future, this example will then be extended.
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
};

View File

@@ -0,0 +1,17 @@
# Fix unreachable Webserver
This modification performs a ping request to the local IP address every 60 seconds. By this procedure the web server remains accessible in some problematic WLAN environments.
The modification works with static or DHCP IP address configuration
_Story:_
Unfortunately, with all ESP projects where a web server or other network services are running, I have the problem that after some time the web server is no longer accessible. Now I found out that the connection is at least reestablished when a ping request is executed by the device.
With this modification, in the worst case, the network functions are not available for 60 seconds until the next ping request.
## Installation
Copy and replace the file `usermod.cpp` in wled00 directory.

View File

@@ -0,0 +1,43 @@
#include "wled.h"
/*
* This file allows you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
* bytes 2400+ are currently ununsed, but might be used for future wled features
*/
#include <ping.h>
const int PingDelayMs = 60000;
long lastCheckTime = 0;
bool connectedWiFi = false;
ping_option pingOpt;
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
//gets called once at boot. Do all initialization that doesn't depend on network here
void userSetup()
{
}
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
void userConnected()
{
connectedWiFi = true;
// initialize ping_options structure
memset(&pingOpt, 0, sizeof(struct ping_option));
pingOpt.count = 1;
pingOpt.ip = WiFi.localIP();
}
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
void userLoop()
{
if (connectedWiFi && millis()-lastCheckTime > PingDelayMs)
{
ping_start(&pingOpt);
lastCheckTime = millis();
}
}

View File

@@ -0,0 +1,9 @@
# PIR sensor with MQTT
This simple usermod allows attaching a PIR sensor like the AM312 and publish the readings over MQTT. A message is sent when motion is detected as well as when motion has stopped.
This usermod has only been tested with the AM312 sensor though should work for any other PIR sensor. Note that this does not control the LED strip directly, it only publishes MQTT readings for use with other integrations like Home Assistant.
## Installation
Copy and replace the file `usermod.cpp` in wled00 directory.

View File

@@ -0,0 +1,55 @@
#include "wled.h"
/*
* This v1 usermod file allows you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
* If you just need 8 bytes, use 2551-2559 (you do not need to increase EEPSIZE)
*
* Consider the v2 usermod API if you need a more advanced feature set!
*/
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
// PIR sensor pin
const int MOTION_PIN = 16;
// MQTT topic for sensor values
const char MQTT_TOPIC[] = "/motion";
int prevState = LOW;
//gets called once at boot. Do all initialization that doesn't depend on network here
void userSetup()
{
pinMode(MOTION_PIN, INPUT);
}
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
void userConnected()
{
}
void publishMqtt(String state)
{
//Check if MQTT Connected, otherwise it will crash the 8266
if (mqtt != nullptr){
char subuf[38];
strcpy(subuf, mqttDeviceTopic);
strcat(subuf, MQTT_TOPIC);
mqtt->publish(subuf, 0, true, state.c_str());
}
}
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
void userLoop()
{
if (digitalRead(MOTION_PIN) == HIGH && prevState == LOW) { // Motion detected
publishMqtt("ON");
prevState = HIGH;
}
if (digitalRead(MOTION_PIN) == LOW && prevState == HIGH) { // Motion stopped
publishMqtt("OFF");
prevState = LOW;
}
}

View File

@@ -0,0 +1,347 @@
#pragma once
#include "wled.h"
/*
* --------------------
* Rawframe edit:
* - TESTED ON WLED VS.0.10.1 - WHERE ONLY PRESET 16 SAVES SEGMENTS - some macros may not be needed if this changes.
* - Code has been modified as my usage changed, as such it has poor use of functions vs if thens, but feel free to change it for me :)
*
* Edited to SWITCH between two lighting scenes/modes : STANDBY and HIGHLIGHT
*
* Usage:
* - Standby is the default mode and Highlight is activated when the PIR detects activity.
* - PIR delay now set to same value as Nightlight feature on boot but otherwise controlled as normal.
* - Standby and Highlight brightness can be set on the fly (default values set on boot via macros calling presets).
* - Macros are used to set Standby and Highlight states (macros can load saved presets etc).
*
* - Macro short button press = Highlight state default (used on boot only and sets default brightness).
* - Macro double button press = Standby state default (used on boot only and sets default brightness).
* - Macro long button press = Highlight state (after boot).
* - Macro 16 = Standby state (after boot).
*
* ! It is advised not to set 'Apply preset at boot' or a boot macro (that activates a preset) as we will call our own macros on boot.
*
* - When the strip is off before PIR activates the strip will return to off for Standby mode, and vice versa.
* - When the strip is turned off while in Highlight mode, it will return to standby mode. (This behaviour could be changed easily if for some reason you wanted the lights to go out when the pir is activated).
* - Macros can be chained so you could do almost anything, such as have standby mode also turn on the nightlight function with a new time delay.
*
* Segment Notes:
* - It's easier to save the segment selections in preset than apply via macro while we a limited to preset 16. (Ie, instead of selecting sections at the point of activating standby/highlight modes).
* - Because only preset 16 saves segments, for now we are having to use addiotional macros to control segments where they are involved. Macros can be chained so this works but it would be better if macros also accepted json-api commands. (Testing http api segement behaviour of SS with SB left me a little confused).
*
* Future:
* - Maybe a second timer/timetable that turns on/off standby mode also after set inactivity period / date & times. For now this can be achieved others ways so may not be worth eating more processing power.
*
* --------------------
*
* This usermod handles PIR sensor states.
* The strip will be switched on and the off timer will be resetted when the sensor goes HIGH.
* When the sensor state goes LOW, the off timer is started and when it expires, the strip is switched off.
*
*
* Usermods allow you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
*
* v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example.
* Multiple v2 usermods can be added to one compilation easily.
*
* Creating a usermod:
* This file serves as an example. If you want to create a usermod, it is recommended to use usermod_v2_empty.h from the usermods folder as a template.
* Please remember to rename the class and file to a descriptive name.
* You may also use multiple .h and .cpp files.
*
* Using a usermod:
* 1. Copy the usermod into the sketch folder (same folder as wled00.ino)
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
*/
class PIRsensorSwitch : public Usermod {
private:
// PIR sensor pin
const uint8_t PIRsensorPin = 13; // D7 on D1 mini
// notification mode for colorUpdated()
const byte NotifyUpdateMode = NOTIFIER_CALL_MODE_NO_NOTIFY; // NOTIFIER_CALL_MODE_DIRECT_CHANGE
// 1 min delay before switch off after the sensor state goes LOW
uint32_t m_switchOffDelay = 60000;
// off timer start time
uint32_t m_offTimerStart = 0;
// current PIR sensor pin state
byte m_PIRsensorPinState = LOW;
// PIR sensor enabled - ISR attached
bool m_PIRenabled = true;
// temp standby brightness store. initial value set as nightlight default target brightness
byte briStandby _INIT(nightlightTargetBri);
// temp hightlight brightness store. initial value set as current brightness
byte briHighlight _INIT(bri);
// highlight active/deactive monitor
bool highlightActive = false;
// wled on/off state in standby mode
bool standbyoff = false;
/*
* return or change if new PIR sensor state is available
*/
static volatile bool newPIRsensorState(bool changeState = false, bool newState = false) {
static volatile bool s_PIRsensorState = false;
if (changeState) {
s_PIRsensorState = newState;
}
return s_PIRsensorState;
}
/*
* PIR sensor state has changed
*/
static void IRAM_ATTR ISR_PIRstateChange() {
newPIRsensorState(true, true);
}
/*
* switch strip on/off
*/
// now allowing adjustable standby and highlight brightness
void switchStrip(bool switchOn) {
//if (switchOn && bri == 0) {
if (switchOn) { // **pir sensor is on and activated**
//bri = briLast;
if (bri != 0) { // is WLED currently on
if (highlightActive) { // and is Highlight already on
briHighlight = bri; // then update highlight brightness with current brightness
}
else {
briStandby = bri; // else update standby brightness with current brightness
}
}
else { // WLED is currently off
if (!highlightActive) { // and Highlight is not already on
briStandby = briLast; // then update standby brightness with last active brightness (before turned off)
standbyoff = true;
}
else { // and Highlight is already on
briHighlight = briLast; // then set hightlight brightness to last active brightness (before turned off)
}
}
applyMacro(16); // apply highlight lighting without brightness
if (bri != briHighlight) {
bri = briHighlight; // set current highlight brightness to last set highlight brightness
}
colorUpdated(NotifyUpdateMode);
highlightActive = true; // flag highlight is on
}
else { // **pir timer has elapsed**
//briLast = bri;
//bri = 0;
if (bri != 0) { // is WLED currently on
briHighlight = bri; // update highlight brightness with current brightness
if (!standbyoff) { //
bri = briStandby; // set standby brightness to last set standby brightness
}
else { //
briLast = briStandby; // set standby off brightness
bri = 0; // set power off in standby
standbyoff = false; // turn off flag
}
applyMacro(macroLongPress); // apply standby lighting without brightness
}
else { // WLED is currently off
briHighlight = briLast; // set last active brightness (before turned off) to highlight lighting brightness
if (!standbyoff) { //
bri = briStandby; // set standby brightness to last set standby brightness
}
else { //
briLast = briStandby; // set standby off brightness
bri = 0; // set power off in standby
standbyoff = false; // turn off flag
}
applyMacro(macroLongPress); // apply standby lighting without brightness
}
colorUpdated(NotifyUpdateMode);
highlightActive = false; // flag highlight is off
}
}
/*
* Read and update PIR sensor state.
* Initilize/reset switch off timer
*/
bool updatePIRsensorState() {
if (newPIRsensorState()) {
m_PIRsensorPinState = digitalRead(PIRsensorPin);
if (m_PIRsensorPinState == HIGH) {
m_offTimerStart = 0;
switchStrip(true);
}
else if (bri != 0) {
// start switch off timer
m_offTimerStart = millis();
}
newPIRsensorState(true, false);
return true;
}
return false;
}
/*
* switch off the strip if the delay has elapsed
*/
bool handleOffTimer() {
if (m_offTimerStart > 0) {
if ((millis() - m_offTimerStart > m_switchOffDelay) || bri == 0 ) { // now also checking for manual power off during highlight mode
switchStrip(false);
m_offTimerStart = 0;
return true;
}
}
return false;
}
public:
//Functions called by WLED
/*
* setup() is called once at boot. WiFi is not yet connected at this point.
* You can use it to initialize variables, sensors or similar.
*/
void setup() {
// PIR Sensor mode INPUT_PULLUP
pinMode(PIRsensorPin, INPUT_PULLUP);
// assign interrupt function and set CHANGE mode
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
// set delay to nightlight default duration on boot (after which json PIRoffSec overides if needed)
m_switchOffDelay = (nightlightDelayMins*60000);
applyMacro(macroButton); // apply default highlight lighting
briHighlight = bri;
applyMacro(macroDoublePress); // apply default standby lighting with brightness
briStandby = bri;
}
/*
* connected() is called every time the WiFi is (re)connected
* Use it to initialize network interfaces
*/
void connected() {
}
/*
* loop() is called continuously. Here you can check for events, read sensors, etc.
*/
void loop() {
if (!updatePIRsensorState()) {
handleOffTimer();
}
}
/*
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
*
* Add PIR sensor state and switch off timer duration to jsoninfo
*/
void addToJsonInfo(JsonObject& root)
{
//this code adds "u":{"&#x23F2; PIR sensor state":uiDomString} to the info object
// the value contains a button to toggle the sensor enabled/disabled
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray infoArr = user.createNestedArray("&#x23F2; PIR sensor state"); //name
String uiDomString = "<button class=\"btn infobtn\" onclick=\"requestJson({PIRenabled:";
String sensorStateInfo;
// PIR sensor state
if (m_PIRenabled) {
uiDomString += "false";
sensorStateInfo = (m_PIRsensorPinState != LOW ? "active" : "inactive"); //value
} else {
uiDomString += "true";
sensorStateInfo = "Disabled !";
}
uiDomString += "});return false;\">";
uiDomString += sensorStateInfo;
uiDomString += "</button>";
infoArr.add(uiDomString); //value
//this code adds "u":{"&#x23F2; switch off timer":uiDomString} to the info object
infoArr = user.createNestedArray("&#x23F2; switch off timer"); //name
// off timer
if (m_offTimerStart > 0) {
uiDomString = "";
unsigned int offSeconds = (m_switchOffDelay - (millis() - m_offTimerStart)) / 1000;
if (offSeconds >= 3600) {
uiDomString += (offSeconds / 3600);
uiDomString += " hours ";
offSeconds %= 3600;
}
if (offSeconds >= 60) {
uiDomString += (offSeconds / 60);
offSeconds %= 60;
} else if (uiDomString.length() > 0){
uiDomString += 0;
}
if (uiDomString.length() > 0){
uiDomString += " min ";
}
uiDomString += (offSeconds);
infoArr.add(uiDomString + " sec");
} else {
infoArr.add("inactive");
}
}
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
* Add "PIRenabled" to json state. This can be used to disable/enable the sensor.
* Add "PIRoffSec" to json state. This can be used to adjust <m_switchOffDelay> milliseconds .
*/
void addToJsonState(JsonObject& root)
{
root["PIRenabled"] = m_PIRenabled;
root["PIRoffSec"] = (m_switchOffDelay / 1000);
}
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
* Read "PIRenabled" from json state and switch enable/disable the PIR sensor.
* Read "PIRoffSec" from json state and adjust <m_switchOffDelay> milliseconds .
*/
void readFromJsonState(JsonObject& root)
{
if (root["PIRoffSec"] != nullptr) {
m_switchOffDelay = (1000 * max(60UL, min(43200UL, root["PIRoffSec"].as<unsigned long>())));
}
if (root["PIRenabled"] != nullptr) {
if (root["PIRenabled"] && !m_PIRenabled) {
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
newPIRsensorState(true, true);
}
else if(m_PIRenabled) {
detachInterrupt(PIRsensorPin);
}
m_PIRenabled = root["PIRenabled"];
}
}
/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
* This could be used in the future for the system to determine whether your usermod is installed.
*/
uint16_t getId()
{
return USERMOD_ID_PIRSWITCH;
}
//More methods can be added in the future, this example will then be extended.
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
};

View File

@@ -0,0 +1,97 @@
# PIR sensor switch
This usermod-v2 modification allows the connection of a PIR sensor to switch on the LED strip when motion is detected. The switch-off occurs ten minutes after no more motion is detected.
_Story:_
I use the PIR Sensor to automatically turn on the WLED analog clock in my home office room when I am there.
The LED strip is switched [using a relay](https://github.com/Aircoookie/WLED/wiki/Control-a-relay-with-WLED) to keep the power consumption low when it is switched off.
## Webinterface
The info page in the web interface shows the items below
- the state of the sensor. By clicking on the state the sensor can be deactivated/activated.
**I recommend to deactivate the sensor before installing an OTA update**.
- the remaining time of the off timer.
## JSON API
The usermod supports the following state changes:
| JSON key | Value range | Description |
|------------|-------------|---------------------------------|
| PIRenabled | bool | Deactivdate/activate the sensor |
| PIRoffSec | 60 to 43200 | Off timer seconds |
## Sensor connection
My setup uses an HC-SR501 sensor, a HC-SR505 should also work.
The usermod uses GPIO13 (D1 mini pin D7) for the sensor signal.
[This example page](http://www.esp8266learning.com/wemos-mini-pir-sensor-example.php) describes how to connect the sensor.
Use the potentiometers on the sensor to set the time-delay to the minimum and the sensitivity to about half, or slightly above.
## Usermod installation
1. Copy the file `usermod_PIR_sensor_switch.h` to the `wled00` directory.
2. Register the usermod by adding `#include "usermod_PIR_sensor_switch.h"` in the top and `registerUsermod(new PIRsensorSwitch());` in the bottom of `usermods_list.cpp`.
Example **usermods_list.cpp**:
```cpp
#include "wled.h"
/*
* Register your v2 usermods here!
* (for v1 usermods using just usermod.cpp, you can ignore this file)
*/
/*
* Add/uncomment your usermod filename here (and once more below)
* || || ||
* \/ \/ \/
*/
//#include "usermod_v2_example.h"
//#include "usermod_temperature.h"
//#include "usermod_v2_empty.h"
#include "usermod_PIR_sensor_switch.h"
void registerUsermods()
{
/*
* Add your usermod class name here
* || || ||
* \/ \/ \/
*/
//usermods.add(new MyExampleUsermod());
//usermods.add(new UsermodTemperature());
//usermods.add(new UsermodRenameMe());
usermods.add(new PIRsensorSwitch());
}
```
## Usermod installation (advanced mode)
In this mode IR sensor will disable PIR when light ON by remote controller and enable PIR when light OFF.
1. Copy the file `usermod_PIR_sensor_switch.h` to the `wled00` directory.
2. Register the usermod by adding `#include "usermod_PIR_sensor_switch.h"` in the top and `registerUsermod(new PIRsensorSwitch());` in the bottom of `usermods_list.cpp`.
3. Add to the line 237, on `wled.h` in the `wled00` directory:
`WLED_GLOBAL bool m_PIRenabled _INIT(true); // enable PIR sensor`
4. On `ir.cpp` in the `wled00` directory, add to the IR controller's mapping (beyond line 200):
- To the off button:
`m_PIRenabled = true;`
- To the on button:
`m_PIRenabled = false;`
5. Edit line 40, on `usermod_PIR_sensor_switch.h` in the `wled00` directory:
`\\bool m_PIRenabled = true;`
Have fun - @gegu

View File

@@ -0,0 +1,251 @@
#pragma once
#include "wled.h"
/*
* This usermod handles PIR sensor states.
* The strip will be switched on and the off timer will be resetted when the sensor goes HIGH.
* When the sensor state goes LOW, the off timer is started and when it expires, the strip is switched off.
*
*
* Usermods allow you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
*
* v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example.
* Multiple v2 usermods can be added to one compilation easily.
*
* Creating a usermod:
* This file serves as an example. If you want to create a usermod, it is recommended to use usermod_v2_empty.h from the usermods folder as a template.
* Please remember to rename the class and file to a descriptive name.
* You may also use multiple .h and .cpp files.
*
* Using a usermod:
* 1. Copy the usermod into the sketch folder (same folder as wled00.ino)
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
*/
class PIRsensorSwitch : public Usermod {
private:
// PIR sensor pin
const uint8_t PIRsensorPin = 13; // D7 on D1 mini
// notification mode for colorUpdated()
const byte NotifyUpdateMode = NOTIFIER_CALL_MODE_NO_NOTIFY; // NOTIFIER_CALL_MODE_DIRECT_CHANGE
// delay before switch off after the sensor state goes LOW
uint32_t m_switchOffDelay = 600000;
// off timer start time
uint32_t m_offTimerStart = 0;
// current PIR sensor pin state
byte m_PIRsensorPinState = LOW;
// PIR sensor enabled - ISR attached
bool m_PIRenabled = true;
/*
* return or change if new PIR sensor state is available
*/
static volatile bool newPIRsensorState(bool changeState = false, bool newState = false) {
static volatile bool s_PIRsensorState = false;
if (changeState) {
s_PIRsensorState = newState;
}
return s_PIRsensorState;
}
/*
* PIR sensor state has changed
*/
static void IRAM_ATTR ISR_PIRstateChange() {
newPIRsensorState(true, true);
}
/*
* switch strip on/off
*/
void switchStrip(bool switchOn) {
if (switchOn && bri == 0) {
bri = briLast;
colorUpdated(NotifyUpdateMode);
}
else if (!switchOn && bri != 0) {
briLast = bri;
bri = 0;
colorUpdated(NotifyUpdateMode);
}
}
/*
* Read and update PIR sensor state.
* Initilize/reset switch off timer
*/
bool updatePIRsensorState() {
if (newPIRsensorState()) {
m_PIRsensorPinState = digitalRead(PIRsensorPin);
if (m_PIRsensorPinState == HIGH) {
m_offTimerStart = 0;
switchStrip(true);
}
else if (bri != 0) {
// start switch off timer
m_offTimerStart = millis();
}
newPIRsensorState(true, false);
return true;
}
return false;
}
/*
* switch off the strip if the delay has elapsed
*/
bool handleOffTimer() {
if (m_offTimerStart > 0 && millis() - m_offTimerStart > m_switchOffDelay) {
if (m_PIRenabled == true){
switchStrip(false);
}
m_offTimerStart = 0;
return true;
}
return false;
}
public:
//Functions called by WLED
/*
* setup() is called once at boot. WiFi is not yet connected at this point.
* You can use it to initialize variables, sensors or similar.
*/
void setup() {
// PIR Sensor mode INPUT_PULLUP
pinMode(PIRsensorPin, INPUT_PULLUP);
// assign interrupt function and set CHANGE mode
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
}
/*
* connected() is called every time the WiFi is (re)connected
* Use it to initialize network interfaces
*/
void connected() {
}
/*
* loop() is called continuously. Here you can check for events, read sensors, etc.
*/
void loop() {
if (!updatePIRsensorState()) {
handleOffTimer();
}
}
/*
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
*
* Add PIR sensor state and switch off timer duration to jsoninfo
*/
void addToJsonInfo(JsonObject& root)
{
//this code adds "u":{"&#x23F2; PIR sensor state":uiDomString} to the info object
// the value contains a button to toggle the sensor enabled/disabled
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray infoArr = user.createNestedArray("&#x23F2; PIR sensor state"); //name
String uiDomString = "<button class=\"btn infobtn\" onclick=\"requestJson({PIRenabled:";
String sensorStateInfo;
// PIR sensor state
if (m_PIRenabled) {
uiDomString += "false";
sensorStateInfo = (m_PIRsensorPinState != LOW ? "active" : "inactive"); //value
} else {
uiDomString += "true";
sensorStateInfo = "Disabled !";
}
uiDomString += "});return false;\">";
uiDomString += sensorStateInfo;
uiDomString += "</button>";
infoArr.add(uiDomString); //value
//this code adds "u":{"&#x23F2; switch off timer":uiDomString} to the info object
infoArr = user.createNestedArray("&#x23F2; switch off timer"); //name
// off timer
if (m_offTimerStart > 0) {
uiDomString = "";
unsigned int offSeconds = (m_switchOffDelay - (millis() - m_offTimerStart)) / 1000;
if (offSeconds >= 3600) {
uiDomString += (offSeconds / 3600);
uiDomString += " hours ";
offSeconds %= 3600;
}
if (offSeconds >= 60) {
uiDomString += (offSeconds / 60);
offSeconds %= 60;
} else if (uiDomString.length() > 0){
uiDomString += 0;
}
if (uiDomString.length() > 0){
uiDomString += " min ";
}
uiDomString += (offSeconds);
infoArr.add(uiDomString + " sec");
} else {
infoArr.add("inactive");
}
}
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
* Add "PIRenabled" to json state. This can be used to disable/enable the sensor.
* Add "PIRoffSec" to json state. This can be used to adjust <m_switchOffDelay> milliseconds .
*/
void addToJsonState(JsonObject& root)
{
root["PIRenabled"] = m_PIRenabled;
root["PIRoffSec"] = (m_switchOffDelay / 1000);
}
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
* Read "PIRenabled" from json state and switch enable/disable the PIR sensor.
* Read "PIRoffSec" from json state and adjust <m_switchOffDelay> milliseconds .
*/
void readFromJsonState(JsonObject& root)
{
if (root["PIRoffSec"] != nullptr) {
m_switchOffDelay = (1000 * max(60UL, min(43200UL, root["PIRoffSec"].as<unsigned long>())));
}
if (root["PIRenabled"] != nullptr) {
if (root["PIRenabled"] && !m_PIRenabled) {
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
newPIRsensorState(true, true);
}
else if(m_PIRenabled) {
detachInterrupt(PIRsensorPin);
}
m_PIRenabled = root["PIRenabled"];
}
}
/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
* This could be used in the future for the system to determine whether your usermod is installed.
*/
uint16_t getId()
{
return USERMOD_ID_PIRSWITCH;
}
//More methods can be added in the future, this example will then be extended.
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
};

View File

@@ -0,0 +1,77 @@
# TTGO T-Display ESP32 with 240x135 TFT via SPI with TFT_eSPI
This usermod allows use of the TTGO T-Display ESP32 module with integrated 240x135 display
for controlling WLED and showing the following information:
* Current SSID
* IP address if obtained
* in AP mode and turned off lightning AP password is shown
* Current effect
* Current palette
Usermod based on a rework of the ssd1306_i2c_oled_u8g2 usermod from the WLED repo.
## Hardware
![Hardware](assets/ttgo_hardware1.png)
## Github reference for TTGO-Tdisplay
* [TTGO T-Display](https://github.com/Xinyuan-LilyGO/TTGO-T-Display)
## Requirements
Functionality checked with:
* TTGO T-Display
* PlatformIO
* Group of 4 individual Neopixels from Adafruit, and a full string of 68 LEDs.
## Platformio Requirements
### Platformio.ini changes
Under the root folder of the project, in the `platformio.ini` file, uncomment the `TFT_eSPI` line within the [common] section, under `lib_deps`:
```ini
# platformio.ini
...
[common]
...
lib_deps =
...
#For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line
#TFT_eSPI
...
```
Also, while in the `platformio.ini` file, you must change the environment setup to build for just the esp32dev platform as follows:
Comment out the line described below:
```ini
# Travis CI binaries (comment this out when building for single board)
; default_envs = travis_esp8266, esp01, esp01_1m_ota, travis_esp32
```
and UNCOMMENT the following line in the 'Single binaries' section:
```ini
default_envs = esp32dev
```
Save the `platformio.ini` file. Once this is saved, the required library files should be automatically downloaded for modifications in a later step.
### Platformio_overrides.ini (added)
Copy the `platformio_overrides.ini` file which is contained in the `usermods/TTGO-T-Display/` folder into the root of your project folder. This file contains an override that remaps the button pin of WLED to use the on-board button to the right of the USB-C connector (when viewed with the port oriented downward - see hardware photo).
### TFT_eSPI Library Adjustments (board selection)
We need to modify a file in the `TFT_eSPI` library to select the correct board. If you followed the directions to modify and save the `platformio.ini` file above, the `User_Setup_Select.h` file can be found in the `/.pio/libdeps/esp32dev/TFT_eSPI_ID1559` folder.
Modify the `User_Setup_Select.h` file as follows:
* Comment out the following line (which is the 'default' setup file):
```ini
//#include <User_Setup.h> // Default setup is root library folder
```
* Uncomment the following line (which points to the setup file for the TTGO T-Display):
```ini
#include <User_Setups/Setup25_TTGO_T_Display.h> // Setup file for ESP32 and TTGO T-Display ST7789V SPI bus TFT
```
Run the build and it should complete correctly. If you see a failure like this:
```ini
xtensa-esp32-elf-g++: error: wled00\wled00.ino.cpp: No such file or directory
xtensa-esp32-elf-g++: fatal error: no input files
```
Just try building again - I find that sometimes this happens on the first build attempt and subsequent attempts will build correctly.
## Arduino IDE
- UNTESTED

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 KiB

View File

@@ -0,0 +1,8 @@
[env:esp32dev]
build_flags = ${common.build_flags_esp32}
; PIN defines - uncomment and change, if needed:
; -D LEDPIN=2
-D BTNPIN=35
; -D IRPIN=4
; -D RLYPIN=12
; -D RLYMDE=1

View File

@@ -0,0 +1,214 @@
/*
* This file allows you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
* bytes 2400+ are currently ununsed, but might be used for future wled features
*/
/*
* Pin 2 of the TTGO T-Display serves as the data line for the LED string.
* Pin 35 is set up as the button pin in the platformio_overrides.ini file.
* The button can be set up via the macros section in the web interface.
* I use the button to cycle between presets.
* The Pin 35 button is the one on the RIGHT side of the USB-C port on the board,
* when the port is oriented downwards. See readme.md file for photo.
* The display is set up to turn off after 5 minutes, and turns on automatically
* when a change in the dipslayed info is detected (within a 5 second interval).
*/
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
#include "wled.h"
#include <TFT_eSPI.h>
#include <SPI.h>
#include "WiFi.h"
#include <Wire.h>
#ifndef TFT_DISPOFF
#define TFT_DISPOFF 0x28
#endif
#ifndef TFT_SLPIN
#define TFT_SLPIN 0x10
#endif
#define TFT_MOSI 19
#define TFT_SCLK 18
#define TFT_CS 5
#define TFT_DC 16
#define TFT_RST 23
#define TFT_BL 4 // Display backlight control pin
#define ADC_EN 14 // Used for enabling battery voltage measurements - not used in this program
TFT_eSPI tft = TFT_eSPI(135, 240); // Invoke custom library
//gets called once at boot. Do all initialization that doesn't depend on network here
void userSetup() {
Serial.begin(115200);
Serial.println("Start");
tft.init();
tft.setRotation(3); //Rotation here is set up for the text to be readable with the port on the left. Use 1 to flip.
tft.fillScreen(TFT_BLACK);
tft.setTextSize(2);
tft.setTextColor(TFT_WHITE);
tft.setCursor(1, 10);
tft.setTextDatum(MC_DATUM);
tft.setTextSize(2);
tft.print("Loading...");
if (TFT_BL > 0) { // TFT_BL has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h
pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode
digitalWrite(TFT_BL, HIGH); // Turn backlight on.
}
// tft.setRotation(3);
}
// gets called every time WiFi is (re-)connected. Initialize own network
// interfaces here
void userConnected() {}
// needRedraw marks if redraw is required to prevent often redrawing.
bool needRedraw = true;
// Next variables hold the previous known values to determine if redraw is
// required.
String knownSsid = "";
IPAddress knownIp;
uint8_t knownBrightness = 0;
uint8_t knownMode = 0;
uint8_t knownPalette = 0;
uint8_t tftcharwidth = 19; // Number of chars that fit on screen with text size set to 2
long lastUpdate = 0;
long lastRedraw = 0;
bool displayTurnedOff = false;
// How often we are redrawing screen
#define USER_LOOP_REFRESH_RATE_MS 5000
void userLoop() {
// Check if we time interval for redrawing passes.
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) {
return;
}
lastUpdate = millis();
// Turn off display after 5 minutes with no change.
if(!displayTurnedOff && millis() - lastRedraw > 5*60*1000) {
digitalWrite(TFT_BL, LOW); // Turn backlight off.
displayTurnedOff = true;
}
// Check if values which are shown on display changed from the last time.
if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) {
needRedraw = true;
} else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) {
needRedraw = true;
} else if (knownBrightness != bri) {
needRedraw = true;
} else if (knownMode != strip.getMode()) {
needRedraw = true;
} else if (knownPalette != strip.getSegment(0).palette) {
needRedraw = true;
}
if (!needRedraw) {
return;
}
needRedraw = false;
if (displayTurnedOff)
{
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); // Turn backlight on.
displayTurnedOff = false;
}
lastRedraw = millis();
// Update last known values.
#if defined(ESP8266)
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
#else
knownSsid = WiFi.SSID();
#endif
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
knownBrightness = bri;
knownMode = strip.getMode();
knownPalette = strip.getSegment(0).palette;
tft.fillScreen(TFT_BLACK);
tft.setTextSize(2);
// First row with Wifi name
tft.setCursor(1, 10);
tft.print(knownSsid.substring(0, tftcharwidth > 1 ? tftcharwidth - 1 : 0));
// Print `~` char to indicate that SSID is longer, than our dicplay
if (knownSsid.length() > tftcharwidth)
tft.print("~");
// Second row with IP or Psssword
tft.setCursor(1, 40);
// Print password in AP mode and if led is OFF.
if (apActive && bri == 0)
tft.print(apPass);
else
tft.print(knownIp);
// Third row with mode name
tft.setCursor(1, 70);
uint8_t qComma = 0;
bool insideQuotes = false;
uint8_t printedChars = 0;
char singleJsonSymbol;
// Find the mode name in JSON
for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) {
singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i);
switch (singleJsonSymbol) {
case '"':
insideQuotes = !insideQuotes;
break;
case '[':
case ']':
break;
case ',':
qComma++;
default:
if (!insideQuotes || (qComma != knownMode))
break;
tft.print(singleJsonSymbol);
printedChars++;
}
if ((qComma > knownMode) || (printedChars > tftcharwidth - 1))
break;
}
// Fourth row with palette name
tft.setCursor(1, 100);
qComma = 0;
insideQuotes = false;
printedChars = 0;
// Looking for palette name in JSON.
for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) {
singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i);
switch (singleJsonSymbol) {
case '"':
insideQuotes = !insideQuotes;
break;
case '[':
case ']':
break;
case ',':
qComma++;
default:
if (!insideQuotes || (qComma != knownPalette))
break;
tft.print(singleJsonSymbol);
printedChars++;
}
// The following is modified from the code from the u8g2/u8g8 based code (knownPalette was knownMode)
if ((qComma > knownPalette) || (printedChars > tftcharwidth - 1))
break;
}
}

View File

@@ -0,0 +1,13 @@
; Options
; -------
; USERMOD_DALLASTEMPERATURE - define this to have this user mod included wled00\usermods_list.cpp
; USERMOD_DALLASTEMPERATURE_CELSIUS - define this to report temperatures in degrees celsius, otherwise fahrenheit will be reported
; USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - the number of milliseconds between measurements, defaults to 60 seconds
; USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT - the number of milliseconds after boot to take first measurement, defaults to 20 seconds
;
[env:d1_mini_usermod_dallas_temperature_C]
extends = env:d1_mini
build_flags = ${common.build_flags_esp8266} -D USERMOD_DALLASTEMPERATURE -D USERMOD_DALLASTEMPERATURE_CELSIUS
lib_deps = ${env.lib_deps}
milesburton/DallasTemperature@^3.9.0
OneWire@~2.3.5

View File

@@ -0,0 +1,58 @@
# Temperature usermod
Based on the excellent `QuinLED_Dig_Uno_Temp_MQTT` by srg74 and 400killer!
This usermod will read from an attached DS18B20 temperature sensor (as available on the QuinLED Dig-Uno)
The temperature is displayed both in the Info section of the web UI as well as published to the `/temperature` MQTT topic if enabled.
This usermod will be expanded with support for different sensor types in the future.
If temperature sensor is not detected during boot, this usermod will be disabled.
## Installation
Copy the example `platformio_override.ini` to the root directory. This file should be placed in the same directory as `platformio.ini`.
### Define Your Options
* `USERMOD_DALLASTEMPERATURE` - define this to have this user mod included wled00\usermods_list.cpp
* `USERMOD_DALLASTEMPERATURE_CELSIUS` - define this to report temperatures in degrees celsious, otherwise fahrenheit will be reported
* `USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL` - the number of milliseconds between measurements, defaults to 60 seconds
* `USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 20 seconds
## Project link
* [QuinLED-Dig-Uno](https://quinled.info/2018/09/15/quinled-dig-uno/) - Project link
### PlatformIO requirements
If you are using `platformio_override.ini`, you should be able to refresh the task list and see your custom task, for example `env:d1_mini_usermod_dallas_temperature_C`.
If you are not using `platformio_override.ini`, you might have to uncomment `DallasTemperature@~3.8.0`,`OneWire@~2.3.5 under` `[common]` section in `platformio.ini`:
```ini
# platformio.ini
...
[platformio]
...
; default_envs = esp07
default_envs = d1_mini
...
[common]
...
lib_deps_external =
...
#For use SSD1306 OLED display uncomment following
U8g2@~2.27.3
#For Dallas sensor uncomment following 2 lines
DallasTemperature@~3.8.0
OneWire@~2.3.5
...
```
## Change Log
2020-09-12
* Changed to use async, non-blocking implementation
* Do not report low temperatures that indicate an error to mqtt
* Disable plugin if temperature sensor not detected
* Report the number of seconds until the first read in the info screen instead of sensor error

View File

@@ -0,0 +1,174 @@
#pragma once
#include "wled.h"
#include <DallasTemperature.h> //DS18B20
//Pin defaults for QuinLed Dig-Uno
#ifdef ARDUINO_ARCH_ESP32
#define TEMPERATURE_PIN 18
#else //ESP8266 boards
#define TEMPERATURE_PIN 14
#endif
// the frequency to check temperature, 1 minute
#ifndef USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL
#define USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL 60000
#endif
// how many seconds after boot to take first measurement, 20 seconds
#ifndef USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT
#define USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT 20000
#endif
OneWire oneWire(TEMPERATURE_PIN);
DallasTemperature sensor(&oneWire);
class UsermodTemperature : public Usermod {
private:
// The device's unique 64-bit serial code stored in on-board ROM.
// Reading directly from the sensor device address is faster than
// reading from index. When reading by index, DallasTemperature
// must first look up the device address at the specified index.
DeviceAddress sensorDeviceAddress;
// set last reading as "40 sec before boot", so first reading is taken after 20 sec
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT);
// last time requestTemperatures was called
// used to determine when we can read the sensors temperature
// we have to wait at least 93.75 ms after requestTemperatures() is called
unsigned long lastTemperaturesRequest;
float temperature = -100; // default to -100, DS18B20 only goes down to -50C
// indicates requestTemperatures has been called but the sensor measurement is not complete
bool waitingForConversion = false;
// flag to indicate we have finished the first getTemperature call
// allows this library to report to the user how long until the first
// measurement
bool getTemperatureComplete = false;
// flag set at startup if DS18B20 sensor not found, avoids trying to keep getting
// temperature if flashed to a board without a sensor attached
bool disabled = false;
void requestTemperatures() {
// there is requestTemperaturesByAddress however it
// appears to do more work,
// TODO: measure exection time difference
sensor.requestTemperatures();
lastTemperaturesRequest = millis();
waitingForConversion = true;
}
void getTemperature() {
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
temperature = sensor.getTempC(sensorDeviceAddress);
#else
temperature = sensor.getTempF(sensorDeviceAddress);
#endif
lastMeasurement = millis();
waitingForConversion = false;
getTemperatureComplete = true;
}
public:
void setup() {
sensor.begin();
// get the unique 64-bit serial code stored in on-board ROM
// if getAddress returns false, the sensor was not found
disabled = !sensor.getAddress(sensorDeviceAddress, 0);
if (!disabled) {
DEBUG_PRINTLN("Dallas Temperature found");
// set the resolution for this specific device
sensor.setResolution(sensorDeviceAddress, 9, true);
// do not block waiting for reading
sensor.setWaitForConversion(false);
} else {
DEBUG_PRINTLN("Dallas Temperature not found");
}
}
void loop() {
if (disabled) {
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 < USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL)
{
return;
}
// we are due for a measurement, if we are not already waiting
// for a conversion to complete, then make a new request for temps
if (!waitingForConversion)
{
requestTemperatures();
return;
}
// we were waiting for a conversion to complete, have we waited log enough?
if (now - lastTemperaturesRequest >= 94 /* 93.75ms per the datasheet */)
{
getTemperature();
if (WLED_MQTT_CONNECTED) {
char subuf[38];
strcpy(subuf, mqttDeviceTopic);
if (-100 <= temperature) {
// dont publish super low temperature as the graph will get messed up
// the DallasTemperature library returns -127C or -196.6F when problem
// reading the sensor
strcat(subuf, "/temperature");
mqtt->publish(subuf, 0, true, String(temperature).c_str());
} else {
// publish something else to indicate status?
}
}
}
}
void addToJsonInfo(JsonObject& root) {
// dont add temperature to info if we are disabled
if (disabled) {
return;
}
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray temp = user.createNestedArray("Temperature");
if (!getTemperatureComplete) {
// if we haven't read the sensor yet, let the user know
// that we are still waiting for the first measurement
temp.add((USERMOD_DALLASTEMPERATURE_FIRST_MEASUREMENT_AT - millis()) / 1000);
temp.add(" sec until read");
return;
}
if (temperature <= -100) {
temp.add(0);
temp.add(" Sensor Error!");
return;
}
temp.add(temperature);
#ifdef USERMOD_DALLASTEMPERATURE_CELSIUS
temp.add("°C");
#else
temp.add("°F");
#endif
}
uint16_t getId()
{
return USERMOD_ID_TEMPERATURE;
}
};

View File

@@ -0,0 +1,31 @@
#include "wled.h"
/*
* Register your v2 usermods here!
*/
/*
* Add/uncomment your usermod filename here (and once more below)
* || || ||
* \/ \/ \/
*/
//#include "usermod_v2_example.h"
#ifdef USERMOD_DALLASTEMPERATURE
#include "../usermods/Temperature/usermod_temperature.h"
#endif
//#include "usermod_v2_empty.h"
void registerUsermods()
{
/*
* Add your usermod class name here
* || || ||
* \/ \/ \/
*/
//usermods.add(new MyExampleUsermod());
#ifdef USERMOD_DALLASTEMPERATURE
usermods.add(new UsermodTemperature());
#endif
//usermods.add(new UsermodRenameMe());
}

View File

@@ -0,0 +1,15 @@
WLED v2 UserMod for running macros at sunrise and sunset.
At the time of this text, this user mod requires code to be changed to set certain variables:
1. To reflect the user's graphical location (latitude/longitude) used for calculating apparent sunrise/sunset
2. To specify which macros will be run at sunrise and/or sunset. (defaults to 15 at sunrise and 16 at sunset)
3. To optionally provide an offset from sunrise/sunset, in minutes (max of +/- 2 hours), when the macro will be run.
In addition, WLED must be configured to get time from NTP (and the time must be retrieved via NTP.)
Please open the UserMod_SunRiseAndSet.h file for instructions on what needs to be changed, where to copy files, etc.
If this usermod proves useful enough, the code might eventually be updated to allow prompting for the required information
via the web interface and to store settings in EEPROM instead of hard-coding in the .h file.
This usermod has only been tested on the esp32dev platform, but there's no reason it wouldn't work on other platforms.

View File

@@ -0,0 +1,166 @@
#pragma once
#include "wled.h"
#include <Dusk2Dawn.h>
/*
*
* REQUIREMENTS:
* The Dusk2Dawn library must be installed. This can be found at https://github.com/dmkishi/Dusk2Dawn. The 1.0.1 version of this library found via
* Arduino or platformio library managers is buggy and won't compile. The latest version from github should be used.
*
* NTP must be enabled and functional. It simply makes no sense to have events on sunrise/sunset when an accurate time isn't available.
*
* The user's geographical latitude and longitude must be configured (in decimal, not degrees/minutes/etc) using m_fLatitude and m_fLongitude
*
* if desired, an offset of up to +/- 2 hours can be specified for each of sunrise/sunset using m_sunriseOffset and m_sunsetOffset (defaults to 0)
*
* The specific macro to run at sunrise and/or sunset can be changed using m_sunriseMacro and m_sunsetMacro. (defaults to 15 and 16)
*
* From the Dusk2Dawn library:
* HINT: An easy way to find the longitude and latitude for any location is
* to find the spot in Google Maps, right click the place on the map, and
* select "What's here?". At the bottom, youll see a card with the
* coordinates.
*
* Once configured, copy UserMod_SunRiseAndSet.h to the sketch file (the same folder as wled00.ino exists),
* and then edit "usermods_list.cpp":
* Add '#include "UserMod_SunRiseAndSet.h"' in the 'includes' area
* Add 'usermods.add(new UserMod_SunRiseAndSet());' in the registerUsermods() area
*
*/
class UserMod_SunRiseAndSet : public Usermod
{
private:
/**** USER SETTINGS ****/
float m_fLatitude = 40.6; // latitude where sunrise/set are calculated
float m_fLongitude = -79.80; // longitude where sunrise/set are calculated
int8_t m_sunriseOffset = 0; // offset from sunrise, in minutes, when macro should be run (negative for before sunrise, positive for after sunrise)
int8_t m_sunsetOffset = 0; // offset from sunset, in minutes, when macro should be run (negative for before sunset, positive for after sunset)
uint8_t m_sunriseMacro = 15; // macro number to run at sunrise
uint8_t m_sunsetMacro = 16; // macro number to run at sunset
/**** END OF USER SETTINGS. DO NOT EDIT BELOW THIS LINE! ****/
Dusk2Dawn *m_pD2D = NULL; // this must be dynamically allocated in order for parameters to be loaded from EEPROM
int m_nUserSunrise = -1; // time, in minutes from midnight, of sunrise
int m_nUserSunset = -1; // time, in minutes from midnight, of sunset
byte m_nLastRunMinute = -1; // indicates what minute the userloop was last run - used so that the code only runs once per minute
public:
virtual void setup(void)
{
/* TODO: From EEPROM, load the following variables:
*
* int16_t latitude16 = 4060; // user provided latitude, multiplied by 100 and rounded
* int16_t longitude16 = -7980; // user provided longitude, multiplied by 100 and rounded.
* int8_t sunrise_offset = 0; // number of minutes to offset the sunrise macro trigger (positive for minutes after sunrise, negative for minutes before)
* int8_t sunset_offset = 0; // number of minutes to offset the sunset macro trigger (positive for minutes after sunset, negative for minutes before)
*
* then:
* m_fLatitude = (float)latitude / 100.0;
* m_fLongitude = (float)longitude / 100.0;
* m_sunriseOffset = sunrise_offset;
* m_sunsetOffset = sunset_offset;
*/
if ((0.0 != m_fLatitude) || (0.0 != m_fLongitude))
{
m_pD2D = new Dusk2Dawn (m_fLatitude, m_fLongitude, 0 /* UTC */);
// can't really check for failures. if the alloc fails, the mod just doesn't work.
}
}
void loop(void)
{
// without NTP, or a configured lat/long, none of this stuff is going to work...
// As an alternative, need to figure out how to determine if the user has manually set the clock or not.
if (m_pD2D && (999000000L != ntpLastSyncTime))
{
// to prevent needing to import all the timezone stuff from other modules, work completely in UTC
time_t timeUTC = now();
tmElements_t tmNow;
breakTime(timeUTC, tmNow);
int nCurMinute = tmNow.Minute;
if (m_nLastRunMinute != nCurMinute) //only check once a new minute begins
{
m_nLastRunMinute = nCurMinute;
int numMinutes = (60 * tmNow.Hour) + m_nLastRunMinute; // how many minutes into the day are we?
// check to see if sunrise/sunset should be re-determined. Only do this if neither sunrise nor sunset
// are set. That happens when the device has just stated, and after both sunrise/sunset have already run.
if ((-1 == m_nUserSunrise) && (-1 == m_nUserSunset))
{
m_nUserSunrise = m_pD2D->sunrise(tmNow.Year + 1970, tmNow.Month, tmNow.Day, false) % 1440;
m_nUserSunset = m_pD2D->sunset(tmNow.Year + 1970, tmNow.Month, tmNow.Day, false) % 1440;
if (m_nUserSunrise > numMinutes) // has sunrise already passed? if so, recompute for tomorrow
{
breakTime(timeUTC + (60*60*24), tmNow);
m_nUserSunrise = m_pD2D->sunrise(tmNow.Year + 1970, tmNow.Month, tmNow.Day, false) % 1440;
if (m_nUserSunset > numMinutes) // if sunset has also passed, recompute that as well
{
m_nUserSunset = m_pD2D->sunset(tmNow.Year + 1970, tmNow.Month, tmNow.Day, false) % 1440;
}
}
// offset by user provided values. becuase the offsets are signed bytes, the max offset is just over 2 hours.
m_nUserSunrise += m_sunriseOffset;
m_nUserSunset += m_sunsetOffset;
}
if (numMinutes == m_nUserSunrise) // Good Morning!
{
if (m_sunriseMacro)
applyMacro(m_sunriseMacro); // run macro 15
m_nUserSunrise = -1;
}
else if (numMinutes == m_nUserSunset) // Good Night!
{
if (m_sunsetMacro)
applyMacro(m_sunsetMacro); // run macro 16
m_nUserSunset = -1;
}
} // if (m_nLastRunMinute != nCurMinute)
} // if (m_pD2D && (999000000L != ntpLastSyncTime))
}
void addToJsonState(JsonObject& root)
{
JsonObject user = root["SunRiseAndSet"];
if (user.isNull()) user = root.createNestedObject("SunRiseAndSet");
char buf[10];
if (-1 != m_nUserSunrise)
{
snprintf(buf, 10, "%02d:%02d UTC", m_nUserSunrise / 60, m_nUserSunrise % 60);
user["rise"] = buf;
}
if (-1 != m_nUserSunset)
{
snprintf(buf, 10, "%02d:%02d UTC", m_nUserSunset / 60, m_nUserSunset % 60);
user["set"] = buf;
}
JsonObject vars = user.createNestedObject("vars");
vars["lat"] = m_fLatitude;
vars["long"] = m_fLongitude;
vars["rise_mac"] = m_sunriseMacro;
vars["set_mac"] = m_sunsetMacro;
vars["rise_off"] = m_sunriseOffset;
vars["set_off"] = m_sunsetOffset;
}
~UserMod_SunRiseAndSet(void)
{
if (m_pD2D) delete m_pD2D;
}
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 KiB

After

Width:  |  Height:  |  Size: 299 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

After

Width:  |  Height:  |  Size: 323 KiB

View File

@@ -0,0 +1,407 @@
//this code is a modified version of https://github.com/Makuna/NeoPixelBus/issues/103
#ifndef NpbWrapper_h
#define NpbWrapper_h
// make sure we're using esp32 platform
#ifndef ARDUINO_ARCH_ESP32
#error This version of NbpWrapper.h only works with ESP32 hardware.
#endif
#ifndef NUM_STRIPS
#error Need to define number of LED strips using build flag -D NUM_STRIPS=4 for 4 LED strips
#endif
#ifndef PIXEL_COUNTS
#error Need to define pixel counts using build flag -D PIXEL_COUNTS="25, 25, 25, 25" for 4 LED strips with 25 LEDs each
#endif
#ifndef DATA_PINS
#error Need to define data pins using build flag -D DATA_PINS="1, 2, 3, 4" if LED strips are on data pins 1, 2, 3, and 4
#endif
// //PIN CONFIGURATION
#ifndef LEDPIN
#define LEDPIN 1 // Legacy pin def required by some other portions of code. This pin is not used do drive LEDs.
#endif
#ifndef IRPIN
#define IRPIN -1 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
#endif
#ifndef RLYPIN
#define RLYPIN -1 //pin for relay, will be set HIGH if LEDs are on (-1 to disable). Also usable for standby leds, triggers,...
#endif
#ifndef AUXPIN
#define AUXPIN -1 //debug auxiliary output pin (-1 to disable)
#endif
#ifndef RLYMDE
#define RLYMDE 1 //mode for relay, 0: LOW if LEDs are on 1: HIGH if LEDs are on
#endif
#include <NeoPixelBrightnessBus.h>
const uint8_t numStrips = NUM_STRIPS; // max 8 strips allowed on esp32
const uint16_t pixelCounts[numStrips] = {PIXEL_COUNTS}; // number of pixels on each strip
const uint8_t dataPins[numStrips] = {DATA_PINS}; // change these pins based on your board
#define PIXELFEATURE3 NeoGrbFeature
#define PIXELFEATURE4 NeoGrbwFeature
// ESP32 has 8 RMT interfaces available, each of which can drive a strip of pixels
// Convenience #defines for creating NeoPixelBrightnessBus on each RMT interface for both GRB and GRBW LED strips
#define NeoPixelBrightnessBusGrbRmt0 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt0Ws2812xMethod>
#define NeoPixelBrightnessBusGrbRmt1 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt1Ws2812xMethod>
#define NeoPixelBrightnessBusGrbRmt2 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt2Ws2812xMethod>
#define NeoPixelBrightnessBusGrbRmt3 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt3Ws2812xMethod>
#define NeoPixelBrightnessBusGrbRmt4 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt4Ws2812xMethod>
#define NeoPixelBrightnessBusGrbRmt5 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt5Ws2812xMethod>
#define NeoPixelBrightnessBusGrbRmt6 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt6Ws2812xMethod>
#define NeoPixelBrightnessBusGrbRmt7 NeoPixelBrightnessBus<PIXELFEATURE3, NeoEsp32Rmt7Ws2812xMethod>
#define NeoPixelBrightnessBusGrbwRmt0 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt0Ws2812xMethod>
#define NeoPixelBrightnessBusGrbwRmt1 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt1Ws2812xMethod>
#define NeoPixelBrightnessBusGrbwRmt2 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt2Ws2812xMethod>
#define NeoPixelBrightnessBusGrbwRmt3 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt3Ws2812xMethod>
#define NeoPixelBrightnessBusGrbwRmt4 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt4Ws2812xMethod>
#define NeoPixelBrightnessBusGrbwRmt5 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt5Ws2812xMethod>
#define NeoPixelBrightnessBusGrbwRmt6 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt6Ws2812xMethod>
#define NeoPixelBrightnessBusGrbwRmt7 NeoPixelBrightnessBus<PIXELFEATURE4, NeoEsp32Rmt7Ws2812xMethod>
enum NeoPixelType
{
NeoPixelType_None = 0,
NeoPixelType_Grb = 1,
NeoPixelType_Grbw = 2,
NeoPixelType_End = 3
};
class NeoPixelWrapper
{
public:
NeoPixelWrapper() :
_type(NeoPixelType_None)
{
// On initialization fill in the pixelStripStartIdx array with the beginning index of each strip
// relative to th entire array.
uint16_t totalPixels = 0;
for (uint8_t idx = 0; idx < numStrips; idx++)
{
pixelStripStartIdx[idx] = totalPixels;
totalPixels += pixelCounts[idx];
}
}
~NeoPixelWrapper()
{
cleanup();
}
void Begin(NeoPixelType type, uint16_t pixelCount)
{
cleanup();
_type = type;
switch (_type)
{
case NeoPixelType_Grb:
{
for (uint8_t idx = 0; idx < numStrips; idx++)
{
switch (idx)
{
case 0: pGrb0 = new NeoPixelBrightnessBusGrbRmt0(pixelCounts[idx], dataPins[idx]); pGrb0->Begin(); break;
case 1: pGrb1 = new NeoPixelBrightnessBusGrbRmt1(pixelCounts[idx], dataPins[idx]); pGrb1->Begin(); break;
case 2: pGrb2 = new NeoPixelBrightnessBusGrbRmt2(pixelCounts[idx], dataPins[idx]); pGrb2->Begin(); break;
case 3: pGrb3 = new NeoPixelBrightnessBusGrbRmt3(pixelCounts[idx], dataPins[idx]); pGrb3->Begin(); break;
case 4: pGrb4 = new NeoPixelBrightnessBusGrbRmt4(pixelCounts[idx], dataPins[idx]); pGrb4->Begin(); break;
case 5: pGrb5 = new NeoPixelBrightnessBusGrbRmt5(pixelCounts[idx], dataPins[idx]); pGrb5->Begin(); break;
case 6: pGrb6 = new NeoPixelBrightnessBusGrbRmt6(pixelCounts[idx], dataPins[idx]); pGrb6->Begin(); break;
case 7: pGrb7 = new NeoPixelBrightnessBusGrbRmt7(pixelCounts[idx], dataPins[idx]); pGrb7->Begin(); break;
}
}
break;
}
case NeoPixelType_Grbw:
{
for (uint8_t idx = 0; idx < numStrips; idx++)
{
switch (idx)
{
case 0: pGrbw0 = new NeoPixelBrightnessBusGrbwRmt0(pixelCounts[idx], dataPins[idx]); pGrbw0->Begin(); break;
case 1: pGrbw1 = new NeoPixelBrightnessBusGrbwRmt1(pixelCounts[idx], dataPins[idx]); pGrbw1->Begin(); break;
case 2: pGrbw2 = new NeoPixelBrightnessBusGrbwRmt2(pixelCounts[idx], dataPins[idx]); pGrbw2->Begin(); break;
case 3: pGrbw3 = new NeoPixelBrightnessBusGrbwRmt3(pixelCounts[idx], dataPins[idx]); pGrbw3->Begin(); break;
case 4: pGrbw4 = new NeoPixelBrightnessBusGrbwRmt4(pixelCounts[idx], dataPins[idx]); pGrbw4->Begin(); break;
case 5: pGrbw5 = new NeoPixelBrightnessBusGrbwRmt5(pixelCounts[idx], dataPins[idx]); pGrbw5->Begin(); break;
case 6: pGrbw6 = new NeoPixelBrightnessBusGrbwRmt6(pixelCounts[idx], dataPins[idx]); pGrbw6->Begin(); break;
case 7: pGrbw7 = new NeoPixelBrightnessBusGrbwRmt7(pixelCounts[idx], dataPins[idx]); pGrbw7->Begin(); break;
}
}
break;
}
}
}
void Show()
{
byte b;
switch (_type)
{
case NeoPixelType_Grb:
{
for (uint8_t idx = 0; idx < numStrips; idx++)
{
switch (idx)
{
case 0: pGrb0->Show(); break;
case 1: pGrb1->Show(); break;
case 2: pGrb2->Show(); break;
case 3: pGrb3->Show(); break;
case 4: pGrb4->Show(); break;
case 5: pGrb5->Show(); break;
case 6: pGrb6->Show(); break;
case 7: pGrb7->Show(); break;
}
}
break;
}
case NeoPixelType_Grbw:
{
for (uint8_t idx = 0; idx < numStrips; idx++)
{
switch (idx)
{
case 0: pGrbw0->Show(); break;
case 1: pGrbw1->Show(); break;
case 2: pGrbw2->Show(); break;
case 3: pGrbw3->Show(); break;
case 4: pGrbw4->Show(); break;
case 5: pGrbw5->Show(); break;
case 6: pGrbw6->Show(); break;
case 7: pGrbw7->Show(); break;
}
}
break;
}
}
}
void SetPixelColor(uint16_t indexPixel, RgbwColor color)
{
// figure out which strip this pixel index is on
uint8_t stripIdx = 0;
for (uint8_t idx = 0; idx < numStrips; idx++)
{
if (indexPixel >= pixelStripStartIdx[idx])
{
stripIdx = idx;
}
else
{
break;
}
}
// subtract strip start index so we're addressing just this strip instead of all pixels on all strips
indexPixel -= pixelStripStartIdx[stripIdx];
switch (_type)
{
case NeoPixelType_Grb:
{
RgbColor c = RgbColor(color.R, color.G, color.B);
switch (stripIdx)
{
case 0: pGrb0->SetPixelColor(indexPixel, c); break;
case 1: pGrb1->SetPixelColor(indexPixel, c); break;
case 2: pGrb2->SetPixelColor(indexPixel, c); break;
case 3: pGrb3->SetPixelColor(indexPixel, c); break;
case 4: pGrb4->SetPixelColor(indexPixel, c); break;
case 5: pGrb5->SetPixelColor(indexPixel, c); break;
case 6: pGrb6->SetPixelColor(indexPixel, c); break;
case 7: pGrb7->SetPixelColor(indexPixel, c); break;
}
break;
}
case NeoPixelType_Grbw:
{
switch (stripIdx)
{
case 0: pGrbw0->SetPixelColor(indexPixel, color); break;
case 1: pGrbw1->SetPixelColor(indexPixel, color); break;
case 2: pGrbw2->SetPixelColor(indexPixel, color); break;
case 3: pGrbw3->SetPixelColor(indexPixel, color); break;
case 4: pGrbw4->SetPixelColor(indexPixel, color); break;
case 5: pGrbw5->SetPixelColor(indexPixel, color); break;
case 6: pGrbw6->SetPixelColor(indexPixel, color); break;
case 7: pGrbw7->SetPixelColor(indexPixel, color); break;
}
break;
}
}
}
void SetBrightness(byte b)
{
switch (_type)
{
case NeoPixelType_Grb:
{
for (uint8_t idx = 0; idx < numStrips; idx++)
{
switch (idx)
{
case 0: pGrb0->SetBrightness(b); break;
case 1: pGrb1->SetBrightness(b); break;
case 2: pGrb2->SetBrightness(b); break;
case 3: pGrb3->SetBrightness(b); break;
case 4: pGrb4->SetBrightness(b); break;
case 5: pGrb5->SetBrightness(b); break;
case 6: pGrb6->SetBrightness(b); break;
case 7: pGrb7->SetBrightness(b); break;
}
}
break;
}
case NeoPixelType_Grbw:
{
for (uint8_t idx = 0; idx < numStrips; idx++)
{
switch (idx)
{
case 0: pGrbw0->SetBrightness(b); break;
case 1: pGrbw1->SetBrightness(b); break;
case 2: pGrbw2->SetBrightness(b); break;
case 3: pGrbw3->SetBrightness(b); break;
case 4: pGrbw4->SetBrightness(b); break;
case 5: pGrbw5->SetBrightness(b); break;
case 6: pGrbw6->SetBrightness(b); break;
case 7: pGrbw7->SetBrightness(b); break;
}
}
break;
}
}
}
// NOTE: Due to feature differences, some support RGBW but the method name
// here needs to be unique, thus GetPixeColorRgbw
RgbwColor GetPixelColorRgbw(uint16_t indexPixel) const
{
// figure out which strip this pixel index is on
uint8_t stripIdx = 0;
for (uint8_t idx = 0; idx < numStrips; idx++)
{
if (indexPixel >= pixelStripStartIdx[idx])
{
stripIdx = idx;
}
else
{
break;
}
}
// subtract strip start index so we're addressing just this strip instead of all pixels on all strips
indexPixel -= pixelStripStartIdx[stripIdx];
switch (_type)
{
case NeoPixelType_Grb:
{
switch (stripIdx)
{
case 0: return pGrb0->GetPixelColor(indexPixel);
case 1: return pGrb1->GetPixelColor(indexPixel);
case 2: return pGrb2->GetPixelColor(indexPixel);
case 3: return pGrb3->GetPixelColor(indexPixel);
case 4: return pGrb4->GetPixelColor(indexPixel);
case 5: return pGrb5->GetPixelColor(indexPixel);
case 6: return pGrb6->GetPixelColor(indexPixel);
case 7: return pGrb7->GetPixelColor(indexPixel);
}
break;
}
case NeoPixelType_Grbw:
switch (stripIdx)
{
case 0: return pGrbw0->GetPixelColor(indexPixel);
case 1: return pGrbw1->GetPixelColor(indexPixel);
case 2: return pGrbw2->GetPixelColor(indexPixel);
case 3: return pGrbw3->GetPixelColor(indexPixel);
case 4: return pGrbw4->GetPixelColor(indexPixel);
case 5: return pGrbw5->GetPixelColor(indexPixel);
case 6: return pGrbw6->GetPixelColor(indexPixel);
case 7: return pGrbw7->GetPixelColor(indexPixel);
}
break;
}
return 0;
}
private:
NeoPixelType _type;
uint16_t pixelStripStartIdx[numStrips];
// pointers for every possible type for up to 8 strips
NeoPixelBrightnessBusGrbRmt0 *pGrb0;
NeoPixelBrightnessBusGrbRmt1 *pGrb1;
NeoPixelBrightnessBusGrbRmt2 *pGrb2;
NeoPixelBrightnessBusGrbRmt3 *pGrb3;
NeoPixelBrightnessBusGrbRmt4 *pGrb4;
NeoPixelBrightnessBusGrbRmt5 *pGrb5;
NeoPixelBrightnessBusGrbRmt6 *pGrb6;
NeoPixelBrightnessBusGrbRmt7 *pGrb7;
NeoPixelBrightnessBusGrbwRmt0 *pGrbw0;
NeoPixelBrightnessBusGrbwRmt1 *pGrbw1;
NeoPixelBrightnessBusGrbwRmt2 *pGrbw2;
NeoPixelBrightnessBusGrbwRmt3 *pGrbw3;
NeoPixelBrightnessBusGrbwRmt4 *pGrbw4;
NeoPixelBrightnessBusGrbwRmt5 *pGrbw5;
NeoPixelBrightnessBusGrbwRmt6 *pGrbw6;
NeoPixelBrightnessBusGrbwRmt7 *pGrbw7;
void cleanup()
{
switch (_type)
{
case NeoPixelType_Grb:
{
for (uint8_t idx = 0; idx < numStrips; idx++)
{
switch (idx)
{
case 0: delete pGrb0; pGrb0 = NULL; break;
case 1: delete pGrb1; pGrb1 = NULL; break;
case 2: delete pGrb2; pGrb2 = NULL; break;
case 3: delete pGrb3; pGrb3 = NULL; break;
case 4: delete pGrb4; pGrb4 = NULL; break;
case 5: delete pGrb5; pGrb5 = NULL; break;
case 6: delete pGrb6; pGrb6 = NULL; break;
case 7: delete pGrb7; pGrb7 = NULL; break;
}
}
break;
}
case NeoPixelType_Grbw:
{
for (uint8_t idx = 0; idx < numStrips; idx++)
{
switch (idx)
{
case 0: delete pGrbw0; pGrbw0 = NULL; break;
case 1: delete pGrbw1; pGrbw1 = NULL; break;
case 2: delete pGrbw2; pGrbw2 = NULL; break;
case 3: delete pGrbw3; pGrbw3 = NULL; break;
case 4: delete pGrbw4; pGrbw4 = NULL; break;
case 5: delete pGrbw5; pGrbw5 = NULL; break;
case 6: delete pGrbw6; pGrbw6 = NULL; break;
case 7: delete pGrbw7; pGrbw7 = NULL; break;
}
}
}
}
}
};
#endif

View File

@@ -0,0 +1,22 @@
# esp32_multistrip
This usermod enables up to 8 data pins to be used from an esp32 module to drive separate LED strands. This only works with one-wire LEDs like the WS2812.
The esp32 RMT hardware is used for data output. See here for hardware driver implementation details: https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
Pass the following variables to the compiler as build flags:
- `ESP32_MULTISTRIP`
- Define this to use usermod NpbWrapper.h instead of default one in WLED.
- `NUM_STRIPS`
- Number of strips in use
- `PIXEL_COUNTS`
- List of pixel counts in each strip
- `DATA_PINS`
- List of data pins each strip is attached to. There may be board-specific restrictions on which pins can be used for RTM.
From the perspective of WLED software, the LEDs are addressed as one long strand. The modified NbpWrapper.h file addresses the appropriate strand from the overall LED index based on the number of LEDs defined in each strand.
See `platformio_override.ini` for example configuration.
Tested on low cost ESP-WROOM-32 dev boards from Amazon, such as those sold by KeeYees.

View File

@@ -0,0 +1,16 @@
; Example platformio_override.ini that shows how to configure your environment to use the multistrip usermod.
; Copy this file to the base wled directory that contains platformio.ini.
; Multistrip requires ESP32 because it has many more pins that can be used as LED outputs.
; Need to define NUM_STRIPS, PIXEL_COUNTS, and DATA_PINS as shown below.
[platformio]
default_envs = esp32_multistrip
[env:esp32_multistrip]
extends=env:esp32dev
build_flags = ${env:esp32dev.build_flags}
-D ESP32_MULTISTRIP ; define this variable to use ESP32_MULTISTRIP usermod
-D NUM_STRIPS=4 ; number of pixel strips in use
-D PIXEL_COUNTS="50, 50, 50, 50" ; number of pixels in each strip
-D DATA_PINS="25, 26, 32, 33" ; esp32 pins used for each pixel strip. available pins depends on esp32 module.

View File

@@ -0,0 +1,94 @@
# MPU-6050 Six-Axis (Gyro + Accelerometer) Driver
This usermod-v2 modification allows the connection of a MPU-6050 IMU sensor to
allow for effects that are controlled by the orientation or motion of the WLED Device.
The MPU6050 has a built in "Digital Motion Processor" which does a lot of the heavy
lifting in integrating the gyro and accel measurements to get potentially more
useful gravity vector and orientation output.
It is pretty straightforward to comment out some of the variables being read off the device if they're not needed to save CPU/Mem/Bandwidth.
_Story:_
As a memento to a long trip I was on, I built an icosahedron globe. I put lights inside to indicate cities I travelled to.
I wanted to integrate an IMU to allow either on-board, or off-board effects that would
react to the globes orientation. See the blog post on building it <https://www.robopenguins.com/icosahedron-travel-globe/> or a video demo <https://youtu.be/zYjybxHBsHM> .
## Adding Dependencies
I2Cdev and MPU6050 must be installed.
To install them, add I2Cdevlib-MPU6050@fbde122cc5 to lib_deps in the platformio.ini file.
You also need to change lib_compat_mode from strict to soft in platformio.ini (This ignores that I2Cdevlib-MPU6050 doesn't list platform compatibility)
For example:
```
lib_compat_mode = soft
lib_deps =
FastLED@3.3.2
NeoPixelBus@2.5.7
ESPAsyncTCP@1.2.0
ESPAsyncUDP@697c75a025
AsyncTCP@1.0.3
Esp Async WebServer@1.2.0
IRremoteESP8266@2.7.3
I2Cdevlib-MPU6050@fbde122cc5
```
## Wiring
The connections needed to the MPU6050 are as follows:
```
VCC VU (5V USB) Not available on all boards so use 3.3V if needed.
GND G Ground
SCL D1 (GPIO05) I2C clock
SDA D2 (GPIO04) I2C data
XDA not connected
XCL not connected
AD0 not connected
INT D8 (GPIO15) Interrupt pin
```
You could probably modify the code not to need an interrupt, but I used the
setup directly from the example.
## JSON API
This code adds:
```json
"u":{
"IMU":{
"Quat": [w, x, y, z],
"Euler": [psi, theta, phi],
"Gyro": [x, y, z],
"Accel": [x, y, z],
"RealAccel": [x, y, z],
"WorldAccel": [x, y, z],
"Gravity": [x, y, z],
"Orientation": [yaw, pitch, roll]
}
}
```
to the info object
## Usermod installation
1. Copy the file `usermod_mpu6050_imu.h` to the `wled00` directory.
2. Register the usermod by adding `#include "usermod_mpu6050_imu.h.h"` in the top and `registerUsermod(new MPU6050Driver());` in the bottom of `usermods_list.cpp`.
Example **usermods_list.cpp**:
```cpp
#include "wled.h"
#include "usermod_mpu6050_imu.h"
void registerUsermods()
{
usermods.add(new MPU6050Driver());
}
```

View File

@@ -0,0 +1,274 @@
#pragma once
#include "wled.h"
/* This driver reads quaternion data from the MPU6060 and adds it to the JSON
This example is adapted from:
https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/MPU6050/examples/MPU6050_DMP6_ESPWiFi
Tested with a d1 mini esp-12f
GY-521 NodeMCU
MPU6050 devkit 1.0
board Lolin Description
======= ========== ====================================================
VCC VU (5V USB) Not available on all boards so use 3.3V if needed.
GND G Ground
SCL D1 (GPIO05) I2C clock
SDA D2 (GPIO04) I2C data
XDA not connected
XCL not connected
AD0 not connected
INT D8 (GPIO15) Interrupt pin
Using usermod:
1. Copy the usermod into the sketch folder (same folder as wled00.ino)
2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
3. I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h file
for both classes must be in the include path of your project. To install the
libraries add I2Cdevlib-MPU6050@fbde122cc5 to lib_deps in the platformio.ini file.
4. You also need to change lib_compat_mode from strict to soft in platformio.ini (This ignores that I2Cdevlib-MPU6050 doesn't list platform compatibility)
5. Wire up the MPU6050 as detailed above.
*/
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
// ================================================================
// === INTERRUPT DETECTION ROUTINE ===
// ================================================================
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void IRAM_ATTR dmpDataReady() {
mpuInterrupt = true;
}
class MPU6050Driver : public Usermod {
private:
MPU6050 mpu;
// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
//NOTE: some of these can be removed to save memory, processing time
// if the measurement isn't needed
Quaternion qat; // [w, x, y, z] quaternion container
float euler[3]; // [psi, theta, phi] Euler angle container
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container
VectorInt16 aa; // [x, y, z] accel sensor measurements
VectorInt16 gy; // [x, y, z] gyro sensor measurements
VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
VectorFloat gravity; // [x, y, z] gravity vector
static const int INTERRUPT_PIN = 15; // use pin 15 on ESP8266
public:
//Functions called by WLED
/*
* setup() is called once at boot. WiFi is not yet connected at this point.
*/
void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
// initialize device
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
// make sure it worked (returns 0 if so)
if (devStatus == 0) {
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
}
/*
* connected() is called every time the WiFi is (re)connected
* Use it to initialize network interfaces
*/
void connected() {
//Serial.println("Connected to WiFi!");
}
/*
* loop() is called continuously. Here you can check for events, read sensors, etc.
*/
void loop() {
// if programming failed, don't try to do anything
if (!dmpReady) return;
// wait for MPU interrupt or extra packet(s) available
if (!mpuInterrupt && fifoCount < packetSize) return;
// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
// get current FIFO count
fifoCount = mpu.getFIFOCount();
// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
// reset so we can continue cleanly
mpu.resetFIFO();
Serial.println(F("FIFO overflow!"));
// otherwise, check for DMP data ready interrupt (this should happen frequently)
} else if (mpuIntStatus & 0x02) {
// wait for correct available data length, should be a VERY short wait
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
// read a packet from FIFO
mpu.getFIFOBytes(fifoBuffer, packetSize);
// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;
//NOTE: some of these can be removed to save memory, processing time
// if the measurement isn't needed
mpu.dmpGetQuaternion(&qat, fifoBuffer);
mpu.dmpGetEuler(euler, &qat);
mpu.dmpGetGravity(&gravity, &qat);
mpu.dmpGetGyro(&gy, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &qat);
mpu.dmpGetYawPitchRoll(ypr, &qat, &gravity);
}
}
void addToJsonInfo(JsonObject& root)
{
int reading = 20;
//this code adds "u":{"Light":[20," lux"]} to the info object
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray imu_meas = user.createNestedObject("IMU");
JsonArray quat_json = imu_meas.createNestedArray("Quat");
quat_json.add(qat.w);
quat_json.add(qat.x);
quat_json.add(qat.y);
quat_json.add(qat.z);
JsonArray euler_json = imu_meas.createNestedArray("Euler");
euler_json.add(euler[0]);
euler_json.add(euler[1]);
euler_json.add(euler[2]);
JsonArray accel_json = imu_meas.createNestedArray("Accel");
accel_json.add(aa.x);
accel_json.add(aa.y);
accel_json.add(aa.z);
JsonArray gyro_json = imu_meas.createNestedArray("Gyro");
gyro_json.add(gy.x);
gyro_json.add(gy.y);
gyro_json.add(gy.z);
JsonArray world_json = imu_meas.createNestedArray("WorldAccel");
world_json.add(aaWorld.x);
world_json.add(aaWorld.y);
world_json.add(aaWorld.z);
JsonArray real_json = imu_meas.createNestedArray("RealAccel");
real_json.add(aaReal.x);
real_json.add(aaReal.y);
real_json.add(aaReal.z);
JsonArray grav_json = imu_meas.createNestedArray("Gravity");
grav_json.add(gravity.x);
grav_json.add(gravity.y);
grav_json.add(gravity.z);
JsonArray orient_json = imu_meas.createNestedArray("Orientation");
orient_json.add(ypr[0]);
orient_json.add(ypr[1]);
orient_json.add(ypr[2]);
}
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void addToJsonState(JsonObject& root)
{
//root["user0"] = userVar0;
}
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void readFromJsonState(JsonObject& root)
{
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
}
/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
*/
uint16_t getId()
{
return USERMOD_ID_IMU;
}
};

View File

@@ -0,0 +1,50 @@
# MQTT controllable switches
This usermod allows controlling switches (e.g. relays) via MQTT.
## Usermod installation
1. Copy the file `usermod_mqtt_switch.h` to the `wled00` directory.
2. Register the usermod by adding `#include "usermod_mqtt_switch.h"` in the top and `registerUsermod(new UsermodMqttSwitch());` in the bottom of `usermods_list.cpp`.
Example `usermods_list.cpp`:
```
#include "wled.h"
#include "usermod_mqtt_switch.h"
void registerUsermods()
{
usermods.add(new UsermodMqttSwitch());
}
```
## Define pins
Add a define for MQTTSWITCHPINS to platformio_override.ini.
The following example defines 3 switches connected to the GPIO pins 13, 5 and 2:
```
[env:livingroom]
board = esp12e
platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266}
-D LEDPIN=3
-D BTNPIN=4
-D RLYPIN=12
-D RLYMDE=1
-D STATUSPIN=15
-D MQTTSWITCHPINS="13, 5, 2"
```
Pins can be inverted by setting `MQTTSWITCHINVERT`. For example `-D MQTTSWITCHINVERT="false, false, true"` would invert the switch on pin 2 in the previous example.
The default state after booting before any MQTT message can be set by `MQTTSWITCHDEFAULTS`. For example `-D MQTTSWITCHDEFAULTS="ON, OFF, OFF"` would power on the switch on pin 13 and power off switches on pins 5 and 2.
## MQTT topics
This usermod listens on `[mqttDeviceTopic]/switch/0/set` (where 0 is replaced with the index of the switch) for commands. Anything starting with `ON` turns on the switch, everything else turns it off.
Feedback about the current state is provided at `[mqttDeviceTopic]/switch/0/state`.
### Home Assistant auto-discovery
Auto-discovery information is automatically published and you shoudn't have to do anything to register the switches in Home Assistant.

View File

@@ -0,0 +1,157 @@
#pragma once
#include "wled.h"
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#ifndef MQTTSWITCHPINS
#error "Please define MQTTSWITCHPINS in platformio_override.ini. e.g. -D MQTTSWITCHPINS="12, 0, 2" "
// The following define helps Eclipse's C++ parser but is never used in production due to the #error statement on the line before
#define MQTTSWITCHPINS 12, 0, 2
#endif
// Default behavior: All outputs active high
#ifndef MQTTSWITCHINVERT
#define MQTTSWITCHINVERT
#endif
// Default behavior: All outputs off
#ifndef MQTTSWITCHDEFAULTS
#define MQTTSWITCHDEFAULTS
#endif
static const uint8_t switchPins[] = { MQTTSWITCHPINS };
//This is a hack to get the number of pins defined by the user
#define NUM_SWITCH_PINS (sizeof(switchPins))
static const bool switchInvert[NUM_SWITCH_PINS] = { MQTTSWITCHINVERT};
//Make settings in config file more readable
#define ON 1
#define OFF 0
static const bool switchDefaults[NUM_SWITCH_PINS] = { MQTTSWITCHDEFAULTS};
#undef ON
#undef OFF
class UsermodMqttSwitch: public Usermod
{
private:
bool mqttInitialized;
bool switchState[NUM_SWITCH_PINS];
public:
UsermodMqttSwitch() :
mqttInitialized(false)
{
}
void setup()
{
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
setState(pinNr, switchDefaults[pinNr]);
pinMode(switchPins[pinNr], OUTPUT);
}
}
void loop()
{
if (!mqttInitialized) {
mqttInit();
return; // Try again in next loop iteration
}
}
void mqttInit()
{
if (!mqtt)
return;
mqtt->onMessage(
std::bind(&UsermodMqttSwitch::onMqttMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4,
std::placeholders::_5, std::placeholders::_6));
mqtt->onConnect(std::bind(&UsermodMqttSwitch::onMqttConnect, this, std::placeholders::_1));
mqttInitialized = true;
}
void onMqttConnect(bool sessionPresent);
void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total);
void updateState(uint8_t pinNr);
void setState(uint8_t pinNr, bool active)
{
if (pinNr > NUM_SWITCH_PINS)
return;
switchState[pinNr] = active;
digitalWrite((char) switchPins[pinNr], (char) (switchInvert[pinNr] ? !active : active));
updateState(pinNr);
}
};
inline void UsermodMqttSwitch::onMqttConnect(bool sessionPresent)
{
if (mqttDeviceTopic[0] == 0)
return;
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
char buf[128];
StaticJsonDocument<1024> json;
sprintf(buf, "%s Switch %d", serverDescription, pinNr + 1);
json[F("name")] = buf;
sprintf(buf, "%s/switch/%d", mqttDeviceTopic, pinNr);
json["~"] = buf;
strcat(buf, "/set");
mqtt->subscribe(buf, 0);
json[F("stat_t")] = "~/state";
json[F("cmd_t")] = "~/set";
json[F("pl_off")] = F("OFF");
json[F("pl_on")] = F("ON");
char uid[16];
sprintf(uid, "%s_sw%d", escapedMac.c_str(), pinNr);
json[F("unique_id")] = uid;
strcpy(buf, mqttDeviceTopic);
strcat(buf, "/status");
json[F("avty_t")] = buf;
json[F("pl_avail")] = F("online");
json[F("pl_not_avail")] = F("offline");
//TODO: dev
sprintf(buf, "homeassistant/switch/%s/config", uid);
char json_str[1024];
size_t payload_size = serializeJson(json, json_str);
mqtt->publish(buf, 0, true, json_str, payload_size);
updateState(pinNr);
}
}
inline void UsermodMqttSwitch::onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)
{
//Note: Payload is not necessarily null terminated. Check "len" instead.
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
char buf[64];
sprintf(buf, "%s/switch/%d/set", mqttDeviceTopic, pinNr);
if (strcmp(topic, buf) == 0) {
//Any string starting with "ON" is interpreted as ON, everything else as OFF
setState(pinNr, len >= 2 && payload[0] == 'O' && payload[1] == 'N');
break;
}
}
}
inline void UsermodMqttSwitch::updateState(uint8_t pinNr)
{
if (!mqttInitialized)
return;
if (pinNr > NUM_SWITCH_PINS)
return;
char buf[64];
sprintf(buf, "%s/switch/%d/state", mqttDeviceTopic, pinNr);
if (switchState[pinNr]) {
mqtt->publish(buf, 0, false, "ON");
} else {
mqtt->publish(buf, 0, false, "OFF");
}
}

View File

@@ -0,0 +1,11 @@
# Photoresister sensor with MQTT
This simple usermod allows attaching a photoresistor sensor like the KY-018 and publish the readings in percentage over MQTT. The frequency of MQTT messages can be modified, and there is a threshold value that can be set so that significant changes in the readings can be published immediately instead of waiting for the next update. This was found to be a good compromise between spamming MQTT messages and delayed updates.
I also found it useful to limit the frequency of analog pin reads because otherwise the board hangs.
This usermod has only been tested with the KY-018 sensor though should work for any other analog pin sensor. Note that this does not control the LED strip directly, it only publishes MQTT readings for use with other integrations like Home Assistant.
## Installation
Copy and replace the file `usermod.cpp` in wled00 directory.

View File

@@ -0,0 +1,70 @@
#include "wled.h"
/*
* This v1 usermod file allows you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
* If you just need 8 bytes, use 2551-2559 (you do not need to increase EEPSIZE)
*
* Consider the v2 usermod API if you need a more advanced feature set!
*/
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
const int LIGHT_PIN = A0; // define analog pin
const long UPDATE_MS = 30000; // Upper threshold between mqtt messages
const char MQTT_TOPIC[] = "/light"; // MQTT topic for sensor values
const int CHANGE_THRESHOLD = 5; // Change threshold in percentage to send before UPDATE_MS
// variables
long lastTime = 0;
long timeDiff = 0;
long readTime = 0;
int lightValue = 0;
float lightPercentage = 0;
float lastPercentage = 0;
//gets called once at boot. Do all initialization that doesn't depend on network here
void userSetup()
{
pinMode(LIGHT_PIN, INPUT);
}
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
void userConnected()
{
}
void publishMqtt(float state)
{
//Check if MQTT Connected, otherwise it will crash the 8266
if (mqtt != nullptr){
char subuf[38];
strcpy(subuf, mqttDeviceTopic);
strcat(subuf, MQTT_TOPIC);
mqtt->publish(subuf, 0, true, String(state).c_str());
}
}
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
void userLoop()
{
// Read only every 500ms, otherwise it causes the board to hang
if (millis() - readTime > 500)
{
readTime = millis();
timeDiff = millis() - lastTime;
// Convert value to percentage
lightValue = analogRead(LIGHT_PIN);
lightPercentage = ((float)lightValue * -1 + 1024)/(float)1024 *100;
// Send MQTT message on significant change or after UPDATE_MS
if (abs(lightPercentage - lastPercentage) > CHANGE_THRESHOLD || timeDiff > UPDATE_MS)
{
publishMqtt(lightPercentage);
lastTime = millis();
lastPercentage = lightPercentage;
}
}
}

View File

@@ -18,25 +18,6 @@ u16 PCARS_maxRPM;
long PCARS_lastRead = millis() - 2001;
float PCARS_rpmRatio;
void userSetup()
{
UDP.begin(PCARS_localUdpPort);
}
void userConnected()
{
// new wifi, who dis?
}
void userLoop()
{
PCARS_readValues();
if (PCARS_lastRead > millis() - 2000) {
PCARS_buildcolorbars();
}
}
void PCARS_readValues() {
int PCARS_packetSize = UDP.parsePacket();
@@ -48,7 +29,7 @@ void PCARS_readValues() {
if (len == 1367) { // Telemetry packet. Ignoring everything else.
PCARS_lastRead = millis();
arlsLock(realtimeTimeoutMs, REALTIME_MODE_GENERIC);
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_GENERIC);
// current RPM
memcpy(&PCARS_tempChar, &PCARS_packet[124], 2);
PCARS_RPM = (PCARS_tempChar[1] << 8) + PCARS_tempChar[0];
@@ -93,4 +74,22 @@ void PCARS_buildcolorbars() {
}
colorUpdated(5);
strip.show();
}
void userSetup()
{
UDP.begin(PCARS_localUdpPort);
}
void userConnected()
{
// new wifi, who dis?
}
void userLoop()
{
PCARS_readValues();
if (PCARS_lastRead > millis() - 2000) {
PCARS_buildcolorbars();
}
}

View File

@@ -7,7 +7,7 @@ If you have created an usermod that you believe is useful (for example to suppor
In order for other people to be able to have fun with your usermod, please keep these points in mind:
- Create a folder in this folder with a descriptive name (for example `usermod_ds18b20_temp_sensor_mqtt`)
- Include your custom `usermod.cpp` file
- Include your custom files
- If your usermod requires changes to other WLED files, please write a `readme.md` outlining the steps one has to take to use the usermod
- Create a pull request!
- If your feature is useful for the majority of WLED users, I will consider adding it to the base code!
@@ -15,4 +15,7 @@ In order for other people to be able to have fun with your usermod, please keep
While I do my best to not break too much, keep in mind that as WLED is being updated, usermods might break.
I am not actively maintaining any usermod in this directory, that is your responsibility as the creator of the usermod.
For new usermods, I would recommend trying out the new v2 usermod API, which allows installing multiple usermods at once and new functions!
You can take a look at `EXAMPLE_v2` for some documentation and at `Temperature` for a completed v2 usermod!
Thank you for your help :)

View File

@@ -0,0 +1,211 @@
#pragma once
#include "wled.h"
//v2 usermod that allows to change brightness and color using a rotary encoder,
//change between modes by pressing a button (many encoder have one included)
class RotaryEncoderSet : public Usermod
{
private:
//Private class members. You can declare variables and functions only accessible to your usermod here
unsigned long lastTime = 0;
/*
** Rotary Encoder Example
** Use the Sparkfun Rotary Encoder to vary brightness of LED
**
** Sample the encoder at 500Hz using the millis() function
*/
int fadeAmount = 5; // how many points to fade the Neopixel with each step
unsigned long currentTime;
unsigned long loopTime;
const int pinA = 5; // DT from encoder
const int pinB = 18; // CLK from encoder
const int pinC = 23; // SW from encoder
unsigned char select_state = 0; // 0 = brightness 1 = color
unsigned char button_state = HIGH;
unsigned char prev_button_state = HIGH;
CRGB fastled_col;
CHSV prim_hsv;
int16_t new_val;
unsigned char Enc_A;
unsigned char Enc_B;
unsigned char Enc_A_prev = 0;
public:
//Functions called by WLED
/*
* setup() is called once at boot. WiFi is not yet connected at this point.
* You can use it to initialize variables, sensors or similar.
*/
void setup()
{
//Serial.println("Hello from my usermod!");
pinMode(pinA, INPUT_PULLUP);
pinMode(pinB, INPUT_PULLUP);
pinMode(pinC, INPUT_PULLUP);
currentTime = millis();
loopTime = currentTime;
}
/*
* connected() is called every time the WiFi is (re)connected
* Use it to initialize network interfaces
*/
void connected()
{
//Serial.println("Connected to WiFi!");
}
/*
* loop() is called continuously. Here you can check for events, read sensors, etc.
*
* Tips:
* 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection.
* Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker.
*
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
* Instead, use a timer check as shown here.
*/
void loop()
{
currentTime = millis(); // get the current elapsed time
if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz
{
button_state = digitalRead(pinC);
if (prev_button_state != button_state)
{
if (button_state == LOW)
{
if (select_state == 1)
{
select_state = 0;
}
else
{
select_state = 1;
}
prev_button_state = button_state;
}
else
{
prev_button_state = button_state;
}
}
int Enc_A = digitalRead(pinA); // Read encoder pins
int Enc_B = digitalRead(pinB);
if ((!Enc_A) && (Enc_A_prev))
{ // A has gone from high to low
if (Enc_B == HIGH)
{ // B is high so clockwise
if (select_state == 0)
{
if (bri + fadeAmount <= 255)
bri += fadeAmount; // increase the brightness, dont go over 255
}
else
{
fastled_col.red = col[0];
fastled_col.green = col[1];
fastled_col.blue = col[2];
prim_hsv = rgb2hsv_approximate(fastled_col);
new_val = (int16_t)prim_hsv.h + fadeAmount;
if (new_val > 255)
new_val -= 255; // roll-over if bigger than 255
if (new_val < 0)
new_val += 255; // roll-over if smaller than 0
prim_hsv.h = (byte)new_val;
hsv2rgb_rainbow(prim_hsv, fastled_col);
col[0] = fastled_col.red;
col[1] = fastled_col.green;
col[2] = fastled_col.blue;
}
}
else if (Enc_B == LOW)
{ // B is low so counter-clockwise
if (select_state == 0)
{
if (bri - fadeAmount >= 0)
bri -= fadeAmount; // decrease the brightness, dont go below 0
}
else
{
fastled_col.red = col[0];
fastled_col.green = col[1];
fastled_col.blue = col[2];
prim_hsv = rgb2hsv_approximate(fastled_col);
new_val = (int16_t)prim_hsv.h - fadeAmount;
if (new_val > 255)
new_val -= 255; // roll-over if bigger than 255
if (new_val < 0)
new_val += 255; // roll-over if smaller than 0
prim_hsv.h = (byte)new_val;
hsv2rgb_rainbow(prim_hsv, fastled_col);
col[0] = fastled_col.red;
col[1] = fastled_col.green;
col[2] = fastled_col.blue;
}
}
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
updateInterfaces()
}
Enc_A_prev = Enc_A; // Store value of A for next time
loopTime = currentTime; // Updates loopTime
}
}
/*
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
* Below it is shown how this could be used for e.g. a light sensor
*/
/*
void addToJsonInfo(JsonObject& root)
{
int reading = 20;
//this code adds "u":{"Light":[20," lux"]} to the info object
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray lightArr = user.createNestedArray("Light"); //name
lightArr.add(reading); //value
lightArr.add(" lux"); //unit
}
*/
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void addToJsonState(JsonObject &root)
{
//root["user0"] = userVar0;
}
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void readFromJsonState(JsonObject &root)
{
userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
}
/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
* This could be used in the future for the system to determine whether your usermod is installed.
*/
uint16_t getId()
{
return 0xABCD;
}
//More methods can be added in the future, this example will then be extended.
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
};

View File

@@ -0,0 +1,136 @@
#include "wled.h"
/*
* Usermods allow you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
*
* This is Stairway-Wipe as a v2 usermod.
*
* Using this usermod:
* 1. Copy the usermod into the sketch folder (same folder as wled00.ino)
* 2. Register the usermod by adding #include "stairway-wipe-usermod-v2.h" in the top and registerUsermod(new StairwayWipeUsermod()) in the bottom of usermods_list.cpp
*/
class StairwayWipeUsermod : public Usermod {
private:
//Private class members. You can declare variables and functions only accessible to your usermod here
unsigned long lastTime = 0;
byte wipeState = 0; //0: inactive 1: wiping 2: solid
unsigned long timeStaticStart = 0;
uint16_t previousUserVar0 = 0;
//comment this out if you want the turn off effect to be just fading out instead of reverse wipe
#define STAIRCASE_WIPE_OFF
public:
void loop() {
//userVar0 (U0 in HTTP API):
//has to be set to 1 if movement is detected on the PIR that is the same side of the staircase as the ESP8266
//has to be set to 2 if movement is detected on the PIR that is the opposite side
//can be set to 0 if no movement is detected. Otherwise LEDs will turn off after a configurable timeout (userVar1 seconds)
if (userVar0 > 0)
{
if ((previousUserVar0 == 1 && userVar0 == 2) || (previousUserVar0 == 2 && userVar0 == 1)) wipeState = 3; //turn off if other PIR triggered
previousUserVar0 = userVar0;
if (wipeState == 0) {
startWipe();
wipeState = 1;
} else if (wipeState == 1) { //wiping
uint32_t cycleTime = 360 + (255 - effectSpeed)*75; //this is how long one wipe takes (minus 25 ms to make sure we switch in time)
if (millis() + strip.timebase > (cycleTime - 25)) { //wipe complete
effectCurrent = FX_MODE_STATIC;
timeStaticStart = millis();
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
wipeState = 2;
}
} else if (wipeState == 2) { //static
if (userVar1 > 0) //if U1 is not set, the light will stay on until second PIR or external command is triggered
{
if (millis() - timeStaticStart > userVar1*1000) wipeState = 3;
}
} else if (wipeState == 3) { //switch to wipe off
#ifdef STAIRCASE_WIPE_OFF
effectCurrent = FX_MODE_COLOR_WIPE;
strip.timebase = 360 + (255 - effectSpeed)*75 - millis(); //make sure wipe starts fully lit
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
wipeState = 4;
#else
turnOff();
#endif
} else { //wiping off
if (millis() + strip.timebase > (725 + (255 - effectSpeed)*150)) turnOff(); //wipe complete
}
} else {
wipeState = 0; //reset for next time
if (previousUserVar0) {
#ifdef STAIRCASE_WIPE_OFF
userVar0 = previousUserVar0;
wipeState = 3;
#else
turnOff();
#endif
}
previousUserVar0 = 0;
}
}
void readFromJsonState(JsonObject& root)
{
userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
}
void addToConfig(JsonObject& root)
{
JsonObject top = root.createNestedObject("exampleUsermod");
top["great"] = userVar0; //save this var persistently whenever settings are saved
}
void readFromConfig(JsonObject& root)
{
JsonObject top = root["top"];
userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot)
}
uint16_t getId()
{
return USERMOD_ID_EXAMPLE;
}
void startWipe()
{
bri = briLast; //turn on
transitionDelayTemp = 0; //no transition
effectCurrent = FX_MODE_COLOR_WIPE;
resetTimebase(); //make sure wipe starts from beginning
//set wipe direction
WS2812FX::Segment& seg = strip.getSegment(0);
bool doReverse = (userVar0 == 2);
seg.setOption(1, doReverse);
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
}
void turnOff()
{
#ifdef STAIRCASE_WIPE_OFF
transitionDelayTemp = 0; //turn off immediately after wipe completed
#else
transitionDelayTemp = 4000; //fade out slowly
#endif
bri = 0;
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
wipeState = 0;
userVar0 = 0;
previousUserVar0 = 0;
}
//More methods can be added in the future, this example will then be extended.
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
};

Binary file not shown.

View File

@@ -0,0 +1,6 @@
## Word clock usermod
By @bwente
See https://www.hackster.io/bwente/word-clock-with-just-two-components-073834 for the hardware guide!
Includes a customizable feature to lower the brightness at night.

View File

@@ -0,0 +1,846 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="288px" height="288px" viewBox="0 0 288 288" style="enable-background:new 0 0 288 288;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#E82429;stroke-miterlimit:10;}
.st1{fill:none;stroke:#E82429;stroke-width:0.9999;stroke-miterlimit:10;}
.st2{fill:#231F20;}
.st3{fill:none;stroke:#231F20;stroke-miterlimit:10;}
</style>
<g>
<g>
<rect x="55.888" y="99.803" class="st0" width="41.1" height="19"/>
<polygon class="st0" points="101.188,142.003 119.688,142.003 119.688,123.003 101.188,123.003 96.988,123.003 55.888,123.003
55.888,142.003 96.988,142.003 "/>
<rect x="123.888" y="146.303" class="st0" width="41.1" height="19"/>
<rect x="55.888" y="192.803" class="st0" width="41.1" height="19"/>
<rect x="123.888" y="169.503" class="st0" width="41.1" height="19"/>
<polygon class="st0" points="169.288,118.803 187.688,118.803 187.688,99.803 146.588,99.803 142.288,99.803 101.188,99.803
101.188,118.803 119.688,118.803 123.888,118.803 164.988,118.803 "/>
<polygon class="st0" points="74.388,146.303 55.888,146.303 55.888,165.303 119.688,165.303 119.688,146.303 78.588,146.303 "/>
<rect x="123.888" y="123.003" class="st0" width="41.1" height="19"/>
<polygon class="st0" points="101.188,95.603 142.288,95.603 142.288,76.603 101.188,76.603 96.988,76.603 55.888,76.603
55.888,95.603 96.988,95.603 "/>
<polygon class="st0" points="96.988,216.003 55.888,216.003 55.888,235.003 142.288,235.003 142.288,216.003 101.188,216.003
"/>
<rect x="55.888" y="53.303" class="st0" width="41.1" height="19"/>
<polygon class="st0" points="187.688,76.603 146.588,76.603 146.588,95.603 187.688,95.603 191.888,95.603 232.988,95.603
232.988,76.603 191.888,76.603 "/>
<rect x="191.988" y="192.803" class="st0" width="41.1" height="19"/>
<polygon class="st0" points="146.588,72.303 187.688,72.303 187.688,53.303 101.188,53.303 101.188,72.303 142.288,72.303 "/>
<rect x="191.888" y="99.803" class="st0" width="41.1" height="19"/>
<rect x="191.888" y="53.303" class="st0" width="41.1" height="19"/>
<polygon class="st0" points="187.688,123.003 169.288,123.003 169.288,142.003 232.988,142.003 232.988,123.003 191.888,123.003
"/>
<rect x="146.588" y="216.003" class="st0" width="86.5" height="19"/>
<polygon class="st0" points="119.688,188.503 119.688,169.503 55.888,169.503 55.888,188.503 96.988,188.503 101.288,188.503
"/>
<rect x="169.288" y="146.303" class="st0" width="63.8" height="19"/>
<polygon class="st0" points="119.588,192.803 101.188,192.803 101.188,211.803 187.588,211.803 187.588,192.803 123.888,192.803
"/>
<rect x="169.288" y="169.503" class="st0" width="63.8" height="19"/>
</g>
<rect x="31.102" y="30.767" class="st1" width="226.772" height="226.772"/>
</g>
<g>
<path class="st2" d="M62.154,59.463c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624v6.672
c0,0.191-0.006,0.332-0.018,0.42c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612V59.463z"/>
<path class="st2" d="M67.014,58.395h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414v-6.024h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C66.546,58.431,66.75,58.395,67.014,58.395z"/>
<path class="st2" d="M80.646,59.463c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624v6.672
c0,0.191-0.006,0.332-0.018,0.42c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612V59.463z"/>
<path class="st2" d="M85.061,65.967c-0.208-0.256-0.312-0.485-0.312-0.689s0.172-0.475,0.516-0.811
c0.2-0.191,0.412-0.288,0.636-0.288c0.224,0,0.536,0.2,0.936,0.601c0.112,0.136,0.271,0.266,0.48,0.39
c0.208,0.124,0.4,0.187,0.576,0.187c0.744,0,1.116-0.305,1.116-0.912c0-0.185-0.102-0.338-0.306-0.462
c-0.204-0.124-0.458-0.214-0.762-0.271c-0.304-0.056-0.632-0.146-0.984-0.27s-0.68-0.271-0.984-0.438s-0.558-0.434-0.762-0.798
c-0.204-0.364-0.306-0.802-0.306-1.313c0-0.704,0.262-1.318,0.786-1.843c0.524-0.523,1.238-0.786,2.142-0.786
c0.48,0,0.918,0.062,1.314,0.187c0.396,0.124,0.67,0.25,0.822,0.378l0.3,0.228c0.248,0.232,0.372,0.429,0.372,0.589
s-0.096,0.38-0.288,0.659c-0.272,0.4-0.552,0.601-0.84,0.601c-0.168,0-0.376-0.08-0.624-0.24c-0.024-0.016-0.07-0.056-0.138-0.12
c-0.068-0.063-0.13-0.115-0.186-0.156c-0.168-0.104-0.382-0.155-0.642-0.155c-0.26,0-0.476,0.062-0.648,0.186
c-0.172,0.124-0.258,0.296-0.258,0.517c0,0.22,0.102,0.397,0.306,0.533c0.204,0.137,0.458,0.229,0.762,0.276
c0.304,0.048,0.636,0.122,0.996,0.222c0.36,0.101,0.692,0.223,0.996,0.366c0.304,0.145,0.558,0.395,0.762,0.75
c0.204,0.356,0.306,0.794,0.306,1.314c0,0.52-0.104,0.978-0.312,1.374c-0.208,0.396-0.48,0.701-0.816,0.918
c-0.648,0.424-1.34,0.636-2.076,0.636c-0.376,0-0.732-0.046-1.068-0.138c-0.336-0.093-0.608-0.206-0.816-0.343
c-0.424-0.256-0.72-0.504-0.888-0.743L85.061,65.967z"/>
</g>
<g>
<path class="st2" d="M132.579,58.659c0.064-0.12,0.172-0.204,0.324-0.252c0.152-0.049,0.344-0.072,0.576-0.072
s0.416,0.02,0.552,0.06c0.136,0.04,0.24,0.089,0.312,0.145c0.072,0.056,0.128,0.136,0.168,0.24c0.04,0.136,0.06,0.344,0.06,0.624
v6.659c0,0.185-0.006,0.322-0.018,0.414c-0.012,0.093-0.05,0.198-0.114,0.318c-0.112,0.216-0.424,0.324-0.936,0.324
c-0.56,0-0.888-0.148-0.984-0.444c-0.048-0.136-0.072-0.344-0.072-0.624v-2.436h-3.18v2.447c0,0.185-0.006,0.322-0.018,0.414
c-0.012,0.093-0.05,0.198-0.114,0.318c-0.112,0.216-0.424,0.324-0.936,0.324c-0.56,0-0.888-0.148-0.984-0.444
c-0.048-0.136-0.072-0.344-0.072-0.624v-6.66c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624v2.447h3.18v-2.46
c0-0.184,0.006-0.321,0.018-0.414C132.477,58.885,132.515,58.779,132.579,58.659z"/>
<path class="st2" d="M141.807,58.959l3.24,6.696c0.136,0.271,0.204,0.476,0.204,0.611c0,0.288-0.232,0.548-0.696,0.78
c-0.272,0.136-0.486,0.204-0.642,0.204c-0.156,0-0.284-0.036-0.384-0.108c-0.1-0.071-0.172-0.147-0.216-0.228
s-0.106-0.2-0.186-0.36l-0.624-1.296h-3.324l-0.624,1.296c-0.08,0.16-0.142,0.276-0.186,0.349
c-0.044,0.071-0.116,0.146-0.216,0.222s-0.228,0.114-0.384,0.114c-0.156,0-0.37-0.068-0.642-0.204
c-0.464-0.225-0.696-0.48-0.696-0.769c0-0.136,0.068-0.34,0.204-0.611l3.24-6.708c0.088-0.185,0.222-0.332,0.402-0.444
c0.18-0.112,0.37-0.168,0.57-0.168C141.279,58.335,141.598,58.543,141.807,58.959z M140.835,61.839l-0.792,1.644h1.596
L140.835,61.839z"/>
<path class="st2" d="M149.235,65.354h3.264c0.264,0,0.456,0.03,0.576,0.091c0.12,0.06,0.2,0.153,0.24,0.281s0.06,0.299,0.06,0.511
s-0.02,0.382-0.06,0.51s-0.108,0.216-0.204,0.264c-0.152,0.08-0.36,0.12-0.624,0.12h-4.32c-0.56,0-0.888-0.152-0.984-0.456
c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624V65.354z"/>
<path class="st2" d="M161.175,58.335c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.196,0.051,0.312,0.114
c0.116,0.064,0.198,0.172,0.246,0.324s0.072,0.355,0.072,0.612c0,0.256-0.024,0.46-0.072,0.611
c-0.048,0.152-0.132,0.258-0.252,0.318c-0.12,0.06-0.226,0.096-0.318,0.107c-0.092,0.013-0.234,0.019-0.426,0.019h-3.672v1.212
h2.364c0.192,0,0.334,0.006,0.426,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.208,0.12,0.312,0.437,0.312,0.948
c0,0.56-0.152,0.892-0.456,0.996c-0.128,0.04-0.332,0.06-0.612,0.06h-2.352v2.269c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.56,0-0.888-0.152-0.984-0.456
c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834c0.152-0.147,0.44-0.222,0.864-0.222H161.175z"/>
</g>
<g>
<path class="st2" d="M200.185,58.389h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414v-6.024h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C199.716,58.424,199.921,58.389,200.185,58.389z"/>
<path class="st2" d="M211.704,65.073h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V65.073z"/>
<path class="st2" d="M224.118,58.767c0.076-0.141,0.19-0.234,0.342-0.282s0.342-0.072,0.57-0.072c0.228,0,0.412,0.021,0.552,0.061
s0.244,0.088,0.312,0.144s0.118,0.141,0.15,0.252c0.048,0.128,0.072,0.332,0.072,0.612v6.66c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.312,0-0.528-0.024-0.648-0.072
c-0.12-0.048-0.22-0.124-0.3-0.228c-1.8-2.4-2.984-3.968-3.552-4.704v3.948c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.496,0-0.8-0.108-0.912-0.324
c-0.064-0.12-0.102-0.228-0.114-0.324c-0.012-0.096-0.018-0.235-0.018-0.42v-6.695c0-0.305,0.038-0.526,0.114-0.666
c0.076-0.141,0.19-0.234,0.342-0.282s0.348-0.072,0.588-0.072c0.24,0,0.43,0.022,0.57,0.066c0.14,0.044,0.238,0.094,0.294,0.149
c0.032,0.024,0.124,0.129,0.276,0.312c1.688,2.296,2.816,3.812,3.384,4.548v-4.056C224.004,59.128,224.042,58.907,224.118,58.767z"
/>
</g>
<g>
<path class="st2" d="M75.291,88.03c0.368,0.248,0.632,0.428,0.792,0.54c0.288,0.216,0.432,0.422,0.432,0.617
c0,0.196-0.12,0.471-0.36,0.822c-0.24,0.353-0.484,0.528-0.732,0.528c-0.152,0-0.384-0.108-0.696-0.324
c-0.041-0.023-0.152-0.1-0.336-0.228s-0.328-0.225-0.432-0.288c-0.744,0.576-1.58,0.863-2.508,0.863
c-1.24,0-2.286-0.439-3.138-1.319s-1.278-1.928-1.278-3.145c0-0.664,0.12-1.285,0.36-1.865c0.24-0.58,0.56-1.066,0.96-1.458
c0.4-0.393,0.86-0.7,1.38-0.925c0.52-0.224,1.056-0.336,1.608-0.336c1.184,0,2.212,0.429,3.084,1.284
c0.872,0.856,1.308,1.94,1.308,3.252C75.735,86.713,75.587,87.373,75.291,88.03z M69.159,86.038c0,0.712,0.23,1.29,0.69,1.733
c0.46,0.444,0.974,0.666,1.542,0.666c0.568,0,1.08-0.216,1.536-0.647s0.684-1.012,0.684-1.74c0-0.728-0.23-1.312-0.69-1.752
c-0.46-0.439-0.974-0.66-1.542-0.66c-0.568,0-1.08,0.223-1.536,0.666C69.387,84.747,69.159,85.326,69.159,86.038z"/>
<path class="st2" d="M83.643,81.946c0.08-0.128,0.196-0.217,0.348-0.265c0.152-0.048,0.342-0.071,0.57-0.071s0.41,0.02,0.546,0.06
s0.24,0.088,0.312,0.145c0.072,0.056,0.124,0.14,0.156,0.252c0.048,0.136,0.072,0.344,0.072,0.624v3.624
c0,1.056-0.328,2.016-0.984,2.88c-0.32,0.407-0.732,0.737-1.236,0.989c-0.504,0.252-1.062,0.378-1.674,0.378
c-0.612,0-1.168-0.128-1.668-0.384s-0.906-0.592-1.218-1.008c-0.648-0.848-0.972-1.808-0.972-2.88v-3.612
c0-0.191,0.006-0.334,0.018-0.426c0.012-0.092,0.05-0.198,0.114-0.318c0.064-0.119,0.172-0.204,0.324-0.252
s0.356-0.071,0.612-0.071s0.46,0.023,0.612,0.071c0.152,0.048,0.256,0.133,0.312,0.252c0.096,0.185,0.144,0.437,0.144,0.757v3.6
c0,0.488,0.12,0.952,0.36,1.392c0.12,0.225,0.3,0.404,0.54,0.54c0.24,0.137,0.524,0.204,0.852,0.204
c0.583,0,1.02-0.216,1.308-0.647c0.288-0.433,0.432-0.933,0.432-1.5v-3.672C83.522,82.293,83.563,82.074,83.643,81.946z"/>
<path class="st2" d="M92.283,82.246l3.24,6.696c0.136,0.271,0.204,0.476,0.204,0.611c0,0.288-0.232,0.548-0.696,0.78
c-0.272,0.136-0.486,0.204-0.642,0.204c-0.156,0-0.284-0.036-0.384-0.108c-0.1-0.071-0.172-0.147-0.216-0.228
s-0.106-0.2-0.186-0.36l-0.624-1.296h-3.324l-0.624,1.296c-0.08,0.16-0.142,0.276-0.186,0.349
c-0.044,0.071-0.116,0.146-0.216,0.222s-0.228,0.114-0.384,0.114c-0.156,0-0.37-0.068-0.642-0.204
c-0.464-0.225-0.696-0.48-0.696-0.769c0-0.136,0.068-0.34,0.204-0.611l3.24-6.708c0.088-0.185,0.222-0.332,0.402-0.444
c0.18-0.112,0.37-0.168,0.57-0.168C91.755,81.621,92.075,81.829,92.283,82.246z M91.311,85.125l-0.792,1.644h1.596L91.311,85.125z"
/>
<path class="st2" d="M104.319,88.929c0.12,0.288,0.18,0.496,0.18,0.624c0,0.305-0.248,0.561-0.744,0.769
c-0.256,0.111-0.462,0.168-0.618,0.168c-0.156,0-0.284-0.038-0.384-0.114s-0.174-0.154-0.222-0.234
c-0.08-0.151-0.392-0.876-0.936-2.172l-0.372,0.024h-1.512v1.355c0,0.185-0.006,0.322-0.018,0.414
c-0.012,0.093-0.05,0.198-0.114,0.318c-0.112,0.216-0.424,0.324-0.936,0.324c-0.56,0-0.888-0.148-0.984-0.444
c-0.048-0.136-0.072-0.344-0.072-0.624v-6.66c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324h2.592c0.704,0,1.388,0.256,2.052,0.768c0.32,0.248,0.584,0.584,0.792,1.009
c0.208,0.424,0.312,0.896,0.312,1.416c0,0.903-0.3,1.647-0.9,2.231C103.679,87.469,103.951,88.097,104.319,88.929z M99.711,85.87
h1.536c0.232,0,0.464-0.088,0.696-0.264c0.232-0.177,0.348-0.44,0.348-0.792c0-0.353-0.116-0.618-0.348-0.799
c-0.232-0.18-0.472-0.27-0.72-0.27h-1.512V85.87z"/>
<path class="st2" d="M106.455,81.61h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414v-6.024h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C105.987,81.645,106.191,81.61,106.455,81.61z"/>
<path class="st2" d="M117.975,88.293h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V88.293z"/>
<path class="st2" d="M131.438,88.929c0.12,0.288,0.18,0.496,0.18,0.624c0,0.305-0.248,0.561-0.744,0.769
c-0.256,0.111-0.462,0.168-0.618,0.168c-0.156,0-0.284-0.038-0.384-0.114s-0.174-0.154-0.222-0.234
c-0.08-0.151-0.392-0.876-0.936-2.172l-0.372,0.024h-1.512v1.355c0,0.185-0.006,0.322-0.018,0.414
c-0.012,0.093-0.05,0.198-0.114,0.318c-0.112,0.216-0.424,0.324-0.936,0.324c-0.56,0-0.888-0.148-0.984-0.444
c-0.048-0.136-0.072-0.344-0.072-0.624v-6.66c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324h2.592c0.704,0,1.388,0.256,2.052,0.768c0.32,0.248,0.584,0.584,0.792,1.009
c0.208,0.424,0.312,0.896,0.312,1.416c0,0.903-0.3,1.647-0.9,2.231C130.798,87.469,131.07,88.097,131.438,88.929z M126.831,85.87
h1.536c0.232,0,0.464-0.088,0.696-0.264c0.232-0.177,0.348-0.44,0.348-0.792c0-0.353-0.116-0.618-0.348-0.799
c-0.232-0.18-0.472-0.27-0.72-0.27h-1.512V85.87z"/>
</g>
<g>
<path class="st2" d="M161.062,81.681h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414V83.42h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C160.594,81.716,160.798,81.681,161.062,81.681z"/>
<path class="st2" d="M180.981,81.741c0.536,0.192,0.804,0.448,0.804,0.768c0,0.104-0.048,0.301-0.144,0.589l-2.304,6.659
c-0.016,0.057-0.044,0.125-0.084,0.204c-0.04,0.08-0.146,0.187-0.318,0.318c-0.172,0.132-0.376,0.198-0.612,0.198
c-0.236,0-0.44-0.066-0.612-0.198s-0.286-0.262-0.342-0.39l-1.404-4.141c-0.888,2.624-1.34,3.96-1.356,4.008
c-0.016,0.049-0.052,0.116-0.108,0.204c-0.056,0.089-0.12,0.168-0.192,0.24c-0.184,0.185-0.404,0.276-0.66,0.276
s-0.466-0.061-0.63-0.181c-0.164-0.119-0.274-0.239-0.33-0.359l-0.084-0.181l-2.316-6.659c-0.088-0.265-0.132-0.46-0.132-0.589
c0-0.319,0.268-0.571,0.804-0.756c0.232-0.079,0.442-0.12,0.63-0.12s0.332,0.064,0.432,0.192s0.19,0.324,0.27,0.588l1.32,4.008
l1.308-3.947c0.112-0.336,0.316-0.568,0.612-0.696c0.128-0.056,0.294-0.084,0.498-0.084c0.204,0,0.394,0.065,0.57,0.198
c0.176,0.132,0.288,0.262,0.336,0.39l1.38,4.164l1.32-4.032c0.064-0.184,0.116-0.319,0.156-0.408
c0.04-0.088,0.114-0.174,0.222-0.258s0.242-0.126,0.402-0.126S180.766,81.661,180.981,81.741z"/>
<path class="st2" d="M185.769,88.365h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V88.365z"/>
<path class="st2" d="M198.184,82.059c0.076-0.141,0.19-0.234,0.342-0.282s0.342-0.072,0.57-0.072c0.228,0,0.412,0.021,0.552,0.061
s0.244,0.088,0.312,0.144s0.118,0.141,0.15,0.252c0.048,0.128,0.072,0.332,0.072,0.612v6.66c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.312,0-0.528-0.024-0.648-0.072
c-0.12-0.048-0.22-0.124-0.3-0.228c-1.8-2.4-2.984-3.968-3.552-4.704v3.948c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.496,0-0.8-0.108-0.912-0.324
c-0.064-0.12-0.102-0.228-0.114-0.324c-0.012-0.096-0.018-0.235-0.018-0.42v-6.695c0-0.305,0.038-0.526,0.114-0.666
c0.076-0.141,0.19-0.234,0.342-0.282s0.348-0.072,0.588-0.072c0.24,0,0.43,0.022,0.57,0.066c0.14,0.044,0.238,0.094,0.294,0.149
c0.032,0.024,0.124,0.129,0.276,0.312c1.688,2.296,2.816,3.812,3.384,4.548v-4.056C198.069,82.42,198.107,82.199,198.184,82.059z"
/>
<path class="st2" d="M202.917,81.681h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414V83.42h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C202.449,81.716,202.653,81.681,202.917,81.681z"/>
<path class="st2" d="M219.297,81.861c0.392,0.272,0.588,0.536,0.588,0.792c0,0.152-0.092,0.364-0.276,0.636l-2.592,3.876v2.292
c0,0.185-0.006,0.322-0.018,0.414s-0.05,0.198-0.114,0.318s-0.172,0.204-0.324,0.252s-0.356,0.072-0.612,0.072
c-0.256,0-0.46-0.024-0.612-0.072s-0.26-0.134-0.324-0.258c-0.064-0.124-0.102-0.232-0.114-0.324
c-0.012-0.092-0.018-0.234-0.018-0.426v-2.269l-2.592-3.876c-0.184-0.271-0.276-0.483-0.276-0.636c0-0.256,0.176-0.502,0.528-0.738
c0.352-0.235,0.604-0.354,0.756-0.354s0.272,0.032,0.36,0.096c0.136,0.088,0.28,0.252,0.432,0.492l1.86,2.976l1.86-2.976
c0.152-0.24,0.284-0.398,0.396-0.475c0.112-0.075,0.242-0.113,0.39-0.113C218.743,81.561,218.977,81.661,219.297,81.861z"/>
</g>
<g>
<path class="st2" d="M123.67,105.22c0.064,0.12,0.102,0.228,0.114,0.324c0.012,0.096,0.018,0.235,0.018,0.42v6.66
c0,0.552-0.152,0.876-0.456,0.972c-0.152,0.048-0.344,0.072-0.576,0.072c-0.232,0-0.417-0.021-0.552-0.061
c-0.136-0.04-0.24-0.088-0.312-0.144c-0.072-0.056-0.128-0.136-0.168-0.24c-0.04-0.136-0.06-0.344-0.06-0.624v-4.02
c-0.2,0.248-0.492,0.642-0.876,1.182c-0.384,0.54-0.628,0.878-0.732,1.014c-0.104,0.137-0.176,0.23-0.216,0.282
c-0.041,0.052-0.138,0.124-0.294,0.216c-0.156,0.093-0.324,0.139-0.504,0.139c-0.18,0-0.344-0.042-0.492-0.126
c-0.148-0.084-0.254-0.166-0.318-0.246l-0.096-0.133c-0.16-0.199-0.476-0.625-0.948-1.277s-0.728-1.002-0.768-1.05v4.044
c0,0.184-0.006,0.322-0.018,0.414c-0.012,0.092-0.05,0.193-0.114,0.306c-0.12,0.216-0.432,0.324-0.936,0.324
c-0.488,0-0.792-0.108-0.912-0.324c-0.064-0.112-0.102-0.216-0.114-0.312c-0.012-0.096-0.018-0.239-0.018-0.432v-6.66
c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317c0.12-0.208,0.432-0.312,0.936-0.312
c0.216,0,0.402,0.026,0.558,0.078c0.156,0.052,0.258,0.106,0.306,0.162l0.072,0.072l2.724,3.575c1.36-1.8,2.268-2.987,2.724-3.563
c0.136-0.216,0.458-0.324,0.966-0.324C123.247,104.895,123.557,105.004,123.67,105.22z"/>
<path class="st2" d="M125.962,105.939c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624v6.672
c0,0.191-0.006,0.332-0.018,0.42c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612V105.939z"/>
<path class="st2" d="M135.927,105.25c0.076-0.141,0.19-0.234,0.342-0.282s0.342-0.072,0.57-0.072c0.228,0,0.412,0.021,0.552,0.061
s0.244,0.088,0.312,0.144s0.118,0.141,0.15,0.252c0.048,0.128,0.072,0.332,0.072,0.612v6.66c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.312,0-0.528-0.024-0.648-0.072
c-0.12-0.048-0.22-0.124-0.3-0.228c-1.8-2.4-2.984-3.968-3.552-4.704v3.948c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.496,0-0.8-0.108-0.912-0.324
c-0.064-0.12-0.102-0.228-0.114-0.324c-0.012-0.096-0.018-0.235-0.018-0.42v-6.695c0-0.305,0.038-0.526,0.114-0.666
c0.076-0.141,0.19-0.234,0.342-0.282s0.348-0.072,0.588-0.072c0.24,0,0.43,0.022,0.57,0.066c0.14,0.044,0.238,0.094,0.294,0.149
c0.032,0.024,0.124,0.129,0.276,0.312c1.688,2.296,2.816,3.812,3.384,4.548v-4.056C135.813,105.611,135.851,105.39,135.927,105.25z
"/>
<path class="st2" d="M145.833,105.208c0.08-0.128,0.196-0.217,0.348-0.265c0.152-0.048,0.342-0.071,0.57-0.071
s0.41,0.02,0.546,0.06s0.24,0.088,0.312,0.145c0.072,0.056,0.124,0.14,0.156,0.252c0.048,0.136,0.072,0.344,0.072,0.624v3.624
c0,1.056-0.328,2.016-0.984,2.88c-0.32,0.407-0.732,0.737-1.236,0.989c-0.504,0.252-1.062,0.378-1.674,0.378
c-0.612,0-1.168-0.128-1.668-0.384s-0.906-0.592-1.218-1.008c-0.648-0.848-0.972-1.808-0.972-2.88v-3.612
c0-0.191,0.006-0.334,0.018-0.426c0.012-0.092,0.05-0.198,0.114-0.318c0.064-0.119,0.172-0.204,0.324-0.252
s0.356-0.071,0.612-0.071s0.46,0.023,0.612,0.071c0.152,0.048,0.256,0.133,0.312,0.252c0.096,0.185,0.144,0.437,0.144,0.757v3.6
c0,0.488,0.12,0.952,0.36,1.392c0.12,0.225,0.3,0.404,0.54,0.54c0.24,0.137,0.524,0.204,0.852,0.204
c0.583,0,1.02-0.216,1.308-0.647c0.288-0.433,0.432-0.933,0.432-1.5v-3.672C145.713,105.556,145.753,105.336,145.833,105.208z"/>
<path class="st2" d="M150.573,104.872h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414v-6.024h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C150.105,104.907,150.309,104.872,150.573,104.872z"/>
<path class="st2" d="M162.093,111.556h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V111.556z"/>
<path class="st2" d="M168.957,112.443c-0.208-0.256-0.312-0.485-0.312-0.689s0.172-0.475,0.516-0.811
c0.2-0.191,0.412-0.288,0.636-0.288c0.224,0,0.536,0.2,0.936,0.601c0.112,0.136,0.271,0.266,0.48,0.39
c0.208,0.124,0.4,0.187,0.576,0.187c0.744,0,1.116-0.305,1.116-0.912c0-0.185-0.102-0.338-0.306-0.462s-0.458-0.214-0.762-0.271
c-0.304-0.056-0.632-0.146-0.984-0.27s-0.68-0.271-0.984-0.438s-0.558-0.434-0.762-0.798c-0.204-0.364-0.306-0.802-0.306-1.313
c0-0.704,0.262-1.318,0.786-1.843c0.524-0.523,1.238-0.786,2.142-0.786c0.48,0,0.918,0.062,1.314,0.187
c0.396,0.124,0.67,0.25,0.822,0.378l0.3,0.228c0.248,0.232,0.372,0.429,0.372,0.589s-0.096,0.38-0.288,0.659
c-0.272,0.4-0.552,0.601-0.84,0.601c-0.168,0-0.376-0.08-0.624-0.24c-0.024-0.016-0.07-0.056-0.138-0.12
c-0.068-0.063-0.13-0.115-0.186-0.156c-0.168-0.104-0.382-0.155-0.642-0.155c-0.26,0-0.476,0.062-0.648,0.186
c-0.172,0.124-0.258,0.296-0.258,0.517c0,0.22,0.102,0.397,0.306,0.533c0.204,0.137,0.458,0.229,0.762,0.276
c0.304,0.048,0.636,0.122,0.996,0.222c0.36,0.101,0.692,0.223,0.996,0.366c0.304,0.145,0.558,0.395,0.762,0.75
c0.204,0.356,0.306,0.794,0.306,1.314c0,0.52-0.104,0.978-0.312,1.374c-0.208,0.396-0.48,0.701-0.816,0.918
c-0.648,0.424-1.34,0.636-2.076,0.636c-0.376,0-0.732-0.046-1.068-0.138c-0.336-0.093-0.608-0.206-0.816-0.343
c-0.424-0.256-0.72-0.504-0.888-0.743L168.957,112.443z"/>
</g>
<g>
<path class="st2" d="M204.553,104.854h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414v-6.024h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C204.084,104.889,204.288,104.854,204.553,104.854z"/>
<path class="st2" d="M217.356,104.757c1.184,0,2.212,0.429,3.084,1.284c0.872,0.856,1.308,1.918,1.308,3.187
c0,1.268-0.416,2.348-1.248,3.239c-0.832,0.893-1.856,1.338-3.072,1.338c-1.216,0-2.25-0.439-3.102-1.319s-1.278-1.928-1.278-3.145
c0-0.664,0.12-1.285,0.36-1.865c0.24-0.58,0.56-1.066,0.96-1.458c0.4-0.393,0.86-0.7,1.38-0.925
C216.268,104.869,216.805,104.757,217.356,104.757z M215.172,109.282c0,0.712,0.23,1.29,0.69,1.733
c0.46,0.444,0.974,0.666,1.542,0.666c0.568,0,1.08-0.216,1.536-0.647s0.684-1.012,0.684-1.74c0-0.728-0.23-1.312-0.69-1.752
c-0.46-0.439-0.974-0.66-1.542-0.66c-0.568,0-1.08,0.223-1.536,0.666C215.4,107.992,215.172,108.57,215.172,109.282z"/>
</g>
<g>
<path class="st2" d="M67.17,104.919c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.196,0.051,0.312,0.114
c0.116,0.064,0.198,0.172,0.246,0.324s0.072,0.355,0.072,0.612c0,0.256-0.024,0.46-0.072,0.611
c-0.048,0.152-0.132,0.258-0.252,0.318c-0.12,0.06-0.226,0.096-0.318,0.107c-0.092,0.013-0.234,0.019-0.426,0.019h-3.672v1.212
h2.364c0.192,0,0.334,0.006,0.426,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.208,0.12,0.312,0.437,0.312,0.948
c0,0.56-0.152,0.892-0.456,0.996c-0.128,0.04-0.332,0.06-0.612,0.06h-2.352v2.269c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.56,0-0.888-0.152-0.984-0.456
c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834c0.152-0.147,0.44-0.222,0.864-0.222H67.17z"/>
<path class="st2" d="M70.193,105.975c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624v6.672
c0,0.191-0.006,0.332-0.018,0.42c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612V105.975z"/>
<path class="st2" d="M82.505,105.051c0.472,0.232,0.708,0.488,0.708,0.768c0,0.129-0.06,0.32-0.18,0.576l-3.312,6.721
c-0.088,0.176-0.222,0.317-0.402,0.426c-0.18,0.107-0.366,0.162-0.558,0.162h-0.12c-0.2,0-0.39-0.055-0.57-0.162
c-0.18-0.108-0.314-0.25-0.402-0.426l-3.312-6.721c-0.12-0.256-0.18-0.447-0.18-0.576c0-0.279,0.236-0.535,0.708-0.768
c0.264-0.136,0.466-0.204,0.606-0.204c0.14,0,0.246,0.017,0.318,0.048c0.072,0.032,0.14,0.089,0.204,0.168
c0.072,0.097,0.138,0.202,0.198,0.318s0.214,0.448,0.462,0.996s0.514,1.13,0.798,1.746c0.284,0.616,0.552,1.198,0.804,1.746
s0.394,0.854,0.426,0.918l2.4-5.256c0.064-0.152,0.12-0.272,0.168-0.36c0.144-0.216,0.32-0.324,0.528-0.324
S82.242,104.915,82.505,105.051z"/>
<path class="st2" d="M87.197,111.591h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V111.591z"/>
</g>
<g>
<path class="st2" d="M77.722,129.916c0.208,0.424,0.312,0.896,0.312,1.416c0,0.52-0.104,0.989-0.312,1.409
c-0.208,0.42-0.476,0.755-0.804,1.002c-0.664,0.513-1.352,0.769-2.064,0.769h-1.5v1.355c0,0.185-0.006,0.322-0.018,0.414
c-0.012,0.093-0.05,0.198-0.114,0.318c-0.112,0.216-0.424,0.324-0.936,0.324c-0.56,0-0.888-0.148-0.984-0.444
c-0.048-0.136-0.072-0.344-0.072-0.624v-6.66c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324h2.568c0.704,0,1.388,0.256,2.052,0.768C77.246,129.155,77.514,129.491,77.722,129.916z
M75.575,132.124c0.232-0.177,0.348-0.44,0.348-0.792c0-0.353-0.116-0.618-0.348-0.799c-0.232-0.18-0.472-0.27-0.72-0.27h-1.5
v2.124h1.512C75.106,132.388,75.342,132.3,75.575,132.124z"/>
<path class="st2" d="M84.095,128.763l3.24,6.696c0.136,0.271,0.204,0.476,0.204,0.611c0,0.288-0.232,0.548-0.696,0.78
c-0.272,0.136-0.486,0.204-0.642,0.204c-0.156,0-0.284-0.036-0.384-0.108c-0.1-0.071-0.172-0.147-0.216-0.228
s-0.106-0.2-0.186-0.36l-0.624-1.296h-3.324l-0.624,1.296c-0.08,0.16-0.142,0.276-0.186,0.349
c-0.044,0.071-0.116,0.146-0.216,0.222s-0.228,0.114-0.384,0.114c-0.156,0-0.37-0.068-0.642-0.204
c-0.464-0.225-0.696-0.48-0.696-0.769c0-0.136,0.068-0.34,0.204-0.611l3.24-6.708c0.088-0.185,0.222-0.332,0.402-0.444
c0.18-0.112,0.37-0.168,0.57-0.168C83.566,128.139,83.886,128.347,84.095,128.763z M83.122,131.643l-0.792,1.644h1.596
L83.122,131.643z"/>
<path class="st2" d="M89.17,135.699c-0.208-0.256-0.312-0.485-0.312-0.689s0.172-0.475,0.516-0.811
c0.2-0.191,0.412-0.288,0.636-0.288c0.224,0,0.536,0.2,0.936,0.601c0.112,0.136,0.271,0.266,0.48,0.39
c0.208,0.124,0.4,0.187,0.576,0.187c0.744,0,1.116-0.305,1.116-0.912c0-0.185-0.102-0.338-0.306-0.462s-0.458-0.214-0.762-0.271
c-0.304-0.056-0.632-0.146-0.984-0.27s-0.68-0.271-0.984-0.438s-0.558-0.434-0.762-0.798c-0.204-0.364-0.306-0.802-0.306-1.313
c0-0.704,0.262-1.318,0.786-1.843c0.524-0.523,1.238-0.786,2.142-0.786c0.48,0,0.918,0.063,1.314,0.187
c0.396,0.124,0.67,0.25,0.822,0.378l0.3,0.228c0.248,0.232,0.372,0.429,0.372,0.589s-0.096,0.38-0.288,0.659
c-0.272,0.4-0.552,0.601-0.84,0.601c-0.168,0-0.376-0.08-0.624-0.24c-0.024-0.016-0.07-0.056-0.138-0.12
c-0.068-0.063-0.13-0.115-0.186-0.156c-0.168-0.104-0.382-0.155-0.642-0.155c-0.26,0-0.476,0.062-0.648,0.186
c-0.172,0.124-0.258,0.296-0.258,0.517c0,0.22,0.102,0.397,0.306,0.533c0.204,0.137,0.458,0.229,0.762,0.276
c0.304,0.048,0.636,0.122,0.996,0.222c0.36,0.101,0.692,0.223,0.996,0.366c0.304,0.145,0.558,0.395,0.762,0.75
c0.204,0.356,0.306,0.794,0.306,1.314c0,0.52-0.104,0.978-0.312,1.374c-0.208,0.396-0.48,0.701-0.816,0.918
c-0.648,0.424-1.34,0.636-2.076,0.636c-0.376,0-0.732-0.046-1.068-0.138c-0.336-0.093-0.608-0.206-0.816-0.343
c-0.424-0.256-0.72-0.504-0.888-0.743L89.17,135.699z"/>
<path class="st2" d="M97.21,128.128h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414v-6.024h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C96.742,128.163,96.946,128.128,97.21,128.128z"/>
</g>
<g>
<path class="st2" d="M135.291,128.001c1.184,0,2.212,0.429,3.084,1.284c0.872,0.856,1.308,1.918,1.308,3.187
c0,1.268-0.416,2.348-1.248,3.239c-0.832,0.893-1.856,1.338-3.072,1.338c-1.216,0-2.25-0.439-3.102-1.319s-1.278-1.928-1.278-3.145
c0-0.664,0.12-1.285,0.36-1.865c0.24-0.58,0.56-1.066,0.96-1.458c0.4-0.393,0.86-0.7,1.38-0.925
C134.203,128.114,134.739,128.001,135.291,128.001z M133.107,132.526c0,0.712,0.23,1.29,0.69,1.733
c0.46,0.444,0.974,0.666,1.542,0.666c0.568,0,1.08-0.216,1.536-0.647s0.684-1.012,0.684-1.74c0-0.728-0.23-1.312-0.69-1.752
c-0.46-0.439-0.974-0.66-1.542-0.66c-0.568,0-1.08,0.223-1.536,0.666C133.335,131.236,133.107,131.814,133.107,132.526z"/>
<path class="st2" d="M147.345,128.476c0.076-0.141,0.19-0.234,0.342-0.282s0.342-0.072,0.57-0.072c0.228,0,0.412,0.021,0.552,0.061
s0.244,0.088,0.312,0.144s0.118,0.141,0.15,0.252c0.048,0.128,0.072,0.332,0.072,0.612v6.66c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.312,0-0.528-0.024-0.648-0.072
c-0.12-0.048-0.22-0.124-0.3-0.228c-1.8-2.4-2.984-3.968-3.552-4.704v3.948c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.496,0-0.8-0.108-0.912-0.324
c-0.064-0.12-0.102-0.228-0.114-0.324c-0.012-0.096-0.018-0.235-0.018-0.42v-6.695c0-0.305,0.038-0.526,0.114-0.666
c0.076-0.141,0.19-0.234,0.342-0.282s0.348-0.072,0.588-0.072c0.24,0,0.43,0.022,0.57,0.066c0.14,0.044,0.238,0.094,0.294,0.149
c0.032,0.024,0.124,0.129,0.276,0.312c1.688,2.296,2.816,3.812,3.384,4.548v-4.056
C147.231,128.837,147.269,128.616,147.345,128.476z"/>
<path class="st2" d="M153.627,134.782h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V134.782z"/>
</g>
<g>
<path class="st2" d="M180.068,128.085h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414v-6.024h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C179.6,128.12,179.804,128.085,180.068,128.085z"/>
<path class="st2" d="M194.9,128.421c0.064-0.12,0.172-0.204,0.324-0.252c0.152-0.049,0.344-0.072,0.576-0.072
s0.416,0.02,0.552,0.06c0.136,0.04,0.24,0.089,0.312,0.145c0.072,0.056,0.128,0.136,0.168,0.24c0.04,0.136,0.06,0.344,0.06,0.624
v6.659c0,0.185-0.006,0.322-0.018,0.414c-0.012,0.093-0.05,0.198-0.114,0.318c-0.112,0.216-0.424,0.324-0.936,0.324
c-0.56,0-0.888-0.148-0.984-0.444c-0.048-0.136-0.072-0.344-0.072-0.624v-2.436h-3.18v2.447c0,0.185-0.006,0.322-0.018,0.414
c-0.012,0.093-0.05,0.198-0.114,0.318c-0.112,0.216-0.424,0.324-0.936,0.324c-0.56,0-0.888-0.148-0.984-0.444
c-0.048-0.136-0.072-0.344-0.072-0.624v-6.66c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624v2.447h3.18v-2.46
c0-0.184,0.006-0.321,0.018-0.414C194.798,128.647,194.836,128.541,194.9,128.421z"/>
<path class="st2" d="M205.784,135.405c0.12,0.288,0.18,0.496,0.18,0.624c0,0.305-0.248,0.561-0.744,0.769
c-0.256,0.111-0.462,0.168-0.618,0.168c-0.156,0-0.284-0.038-0.384-0.114s-0.174-0.154-0.222-0.234
c-0.08-0.151-0.392-0.876-0.936-2.172l-0.372,0.024h-1.512v1.355c0,0.185-0.006,0.322-0.018,0.414
c-0.012,0.093-0.05,0.198-0.114,0.318c-0.112,0.216-0.424,0.324-0.936,0.324c-0.56,0-0.888-0.148-0.984-0.444
c-0.048-0.136-0.072-0.344-0.072-0.624v-6.66c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324h2.592c0.704,0,1.388,0.256,2.052,0.768c0.32,0.248,0.584,0.584,0.792,1.009
c0.208,0.424,0.312,0.896,0.312,1.416c0,0.903-0.3,1.647-0.9,2.231C205.143,133.945,205.415,134.573,205.784,135.405z
M201.176,132.345h1.536c0.232,0,0.464-0.088,0.696-0.264c0.232-0.177,0.348-0.44,0.348-0.792c0-0.353-0.116-0.618-0.348-0.799
c-0.232-0.18-0.472-0.27-0.72-0.27h-1.512V132.345z"/>
<path class="st2" d="M209.948,134.769h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V134.769z"/>
<path class="st2" d="M218.804,134.769h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V134.769z"/>
</g>
<g>
<path class="st2" d="M129.137,151.342h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414v-6.024h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C128.669,151.377,128.873,151.342,129.137,151.342z"/>
<path class="st2" d="M149.056,151.402c0.536,0.192,0.804,0.448,0.804,0.768c0,0.104-0.048,0.301-0.144,0.589l-2.304,6.659
c-0.016,0.057-0.044,0.125-0.084,0.204c-0.04,0.08-0.146,0.187-0.318,0.318c-0.172,0.132-0.376,0.198-0.612,0.198
c-0.236,0-0.44-0.066-0.612-0.198s-0.286-0.262-0.342-0.39l-1.404-4.141c-0.888,2.624-1.34,3.96-1.356,4.008
c-0.016,0.049-0.052,0.116-0.108,0.204c-0.056,0.089-0.12,0.168-0.192,0.24c-0.184,0.185-0.404,0.276-0.66,0.276
s-0.466-0.061-0.63-0.181c-0.164-0.119-0.274-0.239-0.33-0.359l-0.084-0.181l-2.316-6.659c-0.088-0.265-0.132-0.46-0.132-0.589
c0-0.319,0.268-0.571,0.804-0.756c0.232-0.079,0.442-0.12,0.63-0.12s0.332,0.064,0.432,0.192s0.19,0.324,0.27,0.588l1.32,4.008
l1.308-3.947c0.112-0.336,0.316-0.568,0.612-0.696c0.128-0.056,0.294-0.084,0.498-0.084c0.204,0,0.394,0.065,0.57,0.198
c0.176,0.132,0.288,0.262,0.336,0.39l1.38,4.164l1.32-4.032c0.064-0.184,0.116-0.319,0.156-0.408
c0.04-0.088,0.114-0.174,0.222-0.258s0.242-0.126,0.402-0.126S148.841,151.322,149.056,151.402z"/>
<path class="st2" d="M155.848,151.245c1.184,0,2.212,0.429,3.084,1.284c0.872,0.856,1.308,1.918,1.308,3.187
c0,1.268-0.416,2.348-1.248,3.239c-0.832,0.893-1.856,1.338-3.072,1.338c-1.216,0-2.25-0.439-3.102-1.319s-1.278-1.928-1.278-3.145
c0-0.664,0.12-1.285,0.36-1.865c0.24-0.58,0.56-1.066,0.96-1.458c0.4-0.393,0.86-0.7,1.38-0.925
C154.761,151.358,155.297,151.245,155.848,151.245z M153.664,155.77c0,0.712,0.23,1.29,0.69,1.733
c0.46,0.444,0.974,0.666,1.542,0.666c0.568,0,1.08-0.216,1.536-0.647s0.684-1.012,0.684-1.74c0-0.728-0.23-1.312-0.69-1.752
c-0.46-0.439-0.974-0.66-1.542-0.66c-0.568,0-1.08,0.223-1.536,0.666C153.892,154.48,153.664,155.058,153.664,155.77z"/>
</g>
<g>
<path class="st2" d="M73.833,151.354c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.196,0.051,0.312,0.114
c0.116,0.064,0.198,0.172,0.246,0.324s0.072,0.355,0.072,0.612c0,0.256-0.024,0.46-0.072,0.611
c-0.048,0.152-0.132,0.258-0.252,0.318c-0.12,0.06-0.226,0.096-0.318,0.107c-0.092,0.013-0.234,0.019-0.426,0.019h-3.672v1.212
H72.5c0.192,0,0.334,0.006,0.426,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.208,0.12,0.312,0.437,0.312,0.948
c0,0.56-0.152,0.892-0.456,0.996c-0.128,0.04-0.332,0.06-0.612,0.06h-2.352v2.269c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.56,0-0.888-0.152-0.984-0.456
c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834c0.152-0.147,0.44-0.222,0.864-0.222H73.833z"/>
<path class="st2" d="M80.984,151.245c1.184,0,2.212,0.429,3.084,1.284c0.872,0.856,1.308,1.918,1.308,3.187
c0,1.268-0.416,2.348-1.248,3.239c-0.832,0.893-1.856,1.338-3.072,1.338c-1.216,0-2.25-0.439-3.102-1.319s-1.278-1.928-1.278-3.145
c0-0.664,0.12-1.285,0.36-1.865c0.24-0.58,0.56-1.066,0.96-1.458c0.4-0.393,0.86-0.7,1.38-0.925
C79.896,151.358,80.433,151.245,80.984,151.245z M78.8,155.77c0,0.712,0.23,1.29,0.69,1.733c0.46,0.444,0.974,0.666,1.542,0.666
c0.568,0,1.08-0.216,1.536-0.647s0.684-1.012,0.684-1.74c0-0.728-0.23-1.312-0.69-1.752c-0.46-0.439-0.974-0.66-1.542-0.66
c-0.568,0-1.08,0.223-1.536,0.666C79.028,154.48,78.8,155.058,78.8,155.77z"/>
<path class="st2" d="M93.104,151.678c0.08-0.128,0.196-0.217,0.348-0.265c0.152-0.048,0.342-0.071,0.57-0.071s0.41,0.02,0.546,0.06
s0.24,0.088,0.312,0.145c0.072,0.056,0.124,0.14,0.156,0.252c0.048,0.136,0.072,0.344,0.072,0.624v3.624
c0,1.056-0.328,2.016-0.984,2.88c-0.32,0.407-0.732,0.737-1.236,0.989c-0.504,0.252-1.062,0.378-1.674,0.378
c-0.612,0-1.168-0.128-1.668-0.384s-0.906-0.592-1.218-1.008c-0.648-0.848-0.972-1.808-0.972-2.88v-3.612
c0-0.191,0.006-0.334,0.018-0.426c0.012-0.092,0.05-0.198,0.114-0.318c0.064-0.119,0.172-0.204,0.324-0.252
s0.356-0.071,0.612-0.071s0.46,0.023,0.612,0.071c0.152,0.048,0.256,0.133,0.312,0.252c0.096,0.185,0.144,0.437,0.144,0.757v3.6
c0,0.488,0.12,0.952,0.36,1.392c0.12,0.225,0.3,0.404,0.54,0.54c0.24,0.137,0.524,0.204,0.852,0.204
c0.583,0,1.02-0.216,1.308-0.647c0.288-0.433,0.432-0.933,0.432-1.5v-3.672C92.984,152.026,93.024,151.806,93.104,151.678z"/>
<path class="st2" d="M104,158.661c0.12,0.288,0.18,0.496,0.18,0.624c0,0.305-0.248,0.561-0.744,0.769
c-0.256,0.111-0.462,0.168-0.618,0.168c-0.156,0-0.284-0.038-0.384-0.114s-0.174-0.154-0.222-0.234
c-0.08-0.151-0.392-0.876-0.936-2.172l-0.372,0.024h-1.512v1.355c0,0.185-0.006,0.322-0.018,0.414
c-0.012,0.093-0.05,0.198-0.114,0.318c-0.112,0.216-0.424,0.324-0.936,0.324c-0.56,0-0.888-0.148-0.984-0.444
c-0.048-0.136-0.072-0.344-0.072-0.624v-6.66c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324h2.592c0.704,0,1.388,0.256,2.052,0.768c0.32,0.248,0.584,0.584,0.792,1.009
c0.208,0.424,0.312,0.896,0.312,1.416c0,0.903-0.3,1.647-0.9,2.231C103.36,157.201,103.632,157.829,104,158.661z M99.393,155.602
h1.536c0.232,0,0.464-0.088,0.696-0.264c0.232-0.177,0.348-0.44,0.348-0.792c0-0.353-0.116-0.618-0.348-0.799
c-0.232-0.18-0.472-0.27-0.72-0.27h-1.512V155.602z"/>
</g>
<g>
<path class="st2" d="M191.894,151.407c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.196,0.051,0.312,0.114
c0.116,0.064,0.198,0.172,0.246,0.324s0.072,0.355,0.072,0.612c0,0.256-0.024,0.46-0.072,0.611
c-0.048,0.152-0.132,0.258-0.252,0.318c-0.12,0.06-0.226,0.096-0.318,0.107c-0.092,0.013-0.234,0.019-0.426,0.019h-3.672v1.212
h2.364c0.192,0,0.334,0.006,0.426,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.208,0.12,0.312,0.437,0.312,0.948
c0,0.56-0.152,0.892-0.456,0.996c-0.128,0.04-0.332,0.06-0.612,0.06h-2.352v2.269c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.56,0-0.888-0.152-0.984-0.456
c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834c0.152-0.147,0.44-0.222,0.864-0.222H191.894z"/>
<path class="st2" d="M194.918,152.463c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624v6.672
c0,0.191-0.006,0.332-0.018,0.42c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612V152.463z"/>
<path class="st2" d="M207.23,151.539c0.472,0.232,0.708,0.488,0.708,0.768c0,0.129-0.06,0.32-0.18,0.576l-3.312,6.721
c-0.088,0.176-0.222,0.317-0.402,0.426c-0.18,0.107-0.366,0.162-0.558,0.162h-0.12c-0.2,0-0.39-0.055-0.57-0.162
c-0.18-0.108-0.314-0.25-0.402-0.426l-3.312-6.721c-0.12-0.256-0.18-0.447-0.18-0.576c0-0.279,0.236-0.535,0.708-0.768
c0.264-0.136,0.466-0.204,0.606-0.204c0.14,0,0.246,0.017,0.318,0.048c0.072,0.032,0.14,0.089,0.204,0.168
c0.072,0.097,0.138,0.202,0.198,0.318s0.214,0.448,0.462,0.996s0.514,1.13,0.798,1.746c0.284,0.616,0.552,1.198,0.804,1.746
s0.394,0.854,0.426,0.918l2.4-5.256c0.064-0.152,0.12-0.272,0.168-0.36c0.144-0.216,0.32-0.324,0.528-0.324
S206.966,151.404,207.23,151.539z"/>
<path class="st2" d="M211.922,158.079h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V158.079z"/>
</g>
<g>
<path class="st2" d="M134.827,182.229c-0.208-0.256-0.312-0.485-0.312-0.689s0.172-0.475,0.516-0.811
c0.2-0.191,0.412-0.288,0.636-0.288c0.224,0,0.536,0.2,0.936,0.601c0.112,0.136,0.271,0.266,0.48,0.39
c0.208,0.124,0.4,0.187,0.576,0.187c0.744,0,1.116-0.305,1.116-0.912c0-0.185-0.102-0.338-0.306-0.462s-0.458-0.214-0.762-0.271
c-0.304-0.056-0.632-0.146-0.984-0.27s-0.68-0.271-0.984-0.438s-0.558-0.434-0.762-0.798c-0.204-0.364-0.306-0.802-0.306-1.313
c0-0.704,0.262-1.318,0.786-1.843c0.524-0.523,1.238-0.786,2.142-0.786c0.48,0,0.918,0.062,1.314,0.187
c0.396,0.124,0.67,0.25,0.822,0.378l0.3,0.228c0.248,0.232,0.372,0.429,0.372,0.589s-0.096,0.38-0.288,0.659
c-0.272,0.4-0.552,0.601-0.84,0.601c-0.168,0-0.376-0.08-0.624-0.24c-0.024-0.016-0.07-0.056-0.138-0.12
c-0.068-0.063-0.13-0.115-0.186-0.156c-0.168-0.104-0.382-0.155-0.642-0.155c-0.26,0-0.476,0.062-0.648,0.186
c-0.172,0.124-0.258,0.296-0.258,0.517c0,0.22,0.102,0.397,0.306,0.533c0.204,0.137,0.458,0.229,0.762,0.276
c0.304,0.048,0.636,0.122,0.996,0.222c0.36,0.101,0.692,0.223,0.996,0.366c0.304,0.145,0.558,0.395,0.762,0.75
c0.204,0.356,0.306,0.794,0.306,1.314c0,0.52-0.104,0.978-0.312,1.374c-0.208,0.396-0.48,0.701-0.816,0.918
c-0.648,0.424-1.34,0.636-2.076,0.636c-0.376,0-0.732-0.046-1.068-0.138c-0.336-0.093-0.608-0.206-0.816-0.343
c-0.424-0.256-0.72-0.504-0.888-0.743L134.827,182.229z"/>
<path class="st2" d="M142.891,175.725c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624v6.672
c0,0.191-0.006,0.332-0.018,0.42c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612V175.725z"/>
<path class="st2" d="M152.587,179.013l2.412,2.652c0.271,0.304,0.408,0.56,0.408,0.768s-0.154,0.452-0.462,0.732
s-0.568,0.42-0.78,0.42c-0.212,0-0.458-0.16-0.738-0.48l-2.28-2.615l-2.28,2.615c-0.288,0.32-0.534,0.48-0.738,0.48
s-0.464-0.142-0.78-0.426s-0.474-0.526-0.474-0.727c0-0.199,0.14-0.456,0.42-0.768l2.412-2.652l-2.412-2.651
c-0.28-0.296-0.42-0.549-0.42-0.757s0.156-0.453,0.468-0.737s0.574-0.427,0.786-0.427s0.458,0.16,0.738,0.48l2.28,2.616l2.28-2.616
c0.288-0.32,0.534-0.48,0.738-0.48c0.204,0,0.462,0.141,0.774,0.421c0.312,0.279,0.468,0.527,0.468,0.743
c0,0.217-0.136,0.469-0.408,0.757L152.587,179.013z"/>
</g>
<g>
<path class="st2" d="M65.227,182.187c-0.208-0.256-0.312-0.485-0.312-0.689s0.172-0.475,0.516-0.811
c0.2-0.191,0.412-0.288,0.636-0.288c0.224,0,0.536,0.2,0.936,0.601c0.112,0.136,0.271,0.266,0.48,0.39
c0.208,0.124,0.4,0.187,0.576,0.187c0.744,0,1.116-0.305,1.116-0.912c0-0.185-0.102-0.338-0.306-0.462s-0.458-0.214-0.762-0.271
c-0.304-0.056-0.632-0.146-0.984-0.27s-0.68-0.271-0.984-0.438s-0.558-0.434-0.762-0.798c-0.204-0.364-0.306-0.802-0.306-1.313
c0-0.704,0.262-1.318,0.786-1.843c0.524-0.523,1.238-0.786,2.142-0.786c0.48,0,0.918,0.062,1.314,0.187
c0.396,0.124,0.67,0.25,0.822,0.378l0.3,0.228c0.248,0.232,0.372,0.429,0.372,0.589s-0.096,0.38-0.288,0.659
c-0.272,0.4-0.552,0.601-0.84,0.601c-0.168,0-0.376-0.08-0.624-0.24c-0.024-0.016-0.07-0.056-0.138-0.12
c-0.068-0.063-0.13-0.115-0.186-0.156c-0.168-0.104-0.382-0.155-0.642-0.155c-0.26,0-0.476,0.062-0.648,0.186
c-0.172,0.124-0.258,0.296-0.258,0.517c0,0.22,0.102,0.397,0.306,0.533c0.204,0.137,0.458,0.229,0.762,0.276
c0.304,0.048,0.636,0.122,0.996,0.222c0.36,0.101,0.692,0.223,0.996,0.366c0.304,0.145,0.558,0.395,0.762,0.75
c0.204,0.356,0.306,0.794,0.306,1.314c0,0.52-0.104,0.978-0.312,1.374c-0.208,0.396-0.48,0.701-0.816,0.918
c-0.648,0.424-1.34,0.636-2.076,0.636c-0.376,0-0.732-0.046-1.068-0.138c-0.336-0.093-0.608-0.206-0.816-0.343
c-0.424-0.256-0.72-0.504-0.888-0.743L65.227,182.187z"/>
<path class="st2" d="M75.415,181.3h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V181.3z"/>
<path class="st2" d="M90.175,174.759c0.472,0.232,0.708,0.488,0.708,0.768c0,0.129-0.06,0.32-0.18,0.576l-3.312,6.721
c-0.088,0.176-0.222,0.317-0.402,0.426c-0.18,0.107-0.366,0.162-0.558,0.162h-0.12c-0.2,0-0.39-0.055-0.57-0.162
c-0.18-0.108-0.314-0.25-0.402-0.426l-3.312-6.721c-0.12-0.256-0.18-0.447-0.18-0.576c0-0.279,0.236-0.535,0.708-0.768
c0.264-0.136,0.466-0.204,0.606-0.204c0.14,0,0.246,0.017,0.318,0.048c0.072,0.032,0.14,0.089,0.204,0.168
c0.072,0.097,0.138,0.202,0.198,0.318s0.214,0.448,0.462,0.996s0.514,1.13,0.798,1.746c0.284,0.616,0.552,1.198,0.804,1.746
s0.394,0.854,0.426,0.918l2.4-5.256c0.064-0.152,0.12-0.272,0.168-0.36c0.144-0.216,0.32-0.324,0.528-0.324
S89.911,174.624,90.175,174.759z"/>
<path class="st2" d="M94.866,181.3h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V181.3z"/>
<path class="st2" d="M107.281,174.994c0.076-0.141,0.19-0.234,0.342-0.282s0.342-0.072,0.57-0.072c0.228,0,0.412,0.021,0.552,0.061
s0.244,0.088,0.312,0.144s0.118,0.141,0.15,0.252c0.048,0.128,0.072,0.332,0.072,0.612v6.66c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.312,0-0.528-0.024-0.648-0.072
c-0.12-0.048-0.22-0.124-0.3-0.228c-1.8-2.4-2.984-3.968-3.552-4.704v3.948c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.496,0-0.8-0.108-0.912-0.324
c-0.064-0.12-0.102-0.228-0.114-0.324c-0.012-0.096-0.018-0.235-0.018-0.42v-6.695c0-0.305,0.038-0.526,0.114-0.666
c0.076-0.141,0.19-0.234,0.342-0.282s0.348-0.072,0.588-0.072c0.24,0,0.43,0.022,0.57,0.066c0.14,0.044,0.238,0.094,0.294,0.149
c0.032,0.024,0.124,0.129,0.276,0.312c1.688,2.296,2.816,3.812,3.384,4.548v-4.056
C107.166,175.355,107.204,175.134,107.281,174.994z"/>
</g>
<g>
<path class="st2" d="M183.194,181.305h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V181.305z"/>
<path class="st2" d="M189.926,175.689c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624v6.672
c0,0.191-0.006,0.332-0.018,0.42c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612V175.689z"/>
<path class="st2" d="M198.794,178.126h2.112c0.432,0.016,0.696,0.128,0.792,0.336c0.08,0.151,0.12,0.376,0.12,0.672v2.64
c0,0.257-0.112,0.5-0.336,0.732c-0.672,0.696-1.68,1.044-3.024,1.044c-1.192,0-2.228-0.45-3.108-1.351
c-0.88-0.899-1.32-1.985-1.32-3.258c0-1.271,0.448-2.334,1.344-3.186c0.896-0.853,1.952-1.278,3.168-1.278
c0.944,0,1.836,0.312,2.676,0.937c0.216,0.16,0.324,0.338,0.324,0.533c0,0.196-0.092,0.423-0.276,0.679
c-0.312,0.424-0.596,0.636-0.852,0.636c-0.152,0-0.396-0.11-0.732-0.33s-0.736-0.33-1.2-0.33c-0.608,0-1.148,0.214-1.62,0.643
c-0.472,0.428-0.708,0.987-0.708,1.68s0.24,1.28,0.72,1.764c0.48,0.484,1.024,0.727,1.632,0.727c0.44,0,0.836-0.072,1.188-0.217
v-1.308h-0.948c-0.248,0-0.424-0.032-0.528-0.096c-0.104-0.064-0.172-0.158-0.204-0.282c-0.032-0.124-0.048-0.292-0.048-0.504
s0.018-0.382,0.054-0.51s0.102-0.217,0.198-0.265C198.362,178.162,198.554,178.126,198.794,178.126z"/>
<path class="st2" d="M209.414,174.958c0.064-0.12,0.172-0.204,0.324-0.252c0.152-0.049,0.344-0.072,0.576-0.072
s0.416,0.02,0.552,0.06c0.136,0.04,0.24,0.089,0.312,0.145c0.072,0.056,0.128,0.136,0.168,0.24c0.04,0.136,0.06,0.344,0.06,0.624
v6.659c0,0.185-0.006,0.322-0.018,0.414c-0.012,0.093-0.05,0.198-0.114,0.318c-0.112,0.216-0.424,0.324-0.936,0.324
c-0.56,0-0.888-0.148-0.984-0.444c-0.048-0.136-0.072-0.344-0.072-0.624v-2.436h-3.18v2.447c0,0.185-0.006,0.322-0.018,0.414
c-0.012,0.093-0.05,0.198-0.114,0.318c-0.112,0.216-0.424,0.324-0.936,0.324c-0.56,0-0.888-0.148-0.984-0.444
c-0.048-0.136-0.072-0.344-0.072-0.624v-6.66c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624v2.447h3.18v-2.46
c0-0.184,0.006-0.321,0.018-0.414C209.312,175.183,209.35,175.078,209.414,174.958z"/>
<path class="st2" d="M214.142,174.622h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414v-6.024h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C213.674,174.657,213.878,174.622,214.142,174.622z"/>
</g>
<g>
<path class="st2" d="M66.912,198.226c0.076-0.141,0.19-0.234,0.342-0.282s0.342-0.072,0.57-0.072c0.228,0,0.412,0.021,0.552,0.061
s0.244,0.088,0.312,0.144s0.118,0.141,0.15,0.252c0.048,0.128,0.072,0.332,0.072,0.612v6.66c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.312,0-0.528-0.024-0.648-0.072
c-0.12-0.048-0.22-0.124-0.3-0.228c-1.8-2.4-2.984-3.968-3.552-4.704v3.948c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.496,0-0.8-0.108-0.912-0.324
c-0.064-0.12-0.102-0.228-0.114-0.324c-0.012-0.096-0.018-0.235-0.018-0.42v-6.695c0-0.305,0.038-0.526,0.114-0.666
c0.076-0.141,0.19-0.234,0.342-0.282s0.348-0.072,0.588-0.072c0.24,0,0.43,0.022,0.57,0.066c0.14,0.044,0.238,0.094,0.294,0.149
c0.032,0.024,0.124,0.129,0.276,0.312c1.688,2.296,2.816,3.812,3.384,4.548v-4.056C66.798,198.587,66.836,198.365,66.912,198.226z"
/>
<path class="st2" d="M71.07,198.915c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624v6.672
c0,0.191-0.006,0.332-0.018,0.42c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612V198.915z"/>
<path class="st2" d="M81.035,198.226c0.076-0.141,0.19-0.234,0.342-0.282s0.342-0.072,0.57-0.072c0.228,0,0.412,0.021,0.552,0.061
s0.244,0.088,0.312,0.144s0.118,0.141,0.15,0.252c0.048,0.128,0.072,0.332,0.072,0.612v6.66c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.312,0-0.528-0.024-0.648-0.072
c-0.12-0.048-0.22-0.124-0.3-0.228c-1.8-2.4-2.984-3.968-3.552-4.704v3.948c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.496,0-0.8-0.108-0.912-0.324
c-0.064-0.12-0.102-0.228-0.114-0.324c-0.012-0.096-0.018-0.235-0.018-0.42v-6.695c0-0.305,0.038-0.526,0.114-0.666
c0.076-0.141,0.19-0.234,0.342-0.282s0.348-0.072,0.588-0.072c0.24,0,0.43,0.022,0.57,0.066c0.14,0.044,0.238,0.094,0.294,0.149
c0.032,0.024,0.124,0.129,0.276,0.312c1.688,2.296,2.816,3.812,3.384,4.548v-4.056C80.921,198.587,80.959,198.365,81.035,198.226z"
/>
<path class="st2" d="M87.317,204.531h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V204.531z"/>
</g>
<g>
<path class="st2" d="M199.485,197.854h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414v-6.024h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C199.017,197.889,199.221,197.854,199.485,197.854z"/>
<path class="st2" d="M211.005,204.537h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V204.537z"/>
<path class="st2" d="M223.419,198.232c0.076-0.141,0.19-0.234,0.342-0.282s0.342-0.072,0.57-0.072c0.228,0,0.412,0.021,0.552,0.061
s0.244,0.088,0.312,0.144s0.118,0.141,0.15,0.252c0.048,0.128,0.072,0.332,0.072,0.612v6.66c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.312,0-0.528-0.024-0.648-0.072
c-0.12-0.048-0.22-0.124-0.3-0.228c-1.8-2.4-2.984-3.968-3.552-4.704v3.948c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.496,0-0.8-0.108-0.912-0.324
c-0.064-0.12-0.102-0.228-0.114-0.324c-0.012-0.096-0.018-0.235-0.018-0.42v-6.695c0-0.305,0.038-0.526,0.114-0.666
c0.076-0.141,0.19-0.234,0.342-0.282s0.348-0.072,0.588-0.072c0.24,0,0.43,0.022,0.57,0.066c0.14,0.044,0.238,0.094,0.294,0.149
c0.032,0.024,0.124,0.129,0.276,0.312c1.688,2.296,2.816,3.812,3.384,4.548v-4.056
C223.305,198.593,223.343,198.371,223.419,198.232z"/>
</g>
<g>
<path class="st2" d="M118.73,204.568h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V204.568z"/>
<path class="st2" d="M127.586,204.915h3.264c0.264,0,0.456,0.03,0.576,0.091c0.12,0.06,0.2,0.153,0.24,0.281s0.06,0.299,0.06,0.511
s-0.02,0.382-0.06,0.51s-0.108,0.216-0.204,0.264c-0.152,0.08-0.36,0.12-0.624,0.12h-4.32c-0.56,0-0.888-0.152-0.984-0.456
c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624V204.915z"/>
<path class="st2" d="M135.829,204.568h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V204.568z"/>
<path class="st2" d="M150.589,198.028c0.472,0.232,0.708,0.488,0.708,0.768c0,0.129-0.06,0.32-0.18,0.576l-3.312,6.721
c-0.088,0.176-0.222,0.317-0.402,0.426c-0.18,0.107-0.366,0.162-0.558,0.162h-0.12c-0.2,0-0.39-0.055-0.57-0.162
c-0.18-0.108-0.314-0.25-0.402-0.426l-3.312-6.721c-0.12-0.256-0.18-0.447-0.18-0.576c0-0.279,0.236-0.535,0.708-0.768
c0.264-0.136,0.466-0.204,0.606-0.204c0.14,0,0.246,0.017,0.318,0.048c0.072,0.032,0.14,0.089,0.204,0.168
c0.072,0.097,0.138,0.202,0.198,0.318s0.214,0.448,0.462,0.996s0.514,1.13,0.798,1.746c0.284,0.616,0.552,1.198,0.804,1.746
s0.394,0.854,0.426,0.918l2.4-5.256c0.064-0.152,0.12-0.272,0.168-0.36c0.144-0.216,0.32-0.324,0.528-0.324
S150.325,197.892,150.589,198.028z"/>
<path class="st2" d="M155.281,204.568h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V204.568z"/>
<path class="st2" d="M167.695,198.262c0.076-0.141,0.19-0.234,0.342-0.282s0.342-0.072,0.57-0.072c0.228,0,0.412,0.021,0.552,0.061
s0.244,0.088,0.312,0.144s0.118,0.141,0.15,0.252c0.048,0.128,0.072,0.332,0.072,0.612v6.66c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.312,0-0.528-0.024-0.648-0.072
c-0.12-0.048-0.22-0.124-0.3-0.228c-1.8-2.4-2.984-3.968-3.552-4.704v3.948c0,0.191-0.006,0.332-0.018,0.42
c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324c-0.496,0-0.8-0.108-0.912-0.324
c-0.064-0.12-0.102-0.228-0.114-0.324c-0.012-0.096-0.018-0.235-0.018-0.42v-6.695c0-0.305,0.038-0.526,0.114-0.666
c0.076-0.141,0.19-0.234,0.342-0.282s0.348-0.072,0.588-0.072c0.24,0,0.43,0.022,0.57,0.066c0.14,0.044,0.238,0.094,0.294,0.149
c0.032,0.024,0.124,0.129,0.276,0.312c1.688,2.296,2.816,3.812,3.384,4.548v-4.056
C167.581,198.623,167.619,198.402,167.695,198.262z"/>
</g>
<g>
<path class="st2" d="M164.878,220.996c1.184,0,2.212,0.429,3.084,1.284c0.872,0.856,1.308,1.918,1.308,3.187
c0,1.268-0.416,2.348-1.248,3.239c-0.832,0.893-1.856,1.338-3.072,1.338c-1.216,0-2.25-0.439-3.102-1.319s-1.278-1.928-1.278-3.145
c0-0.664,0.12-1.285,0.36-1.865c0.24-0.58,0.56-1.066,0.96-1.458c0.4-0.393,0.86-0.7,1.38-0.925
C163.79,221.108,164.326,220.996,164.878,220.996z M162.694,225.52c0,0.712,0.23,1.29,0.69,1.733
c0.46,0.444,0.974,0.666,1.542,0.666c0.568,0,1.08-0.216,1.536-0.647s0.684-1.012,0.684-1.74c0-0.728-0.23-1.312-0.69-1.752
c-0.46-0.439-0.974-0.66-1.542-0.66c-0.568,0-1.08,0.223-1.536,0.666C162.922,224.23,162.694,224.808,162.694,225.52z"/>
<path class="st2" d="M173.11,221.356c0.136,0.136,0.204,0.368,0.204,0.696v0.191c0,0.2-0.008,0.349-0.024,0.444
c-0.056,0.704-0.264,1.308-0.624,1.812s-0.816,0.757-1.368,0.757c-0.056,0-0.106-0.042-0.15-0.126s-0.066-0.194-0.066-0.33
c0-0.137,0.018-0.242,0.054-0.318c0.036-0.076,0.076-0.12,0.12-0.132s0.078-0.021,0.102-0.024s0.068-0.023,0.132-0.06
c0.064-0.036,0.12-0.086,0.168-0.15c0.128-0.168,0.2-0.428,0.216-0.78c-0.272-0.039-0.474-0.127-0.606-0.264
c-0.132-0.136-0.198-0.424-0.198-0.864c0-0.319,0.04-0.558,0.12-0.714c0.08-0.155,0.202-0.26,0.366-0.312
c0.164-0.052,0.418-0.078,0.762-0.078C172.662,221.104,172.925,221.188,173.11,221.356z"/>
<path class="st2" d="M180.79,227.596l0.216-0.156c0.272-0.16,0.464-0.24,0.576-0.24c0.248,0,0.516,0.225,0.804,0.672
c0.176,0.28,0.264,0.504,0.264,0.672s-0.054,0.309-0.162,0.421c-0.108,0.111-0.234,0.212-0.378,0.3s-0.282,0.172-0.414,0.252
c-0.132,0.08-0.402,0.184-0.81,0.312c-0.408,0.128-0.802,0.192-1.182,0.192c-0.38,0-0.764-0.05-1.152-0.15
c-0.388-0.1-0.788-0.268-1.2-0.504c-0.412-0.235-0.782-0.523-1.11-0.864c-0.328-0.34-0.598-0.775-0.81-1.308
c-0.212-0.532-0.318-1.11-0.318-1.734s0.104-1.189,0.312-1.697s0.474-0.929,0.798-1.261c0.324-0.331,0.694-0.609,1.11-0.834
c0.784-0.432,1.572-0.647,2.364-0.647c0.376,0,0.758,0.058,1.146,0.174c0.388,0.116,0.682,0.234,0.882,0.354l0.288,0.168
c0.144,0.088,0.256,0.16,0.336,0.216c0.208,0.168,0.312,0.357,0.312,0.569c0,0.213-0.084,0.435-0.252,0.666
c-0.312,0.433-0.592,0.648-0.84,0.648c-0.144,0-0.348-0.088-0.612-0.264c-0.336-0.272-0.784-0.408-1.344-0.408
c-0.52,0-1.032,0.18-1.536,0.54c-0.24,0.176-0.44,0.424-0.6,0.744c-0.16,0.319-0.24,0.682-0.24,1.086
c0,0.403,0.08,0.766,0.24,1.086c0.16,0.32,0.364,0.572,0.612,0.756c0.488,0.353,0.996,0.528,1.524,0.528
c0.248,0,0.482-0.032,0.702-0.097C180.536,227.724,180.694,227.66,180.79,227.596z"/>
<path class="st2" d="M186.765,228.124h3.264c0.264,0,0.456,0.03,0.576,0.091c0.12,0.06,0.2,0.153,0.24,0.281s0.06,0.299,0.06,0.511
s-0.02,0.382-0.06,0.51s-0.108,0.216-0.204,0.264c-0.152,0.08-0.36,0.12-0.624,0.12h-4.32c-0.56,0-0.888-0.152-0.984-0.456
c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624V228.124z"/>
<path class="st2" d="M197.013,220.996c1.184,0,2.212,0.429,3.084,1.284c0.872,0.856,1.308,1.918,1.308,3.187
c0,1.268-0.416,2.348-1.248,3.239c-0.832,0.893-1.856,1.338-3.072,1.338c-1.216,0-2.25-0.439-3.102-1.319s-1.278-1.928-1.278-3.145
c0-0.664,0.12-1.285,0.36-1.865c0.24-0.58,0.56-1.066,0.96-1.458c0.4-0.393,0.86-0.7,1.38-0.925
C195.925,221.108,196.462,220.996,197.013,220.996z M194.829,225.52c0,0.712,0.23,1.29,0.69,1.733
c0.46,0.444,0.974,0.666,1.542,0.666c0.568,0,1.08-0.216,1.536-0.647s0.684-1.012,0.684-1.74c0-0.728-0.23-1.312-0.69-1.752
c-0.46-0.439-0.974-0.66-1.542-0.66c-0.568,0-1.08,0.223-1.536,0.666C195.057,224.23,194.829,224.808,194.829,225.52z"/>
<path class="st2" d="M208.882,227.596l0.216-0.156c0.272-0.16,0.464-0.24,0.576-0.24c0.248,0,0.516,0.225,0.804,0.672
c0.176,0.28,0.264,0.504,0.264,0.672s-0.054,0.309-0.162,0.421c-0.108,0.111-0.234,0.212-0.378,0.3s-0.282,0.172-0.414,0.252
c-0.132,0.08-0.402,0.184-0.81,0.312c-0.408,0.128-0.802,0.192-1.182,0.192c-0.38,0-0.764-0.05-1.152-0.15
c-0.388-0.1-0.788-0.268-1.2-0.504c-0.412-0.235-0.782-0.523-1.11-0.864c-0.328-0.34-0.598-0.775-0.81-1.308
c-0.212-0.532-0.318-1.11-0.318-1.734s0.104-1.189,0.312-1.697s0.474-0.929,0.798-1.261c0.324-0.331,0.694-0.609,1.11-0.834
c0.784-0.432,1.572-0.647,2.364-0.647c0.376,0,0.758,0.058,1.146,0.174c0.388,0.116,0.682,0.234,0.882,0.354l0.288,0.168
c0.144,0.088,0.256,0.16,0.336,0.216c0.208,0.168,0.312,0.357,0.312,0.569c0,0.213-0.084,0.435-0.252,0.666
c-0.312,0.433-0.592,0.648-0.84,0.648c-0.144,0-0.348-0.088-0.612-0.264c-0.336-0.272-0.784-0.408-1.344-0.408
c-0.52,0-1.032,0.18-1.536,0.54c-0.24,0.176-0.44,0.424-0.6,0.744c-0.16,0.319-0.24,0.682-0.24,1.086
c0,0.403,0.08,0.766,0.24,1.086c0.16,0.32,0.364,0.572,0.612,0.756c0.488,0.353,0.996,0.528,1.524,0.528
c0.248,0,0.482-0.032,0.702-0.097C208.628,227.724,208.785,227.66,208.882,227.596z"/>
<path class="st2" d="M216.501,225.484c1.224,1.176,2.092,2.061,2.604,2.652c0.264,0.296,0.396,0.546,0.396,0.75
s-0.16,0.443-0.48,0.72c-0.32,0.276-0.582,0.414-0.786,0.414s-0.45-0.168-0.738-0.504l-2.64-3.013v2.341
c0,0.191-0.006,0.332-0.018,0.42c-0.012,0.088-0.05,0.191-0.114,0.312c-0.112,0.216-0.424,0.324-0.936,0.324
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.184,0.006-0.321,0.018-0.414
c0.012-0.092,0.05-0.197,0.114-0.317c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444
c0.04,0.136,0.06,0.344,0.06,0.624v2.292c1.088-1.225,1.968-2.229,2.64-3.013c0.28-0.328,0.524-0.492,0.732-0.492
s0.472,0.139,0.792,0.414c0.32,0.276,0.48,0.517,0.48,0.721s-0.12,0.445-0.36,0.726c-0.464,0.536-1.184,1.272-2.16,2.208
L216.501,225.484z"/>
</g>
<g>
<path class="st2" d="M71.187,221.128h6.672c0.256,0,0.444,0.029,0.564,0.09c0.12,0.06,0.2,0.154,0.24,0.282
c0.04,0.128,0.06,0.296,0.06,0.504s-0.02,0.374-0.06,0.498c-0.041,0.124-0.108,0.21-0.204,0.258
c-0.144,0.072-0.348,0.107-0.612,0.107h-2.292v6.036c0,0.185-0.006,0.32-0.018,0.408c-0.012,0.088-0.048,0.19-0.108,0.306
c-0.06,0.116-0.166,0.198-0.318,0.246s-0.352,0.072-0.6,0.072s-0.446-0.024-0.594-0.072c-0.148-0.048-0.252-0.13-0.312-0.246
c-0.06-0.115-0.096-0.22-0.108-0.312c-0.012-0.092-0.018-0.23-0.018-0.414v-6.024h-2.304c-0.256,0-0.444-0.029-0.564-0.09
c-0.12-0.06-0.2-0.153-0.24-0.282c-0.041-0.128-0.06-0.296-0.06-0.504s0.02-0.374,0.06-0.498c0.04-0.124,0.108-0.21,0.204-0.258
C70.719,221.163,70.923,221.128,71.187,221.128z"/>
<path class="st2" d="M91.106,221.188c0.536,0.192,0.804,0.448,0.804,0.768c0,0.104-0.048,0.301-0.144,0.589l-2.304,6.659
c-0.016,0.057-0.044,0.125-0.084,0.204c-0.04,0.08-0.146,0.187-0.318,0.318c-0.172,0.132-0.376,0.198-0.612,0.198
c-0.236,0-0.44-0.066-0.612-0.198s-0.286-0.262-0.342-0.39l-1.404-4.141c-0.888,2.624-1.34,3.96-1.356,4.008
c-0.016,0.049-0.052,0.116-0.108,0.204c-0.056,0.089-0.12,0.168-0.192,0.24c-0.184,0.185-0.404,0.276-0.66,0.276
s-0.466-0.061-0.63-0.181c-0.164-0.119-0.274-0.239-0.33-0.359l-0.084-0.181l-2.316-6.659c-0.088-0.265-0.132-0.46-0.132-0.589
c0-0.319,0.268-0.571,0.804-0.756c0.232-0.079,0.442-0.12,0.63-0.12s0.332,0.064,0.432,0.192s0.19,0.324,0.27,0.588l1.32,4.008
l1.308-3.947c0.112-0.336,0.316-0.568,0.612-0.696c0.128-0.056,0.294-0.084,0.498-0.084c0.204,0,0.394,0.065,0.57,0.198
c0.176,0.132,0.288,0.262,0.336,0.39l1.38,4.164l1.32-4.032c0.064-0.184,0.116-0.319,0.156-0.408
c0.04-0.088,0.114-0.174,0.222-0.258s0.242-0.126,0.402-0.126S90.891,221.108,91.106,221.188z"/>
<path class="st2" d="M95.895,227.812h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V227.812z"/>
<path class="st2" d="M104.75,228.159h3.264c0.264,0,0.456,0.03,0.576,0.091c0.12,0.06,0.2,0.153,0.24,0.281s0.06,0.299,0.06,0.511
s-0.02,0.382-0.06,0.51s-0.108,0.216-0.204,0.264c-0.152,0.08-0.36,0.12-0.624,0.12h-4.32c-0.56,0-0.888-0.152-0.984-0.456
c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.184,0.006-0.321,0.018-0.414c0.012-0.092,0.05-0.197,0.114-0.317
c0.112-0.217,0.424-0.324,0.936-0.324c0.56,0,0.892,0.148,0.996,0.444c0.04,0.136,0.06,0.344,0.06,0.624V228.159z"/>
<path class="st2" d="M118.898,221.272c0.472,0.232,0.708,0.488,0.708,0.768c0,0.129-0.06,0.32-0.18,0.576l-3.312,6.721
c-0.088,0.176-0.222,0.317-0.402,0.426c-0.18,0.107-0.366,0.162-0.558,0.162h-0.12c-0.2,0-0.39-0.055-0.57-0.162
c-0.18-0.108-0.314-0.25-0.402-0.426l-3.312-6.721c-0.12-0.256-0.18-0.447-0.18-0.576c0-0.279,0.236-0.535,0.708-0.768
c0.264-0.136,0.466-0.204,0.606-0.204c0.14,0,0.246,0.017,0.318,0.048c0.072,0.032,0.14,0.089,0.204,0.168
c0.072,0.097,0.138,0.202,0.198,0.318s0.214,0.448,0.462,0.996s0.514,1.13,0.798,1.746c0.284,0.616,0.552,1.198,0.804,1.746
s0.394,0.854,0.426,0.918l2.4-5.256c0.064-0.152,0.12-0.272,0.168-0.36c0.144-0.216,0.32-0.324,0.528-0.324
S118.634,221.136,118.898,221.272z"/>
<path class="st2" d="M123.59,227.812h3.696c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-4.752
c-0.56,0-0.888-0.152-0.984-0.456c-0.048-0.128-0.072-0.332-0.072-0.612v-6.672c0-0.408,0.076-0.686,0.228-0.834
c0.152-0.147,0.44-0.222,0.864-0.222h4.728c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114
c0.216,0.112,0.324,0.424,0.324,0.937c0,0.56-0.148,0.888-0.444,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-3.684v1.212h2.376
c0.184,0,0.322,0.006,0.414,0.018c0.092,0.013,0.198,0.051,0.318,0.114c0.216,0.112,0.324,0.424,0.324,0.937
c0,0.56-0.152,0.888-0.456,0.983c-0.136,0.048-0.344,0.072-0.624,0.072h-2.352V227.812z"/>
</g>
<g>
<path d="M131.993,13.583c-0.875-0.408-1.248-1.08-1.248-1.751c0-1.235,1.043-2.075,2.423-2.075c1.511,0,2.279,0.936,2.279,1.919
c0,0.66-0.336,1.379-1.295,1.823v0.036c0.972,0.384,1.571,1.08,1.571,2.015c0,1.367-1.164,2.267-2.651,2.267
c-1.631,0-2.614-0.959-2.614-2.099c0-0.983,0.587-1.691,1.547-2.099L131.993,13.583z M134.656,15.657
c0-0.936-0.66-1.403-1.715-1.703c-0.911,0.264-1.403,0.875-1.403,1.619c-0.036,0.78,0.564,1.475,1.56,1.475
C134.044,17.048,134.656,16.461,134.656,15.657z M131.753,11.759c-0.012,0.78,0.587,1.199,1.487,1.439
c0.672-0.228,1.188-0.708,1.188-1.416c0-0.624-0.372-1.271-1.319-1.271C132.233,10.512,131.753,11.088,131.753,11.759z"/>
<path d="M141.903,13.702c0,2.651-0.996,4.114-2.71,4.114c-1.523,0-2.567-1.427-2.591-4.006c0-2.626,1.14-4.054,2.723-4.054
C140.955,9.756,141.903,11.22,141.903,13.702z M137.669,13.822c0,2.027,0.624,3.178,1.583,3.178c1.067,0,1.583-1.259,1.583-3.25
c0-1.919-0.48-3.178-1.583-3.178C138.341,10.572,137.669,11.699,137.669,13.822z"/>
<path d="M143.201,13.45c0-0.611-0.024-1.091-0.048-1.571h0.923l0.048,0.947h0.036c0.324-0.552,0.864-1.067,1.835-1.067
c0.779,0,1.379,0.48,1.631,1.164h0.023c0.181-0.336,0.42-0.576,0.66-0.756c0.348-0.264,0.72-0.408,1.271-0.408
c0.779,0,1.919,0.504,1.919,2.519v3.406h-1.032V14.41c0-1.127-0.419-1.787-1.259-1.787c-0.611,0-1.067,0.443-1.26,0.947
c-0.048,0.156-0.084,0.336-0.084,0.528v3.586h-1.031v-3.478c0-0.923-0.407-1.583-1.211-1.583c-0.648,0-1.14,0.527-1.308,1.055
c-0.06,0.144-0.084,0.336-0.084,0.516v3.49h-1.031V13.45z"/>
<path d="M153.21,13.45c0-0.611-0.024-1.091-0.049-1.571h0.924l0.048,0.947h0.036c0.324-0.552,0.863-1.067,1.835-1.067
c0.779,0,1.379,0.48,1.631,1.164h0.024c0.18-0.336,0.42-0.576,0.659-0.756c0.348-0.264,0.72-0.408,1.271-0.408
c0.779,0,1.919,0.504,1.919,2.519v3.406h-1.031V14.41c0-1.127-0.42-1.787-1.26-1.787c-0.611,0-1.067,0.443-1.259,0.947
c-0.048,0.156-0.084,0.336-0.084,0.528v3.586h-1.031v-3.478c0-0.923-0.408-1.583-1.212-1.583c-0.647,0-1.139,0.527-1.307,1.055
c-0.061,0.144-0.084,0.336-0.084,0.516v3.49h-1.031V13.45z"/>
</g>
<line class="st3" x1="31.102" y1="20.469" x2="31.102" y2="9.225"/>
<line class="st3" x1="257.874" y1="20.469" x2="257.874" y2="9.225"/>
<line class="st3" x1="257.874" y1="14.847" x2="165.853" y2="14.847"/>
<line class="st3" x1="123.888" y1="14.847" x2="31.102" y2="14.847"/>
</svg>

After

Width:  |  Height:  |  Size: 82 KiB

View File

@@ -0,0 +1,305 @@
#include "wled.h"
/*
* This v1 usermod file allows you to add own functionality to WLED more easily
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
* If you just need 8 bytes, use 2551-2559 (you do not need to increase EEPSIZE)
*
* Consider the v2 usermod API if you need a more advanced feature set!
*/
uint8_t minuteLast = 99;
int dayBrightness = 128;
int nightBrightness = 16;
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
//gets called once at boot. Do all initialization that doesn't depend on network here
void userSetup()
{
saveMacro(14, "A=128", false);
saveMacro(15, "A=64", false);
saveMacro(16, "A=16", false);
saveMacro(1, "&FX=0&R=255&G=255&B=255", false);
//strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
//select first two segments (background color + FX settable)
WS2812FX::Segment &seg = strip.getSegment(0);
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((0 & 0xFF) << 8) | ((0 & 0xFF)));
strip.getSegment(0).setOption(0, false);
strip.getSegment(0).setOption(2, false);
//other segments are text
for (int i = 1; i < 10; i++)
{
WS2812FX::Segment &seg = strip.getSegment(i);
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF)));
strip.getSegment(i).setOption(0, true);
strip.setBrightness(128);
}
}
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
void userConnected()
{
}
void selectWordSegments(bool state)
{
for (int i = 1; i < 10; i++)
{
//WS2812FX::Segment &seg = strip.getSegment(i);
strip.getSegment(i).setOption(0, state);
// strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
//seg.mode = 12;
//seg.palette = 1;
//strip.setBrightness(255);
}
strip.getSegment(0).setOption(0, !state);
}
void hourChime()
{
//strip.resetSegments();
selectWordSegments(true);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
savePreset(13, false);
selectWordSegments(false);
//strip.getSegment(0).setOption(0, true);
strip.getSegment(0).setOption(2, true);
applyPreset(12);
colorUpdated(NOTIFIER_CALL_MODE_FX_CHANGED);
}
void displayTime(byte hour, byte minute)
{
bool isToHour = false; //true if minute > 30
strip.setSegment(0, 0, 64); // background
strip.setSegment(1, 0, 2); //It is
strip.setSegment(2, 0, 0);
strip.setSegment(3, 0, 0); //disable minutes
strip.setSegment(4, 0, 0); //past
strip.setSegment(6, 0, 0); //to
strip.setSegment(8, 0, 0); //disable o'clock
if (hour < 24) //valid time, display
{
if (minute == 30)
{
strip.setSegment(2, 3, 6); //half
strip.setSegment(3, 0, 0); //minutes
}
else if (minute == 15 || minute == 45)
{
strip.setSegment(3, 0, 0); //minutes
}
else if (minute == 10)
{
//strip.setSegment(5, 6, 8); //ten
}
else if (minute == 5)
{
//strip.setSegment(5, 16, 18); //five
}
else if (minute == 0)
{
strip.setSegment(3, 0, 0); //minutes
//hourChime();
}
else
{
strip.setSegment(3, 18, 22); //minutes
}
//past or to?
if (minute == 0)
{ //full hour
strip.setSegment(3, 0, 0); //disable minutes
strip.setSegment(4, 0, 0); //disable past
strip.setSegment(6, 0, 0); //disable to
strip.setSegment(8, 60, 64); //o'clock
}
else if (minute > 34)
{
//strip.setSegment(6, 22, 24); //to
//minute = 60 - minute;
isToHour = true;
}
else
{
//strip.setSegment(4, 24, 27); //past
//isToHour = false;
}
}
else
{ //temperature display
}
//byte minuteRem = minute %10;
if (minute <= 4)
{
strip.setSegment(3, 0, 0); //nothing
strip.setSegment(5, 0, 0); //nothing
strip.setSegment(6, 0, 0); //nothing
strip.setSegment(8, 60, 64); //o'clock
}
else if (minute <= 9)
{
strip.setSegment(5, 16, 18); // five past
strip.setSegment(4, 24, 27); //past
}
else if (minute <= 14)
{
strip.setSegment(5, 6, 8); // ten past
strip.setSegment(4, 24, 27); //past
}
else if (minute <= 19)
{
strip.setSegment(5, 8, 12); // quarter past
strip.setSegment(3, 0, 0); //minutes
strip.setSegment(4, 24, 27); //past
}
else if (minute <= 24)
{
strip.setSegment(5, 12, 16); // twenty past
strip.setSegment(4, 24, 27); //past
}
else if (minute <= 29)
{
strip.setSegment(5, 12, 18); // twenty-five past
strip.setSegment(4, 24, 27); //past
}
else if (minute <= 34)
{
strip.setSegment(5, 3, 6); // half past
strip.setSegment(3, 0, 0); //minutes
strip.setSegment(4, 24, 27); //past
}
else if (minute <= 39)
{
strip.setSegment(5, 12, 18); // twenty-five to
strip.setSegment(6, 22, 24); //to
}
else if (minute <= 44)
{
strip.setSegment(5, 12, 16); // twenty to
strip.setSegment(6, 22, 24); //to
}
else if (minute <= 49)
{
strip.setSegment(5, 8, 12); // quarter to
strip.setSegment(3, 0, 0); //minutes
strip.setSegment(6, 22, 24); //to
}
else if (minute <= 54)
{
strip.setSegment(5, 6, 8); // ten to
strip.setSegment(6, 22, 24); //to
}
else if (minute <= 59)
{
strip.setSegment(5, 16, 18); // five to
strip.setSegment(6, 22, 24); //to
}
//hours
if (hour > 23)
return;
if (isToHour)
hour++;
if (hour > 12)
hour -= 12;
if (hour == 0)
hour = 12;
switch (hour)
{
case 1:
strip.setSegment(7, 27, 29);
break; //one
case 2:
strip.setSegment(7, 35, 37);
break; //two
case 3:
strip.setSegment(7, 29, 32);
break; //three
case 4:
strip.setSegment(7, 32, 35);
break; //four
case 5:
strip.setSegment(7, 37, 40);
break; //five
case 6:
strip.setSegment(7, 43, 45);
break; //six
case 7:
strip.setSegment(7, 40, 43);
break; //seven
case 8:
strip.setSegment(7, 45, 48);
break; //eight
case 9:
strip.setSegment(7, 48, 50);
break; //nine
case 10:
strip.setSegment(7, 54, 56);
break; //ten
case 11:
strip.setSegment(7, 50, 54);
break; //eleven
case 12:
strip.setSegment(7, 56, 60);
break; //twelve
}
selectWordSegments(true);
applyMacro(1);
}
void timeOfDay() {
// NOT USED: use timed macros instead
//Used to set brightness dependant of time of day - lights dimmed at night
//monday to thursday and sunday
if ((weekday(localTime) == 6) | (weekday(localTime) == 7)) {
if (hour(localTime) > 0 | hour(localTime) < 8) {
strip.setBrightness(nightBrightness);
}
else {
strip.setBrightness(dayBrightness);
}
}
else {
if (hour(localTime) < 6 | hour(localTime) >= 22) {
strip.setBrightness(nightBrightness);
}
else {
strip.setBrightness(dayBrightness);
}
}
}
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
void userLoop()
{
if (minute(localTime) != minuteLast)
{
updateLocalTime();
//timeOfDay();
minuteLast = minute(localTime);
displayTime(hour(localTime), minute(localTime));
if (minute(localTime) == 0){
hourChime();
}
if (minute(localTime) == 1){
//turn off background segment;
strip.getSegment(0).setOption(2, false);
//applyPreset(13);
}
}
}

View File

@@ -778,6 +778,7 @@ uint16_t WS2812FX::mode_chase_random(void) {
*/
uint16_t WS2812FX::mode_chase_rainbow(void) {
uint8_t color_sep = 256 / SEGLEN;
if (color_sep == 0) color_sep = 1; // correction for segments longer than 256 LEDs
uint8_t color_index = SEGENV.call & 0xFF;
uint32_t color = color_wheel(((SEGENV.step * color_sep) + color_index) & 0xFF);
@@ -802,46 +803,40 @@ uint16_t WS2812FX::mode_chase_rainbow_white(void) {
* Red - Amber - Green - Blue lights running
*/
uint16_t WS2812FX::mode_colorful(void) {
uint32_t cols[]{0x00FF0000,0x00EEBB00,0x0000EE00,0x000077CC,0x00FF0000,0x00EEBB00,0x0000EE00};
if (SEGMENT.intensity < 127) //pastel (easter) colors
uint8_t numColors = 4; //3, 4, or 5
uint32_t cols[9]{0x00FF0000,0x00EEBB00,0x0000EE00,0x000077CC};
if (SEGMENT.intensity > 160 || SEGMENT.palette) { //palette or color
if (!SEGMENT.palette) {
numColors = 3;
for (uint8_t i = 0; i < 3; i++) cols[i] = SEGCOLOR(i);
} else {
uint16_t fac = 80;
if (SEGMENT.palette == 52) {numColors = 5; fac = 61;} //C9 2 has 5 colors
for (uint8_t i = 0; i < numColors; i++) {
cols[i] = color_from_palette(i*fac, false, true, 255);
}
}
} else if (SEGMENT.intensity < 80) //pastel (easter) colors
{
cols[0] = 0x00FF8040;
cols[1] = 0x00E5D241;
cols[2] = 0x0077FF77;
cols[3] = 0x0077F0F0;
for (uint8_t i = 4; i < 7; i++) cols[i] = cols[i-4];
}
for (uint8_t i = numColors; i < numColors*2 -1; i++) cols[i] = cols[i-numColors];
uint32_t cycleTime = 50 + (15 * (uint32_t)(255 - SEGMENT.speed));
uint32_t cycleTime = 50 + (8 * (uint32_t)(255 - SEGMENT.speed));
uint32_t it = now / cycleTime;
if (it != SEGENV.step)
{
if (SEGMENT.speed > 0) SEGENV.aux0++;
if (SEGENV.aux0 > 3) SEGENV.aux0 = 0;
if (SEGENV.aux0 >= numColors) SEGENV.aux0 = 0;
SEGENV.step = it;
}
uint16_t i = 0;
for (i; i < SEGLEN -3; i+=4)
for (uint16_t i = 0; i < SEGLEN; i+= numColors)
{
setPixelColor(i, cols[SEGENV.aux0]);
setPixelColor(i+1, cols[SEGENV.aux0+1]);
setPixelColor(i+2, cols[SEGENV.aux0+2]);
setPixelColor(i+3, cols[SEGENV.aux0+3]);
}
if(i < SEGLEN)
{
setPixelColor(i, cols[SEGENV.aux0]);
if(i+1 < SEGLEN)
{
setPixelColor(i+1, cols[SEGENV.aux0+1]);
if(i+2 < SEGLEN)
{
setPixelColor(i+2, cols[SEGENV.aux0+2]);
}
}
for (uint16_t j = 0; j < numColors; j++) setPixelColor(i + j, cols[SEGENV.aux0 + j]);
}
return FRAMETIME;
@@ -869,6 +864,7 @@ uint16_t WS2812FX::mode_traffic_light(void) {
if (now - SEGENV.step > mdelay)
{
SEGENV.aux0++;
if (SEGENV.aux0 == 1 && SEGMENT.intensity > 140) SEGENV.aux0 = 2; //skip Red + Amber, to get US-style sequence
if (SEGENV.aux0 > 3) SEGENV.aux0 = 0;
SEGENV.step = now;
}
@@ -1133,12 +1129,12 @@ uint16_t WS2812FX::mode_rain()
SEGENV.step += FRAMETIME;
if (SEGENV.step > SPEED_FORMULA_L) {
SEGENV.step = 0;
//shift all leds right
uint32_t ctemp = getPixelColor(SEGLEN -1);
for(uint16_t i = SEGLEN -1; i > 0; i--) {
setPixelColor(i, getPixelColor(i-1));
//shift all leds left
uint32_t ctemp = getPixelColor(0);
for(uint16_t i = 0; i < SEGLEN - 1; i++) {
setPixelColor(i, getPixelColor(i+1));
}
setPixelColor(0, ctemp);
setPixelColor(SEGLEN -1, ctemp);
SEGENV.aux0++;
SEGENV.aux1++;
if (SEGENV.aux0 == 0) SEGENV.aux0 = UINT16_MAX;
@@ -1598,7 +1594,7 @@ uint16_t WS2812FX::mode_oscillate(void)
uint16_t WS2812FX::mode_lightning(void)
{
uint16_t ledstart = random16(SEGLEN); // Determine starting location of flash
uint16_t ledlen = random16(SEGLEN -1 -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1)
uint16_t ledlen = 1 + random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1)
uint8_t bri = 255/random8(1, 3);
if (SEGENV.step == 0)
@@ -2246,7 +2242,7 @@ uint16_t WS2812FX::mode_ripple_rainbow(void) {
CRGB WS2812FX::twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat)
{
// Overall twinkle speed (changed)
uint16_t ticks = ms / (32 - (SEGMENT.speed >> 3));
uint16_t ticks = ms / SEGENV.aux0;
uint8_t fastcycle8 = ticks;
uint16_t slowcycle16 = (ticks >> 8) + salt;
slowcycle16 += sin8(slowcycle16);
@@ -2311,10 +2307,11 @@ uint16_t WS2812FX::twinklefox_base(bool cat)
// numbers that it generates is (paradoxically) stable.
uint16_t PRNG16 = 11337;
// Calculate speed
if (SEGMENT.speed > 100) SEGENV.aux0 = 3 + ((255 - SEGMENT.speed) >> 3);
else SEGENV.aux0 = 22 + ((100 - SEGMENT.speed) >> 1);
// Set up the background color, "bg".
// if AUTO_SELECT_BACKGROUND_COLOR == 1, and the first two colors of
// the current palette are identical, then a deeply faded version of
// that color is used for the background color
CRGB bg;
bg = col_to_crgb(SEGCOLOR(1));
uint8_t bglight = bg.getAverageLight();
@@ -2730,7 +2727,7 @@ uint16_t WS2812FX::candle(bool multi)
//max. flicker range controlled by intensity
uint8_t valrange = SEGMENT.intensity;
uint8_t rndval = valrange >> 1;
uint8_t rndval = valrange >> 1; //max 127
//step (how much to move closer to target per frame) coarsely set by speed
uint8_t speedFactor = 4;
@@ -2767,9 +2764,9 @@ uint16_t WS2812FX::candle(bool multi)
}
if (newTarget) {
s_target = random8(rndval) + random8(rndval);
s_target = random8(rndval) + random8(rndval); //between 0 and rndval*2 -2 = 252
if (s_target < (rndval >> 1)) s_target = (rndval >> 1) + random8(rndval);
uint8_t offset = (255 - valrange) >> 1;
uint8_t offset = (255 - valrange);
s_target += offset;
uint8_t dif = (s_target > s) ? s_target - s : s - s_target;
@@ -3238,6 +3235,8 @@ uint16_t WS2812FX::mode_heartbeat(void) {
//
uint16_t WS2812FX::mode_pacifica()
{
uint32_t nowOld = now;
CRGBPalette16 pacifica_palette_1 =
{ 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117,
0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50 };
@@ -3258,8 +3257,11 @@ uint16_t WS2812FX::mode_pacifica()
// Each is incremented at a different speed, and the speeds vary over time.
uint16_t sCIStart1 = SEGENV.aux0, sCIStart2 = SEGENV.aux1, sCIStart3 = SEGENV.step, sCIStart4 = SEGENV.step >> 16;
//static uint16_t sCIStart1, sCIStart2, sCIStart3, sCIStart4;
uint32_t deltams = 26 + (SEGMENT.speed >> 3);
//uint32_t deltams = 26 + (SEGMENT.speed >> 3);
uint32_t deltams = (FRAMETIME >> 2) + ((FRAMETIME * SEGMENT.speed) >> 7);
uint64_t deltat = (now >> 2) + ((now * SEGMENT.speed) >> 7);
now = deltat;
uint16_t speedfactor1 = beatsin16(3, 179, 269);
uint16_t speedfactor2 = beatsin16(4, 179, 269);
uint32_t deltams1 = (deltams * speedfactor1) / 256;
@@ -3304,6 +3306,7 @@ uint16_t WS2812FX::mode_pacifica()
setPixelColor(i, c.red, c.green, c.blue);
}
now = nowOld;
return FRAMETIME;
}
@@ -3322,3 +3325,405 @@ CRGB WS2812FX::pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart
uint8_t sindex8 = scale16(sindex16, 240);
return ColorFromPalette(p, sindex8, bri, LINEARBLEND);
}
//Solid colour background with glitter
uint16_t WS2812FX::mode_solid_glitter()
{
fill(SEGCOLOR(0));
if (SEGMENT.intensity > random8())
{
setPixelColor(random16(SEGLEN), ULTRAWHITE);
}
return FRAMETIME;
}
/*
* Mode simulates a gradual sunrise
*/
uint16_t WS2812FX::mode_sunrise() {
//speed 0 - static sun
//speed 1 - 60: sunrise time in minutes
//speed 60 - 120 : sunset time in minutes - 60;
//speed above: "breathing" rise and set
if (SEGENV.call == 0 || SEGMENT.speed != SEGENV.aux0) {
SEGENV.step = millis(); //save starting time, millis() because now can change from sync
SEGENV.aux0 = SEGMENT.speed;
}
fill(0);
uint16_t stage = 0xFFFF;
uint32_t s10SinceStart = (millis() - SEGENV.step) /100; //tenths of seconds
if (SEGMENT.speed > 120) { //quick sunrise and sunset
uint16_t counter = (now >> 1) * (((SEGMENT.speed -120) >> 1) +1);
stage = triwave16(counter);
} else if (SEGMENT.speed) { //sunrise
uint8_t durMins = SEGMENT.speed;
if (durMins > 60) durMins -= 60;
uint32_t s10Target = durMins * 600;
if (s10SinceStart > s10Target) s10SinceStart = s10Target;
stage = map(s10SinceStart, 0, s10Target, 0, 0xFFFF);
if (SEGMENT.speed > 60) stage = 0xFFFF - stage; //sunset
}
for (uint16_t i = 0; i <= SEGLEN/2; i++)
{
//default palette is Fire
uint32_t c = color_from_palette(0, false, true, 255); //background
uint16_t wave = triwave16((i * stage) / SEGLEN);
wave = (wave >> 8) + ((wave * SEGMENT.intensity) >> 15);
if (wave > 240) { //clipped, full white sun
c = color_from_palette( 240, false, true, 255);
} else { //transition
c = color_from_palette(wave, false, true, 255);
}
setPixelColor(i, c);
setPixelColor(SEGLEN - i - 1, c);
}
return FRAMETIME;
}
/*
* Effects by Andrew Tuline
*/
uint16_t WS2812FX::phased_base(uint8_t moder) { // We're making sine waves here. By Andrew Tuline.
uint8_t allfreq = 16; // Base frequency.
//float* phasePtr = reinterpret_cast<float*>(SEGENV.step); // Phase change value gets calculated.
static float phase = 0;//phasePtr[0];
uint8_t cutOff = (255-SEGMENT.intensity); // You can change the number of pixels. AKA INTENSITY (was 192).
uint8_t modVal = 5;//SEGMENT.fft1/8+1; // You can change the modulus. AKA FFT1 (was 5).
uint8_t index = now/64; // Set color rotation speed
phase += SEGMENT.speed/32.0; // You can change the speed of the wave. AKA SPEED (was .4)
//phasePtr[0] = phase;
for (int i = 0; i < SEGLEN; i++) {
if (moder == 1) modVal = (inoise8(i*10 + i*10) /16); // Let's randomize our mod length with some Perlin noise.
uint16_t val = (i+1) * allfreq; // This sets the frequency of the waves. The +1 makes sure that leds[0] is used.
if (modVal == 0) modVal = 1;
val += phase * (i % modVal +1) /2; // This sets the varying phase change of the waves. By Andrew Tuline.
uint8_t b = cubicwave8(val); // Now we make an 8 bit sinewave.
b = (b > cutOff) ? (b - cutOff) : 0; // A ternary operator to cutoff the light.
setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(index, false, false, 0), b));
index += 256 / SEGLEN;
if (SEGLEN > 256) index ++; // Correction for segments longer than 256 LEDs
}
return FRAMETIME;
}
uint16_t WS2812FX::mode_phased(void) {
return phased_base(0);
}
uint16_t WS2812FX::mode_phased_noise(void) {
return phased_base(1);
}
uint16_t WS2812FX::mode_twinkleup(void) { // A very short twinkle routine with fade-in and dual controls. By Andrew Tuline.
random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through.
for (int i = 0; i<SEGLEN; i++) {
uint8_t ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work.
uint8_t pixBri = sin8(ranstart + 16 * now/(256-SEGMENT.speed));
if (random8() > SEGMENT.intensity) pixBri = 0;
setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i*20, false, PALETTE_SOLID_WRAP, 0), pixBri));
}
return FRAMETIME;
}
// Peaceful noise that's slow and with gradually changing palettes. Does not support WLED palettes or default colours or controls.
uint16_t WS2812FX::mode_noisepal(void) { // Slow noise palette by Andrew Tuline.
uint16_t scale = 15 + (SEGMENT.intensity >> 2); //default was 30
//#define scale 30
uint16_t dataSize = sizeof(CRGBPalette16) * 2; //allocate space for 2 Palettes
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
CRGBPalette16* palettes = reinterpret_cast<CRGBPalette16*>(SEGENV.data);
uint16_t changePaletteMs = 4000 + SEGMENT.speed *10; //between 4 - 6.5sec
if (millis() - SEGENV.step > changePaletteMs)
{
SEGENV.step = millis();
uint8_t baseI = random8();
palettes[1] = CRGBPalette16(CHSV(baseI+random8(64), 255, random8(128,255)), CHSV(baseI+128, 255, random8(128,255)), CHSV(baseI+random8(92), 192, random8(128,255)), CHSV(baseI+random8(92), 255, random8(128,255)));
}
CRGB color;
//EVERY_N_MILLIS(10) { //(don't have to time this, effect function is only called every 24ms)
nblendPaletteTowardPalette(palettes[0], palettes[1], 48); // Blend towards the target palette over 48 iterations.
if (SEGMENT.palette > 0) palettes[0] = currentPalette;
for(int i = 0; i < SEGLEN; i++) {
uint8_t index = inoise8(i*scale, SEGENV.aux0+i*scale); // Get a value from the noise function. I'm using both x and y axis.
color = ColorFromPalette(palettes[0], index, 255, LINEARBLEND); // Use the my own palette.
setPixelColor(i, color.red, color.green, color.blue);
}
SEGENV.aux0 += beatsin8(10,1,4); // Moving along the distance. Vary it a bit with a sine wave.
return FRAMETIME;
}
// Sine waves that have controllable phase change speed, frequency and cutoff. By Andrew Tuline.
// SEGMENT.speed ->Speed, SEGMENT.intensity -> Frequency (SEGMENT.fft1 -> Color change, SEGMENT.fft2 -> PWM cutoff)
//
uint16_t WS2812FX::mode_sinewave(void) { // Adjustable sinewave. By Andrew Tuline
//#define qsuba(x, b) ((x>b)?x-b:0) // Analog Unsigned subtraction macro. if result <0, then => 0
uint16_t colorIndex = now /32;//(256 - SEGMENT.fft1); // Amount of colour change.
SEGENV.step += SEGMENT.speed/16; // Speed of animation.
uint16_t freq = SEGMENT.intensity/4;//SEGMENT.fft2/8; // Frequency of the signal.
for (int i=0; i<SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows:
int pixBri = cubicwave8((i*freq)+SEGENV.step);//qsuba(cubicwave8((i*freq)+SEGENV.step), (255-SEGMENT.intensity)); // qsub sets a minimum value called thiscutoff. If < thiscutoff, then bright = 0. Otherwise, bright = 128 (as defined in qsub)..
//setPixCol(i, i*colorIndex/255, pixBri);
setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(i*colorIndex/255, false, PALETTE_SOLID_WRAP, 0), pixBri));
}
return FRAMETIME;
}
/*
* Best of both worlds from Palette and Spot effects. By Aircoookie
*/
uint16_t WS2812FX::mode_flow(void)
{
uint16_t counter = 0;
if (SEGMENT.speed != 0)
{
counter = now * ((SEGMENT.speed >> 2) +1);
counter = counter >> 8;
}
uint16_t maxZones = SEGLEN / 6; //only looks good if each zone has at least 6 LEDs
uint16_t zones = (SEGMENT.intensity * maxZones) >> 8;
if (zones & 0x01) zones++; //zones must be even
if (zones < 2) zones = 2;
uint16_t zoneLen = SEGLEN / zones;
uint16_t offset = (SEGLEN - zones * zoneLen) >> 1;
fill(color_from_palette(-counter, false, true, 255));
for (uint16_t z = 0; z < zones; z++)
{
uint16_t pos = offset + z * zoneLen;
for (uint16_t i = 0; i < zoneLen; i++)
{
uint8_t colorIndex = (i * 255 / zoneLen) - counter;
uint16_t led = (z & 0x01) ? i : (zoneLen -1) -i;
if (IS_REVERSE) led = (zoneLen -1) -led;
setPixelColor(pos + led, color_from_palette(colorIndex, false, true, 255));
}
}
return FRAMETIME;
}
/*
* Dots waving around in a sine/pendulum motion.
* Little pixel birds flying in a circle. By Aircoookie
*/
uint16_t WS2812FX::mode_chunchun(void)
{
fill(SEGCOLOR(1));
uint16_t counter = now*(6 + (SEGMENT.speed >> 4));
uint16_t numBirds = SEGLEN >> 2;
uint16_t span = SEGMENT.intensity << 8;
for (uint16_t i = 0; i < numBirds; i++)
{
counter -= span/numBirds;
int megumin = sin16(counter) + 0x8000;
uint32_t bird = (megumin * SEGLEN) >> 16;
uint32_t c = color_from_palette((i * 255)/ numBirds, false, true, 0);
setPixelColor(bird, c);
}
return FRAMETIME;
}
typedef struct Spotlight {
float speed;
uint8_t colorIdx;
int16_t position;
unsigned long lastUpdateTime;
uint8_t width;
uint8_t type;
} spotlight;
#define SPOT_TYPE_SOLID 0
#define SPOT_TYPE_GRADIENT 1
#define SPOT_TYPE_2X_GRADIENT 2
#define SPOT_TYPE_2X_DOT 3
#define SPOT_TYPE_3X_DOT 4
#define SPOT_TYPE_4X_DOT 5
#define SPOT_TYPES_COUNT 6
/*
* Spotlights moving back and forth that cast dancing shadows.
* Shine this through tree branches/leaves or other close-up objects that cast
* interesting shadows onto a ceiling or tarp.
*
* By Steve Pomeroy @xxv
*/
uint16_t WS2812FX::mode_dancing_shadows(void)
{
uint8_t numSpotlights = map(SEGMENT.intensity, 0, 255, 2, 50);
bool initialize = SEGENV.aux0 != numSpotlights;
SEGENV.aux0 = numSpotlights;
uint16_t dataSize = sizeof(spotlight) * numSpotlights;
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
Spotlight* spotlights = reinterpret_cast<Spotlight*>(SEGENV.data);
fill(BLACK);
unsigned long time = millis();
bool respawn = false;
for (uint8_t i = 0; i < numSpotlights; i++) {
if (!initialize) {
// advance the position of the spotlight
int16_t delta = (float)(time - spotlights[i].lastUpdateTime) *
(spotlights[i].speed * ((1.0 + SEGMENT.speed)/100.0));
if (abs(delta) >= 1) {
spotlights[i].position += delta;
spotlights[i].lastUpdateTime = time;
}
respawn = (spotlights[i].speed > 0.0 && spotlights[i].position > (SEGLEN + 2))
|| (spotlights[i].speed < 0.0 && spotlights[i].position < -(spotlights[i].width + 2));
}
if (initialize || respawn) {
spotlights[i].colorIdx = random8();
spotlights[i].width = random8(1, 10);
spotlights[i].speed = 1.0/random8(4, 50);
if (initialize) {
spotlights[i].position = random16(SEGLEN);
spotlights[i].speed *= random8(2) ? 1.0 : -1.0;
} else {
if (random8(2)) {
spotlights[i].position = SEGLEN + spotlights[i].width;
spotlights[i].speed *= -1.0;
}else {
spotlights[i].position = -spotlights[i].width;
}
}
spotlights[i].lastUpdateTime = time;
spotlights[i].type = random8(SPOT_TYPES_COUNT);
}
uint32_t color = color_from_palette(spotlights[i].colorIdx, false, false, 0);
int start = spotlights[i].position;
if (spotlights[i].width <= 1) {
if (start >= 0 && start < SEGLEN) {
blendPixelColor(start, color, 128);
}
} else {
switch (spotlights[i].type) {
case SPOT_TYPE_SOLID:
for (uint8_t j = 0; j < spotlights[i].width; j++) {
if ((start + j) >= 0 && (start + j) < SEGLEN) {
blendPixelColor(start + j, color, 128);
}
}
break;
case SPOT_TYPE_GRADIENT:
for (uint8_t j = 0; j < spotlights[i].width; j++) {
if ((start + j) >= 0 && (start + j) < SEGLEN) {
blendPixelColor(start + j, color,
cubicwave8(map(j, 0, spotlights[i].width - 1, 0, 255)));
}
}
break;
case SPOT_TYPE_2X_GRADIENT:
for (uint8_t j = 0; j < spotlights[i].width; j++) {
if ((start + j) >= 0 && (start + j) < SEGLEN) {
blendPixelColor(start + j, color,
cubicwave8(2 * map(j, 0, spotlights[i].width - 1, 0, 255)));
}
}
break;
case SPOT_TYPE_2X_DOT:
for (uint8_t j = 0; j < spotlights[i].width; j += 2) {
if ((start + j) >= 0 && (start + j) < SEGLEN) {
blendPixelColor(start + j, color, 128);
}
}
break;
case SPOT_TYPE_3X_DOT:
for (uint8_t j = 0; j < spotlights[i].width; j += 3) {
if ((start + j) >= 0 && (start + j) < SEGLEN) {
blendPixelColor(start + j, color, 128);
}
}
break;
case SPOT_TYPE_4X_DOT:
for (uint8_t j = 0; j < spotlights[i].width; j += 4) {
if ((start + j) >= 0 && (start + j) < SEGLEN) {
blendPixelColor(start + j, color, 128);
}
}
break;
}
}
}
return FRAMETIME;
}
/*
Imitates a washing machine, rotating same waves forward, then pause, then backward.
By Stefan Seegel
*/
uint16_t WS2812FX::mode_washing_machine(void) {
float speed = tristate_square8(now >> 7, 90, 15);
float quot = 32.0f - ((float)SEGMENT.speed / 16.0f);
speed /= quot;
SEGENV.step += (speed * 128.0f);
for (int i=0; i<SEGLEN; i++) {
uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7));
setPixelColor(i, color_from_palette(col, false, PALETTE_SOLID_WRAP, 3));
}
return FRAMETIME;
}

View File

@@ -27,19 +27,30 @@
#ifndef WS2812FX_h
#define WS2812FX_h
#include "NpbWrapper.h"
#ifdef ESP32_MULTISTRIP
#include "../usermods/esp32_multistrip/NpbWrapper.h"
#else
#include "NpbWrapper.h"
#endif
#include "const.h"
#define FASTLED_INTERNAL //remove annoying pragma messages
#define USE_GET_MILLISECOND_TIMER
#include "FastLED.h"
#define DEFAULT_BRIGHTNESS (uint8_t)127
#define DEFAULT_MODE (uint8_t)0
#define DEFAULT_SPEED (uint8_t)128
#define DEFAULT_INTENSITY (uint8_t)128
#define DEFAULT_COLOR (uint32_t)0xFFAA00
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
/* Not used in all effects yet */
#define WLED_FPS 42
@@ -47,7 +58,11 @@
/* each segment uses 52 bytes of SRAM memory, so if you're application fails because of
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
#define MAX_NUM_SEGMENTS 10
#ifdef ESP8266
#define MAX_NUM_SEGMENTS 12
#else
#define MAX_NUM_SEGMENTS 16
#endif
/* How much data bytes all segments combined may allocate */
#ifdef ESP8266
@@ -84,21 +99,24 @@
// options
// bit 7: segment is in transition mode
// bits 3-6: TBD
// bits 4-6: TBD
// bit 3: mirror effect within segment
// bit 2: segment is on
// bit 1: reverse segment
// bit 0: segment is selected
#define NO_OPTIONS (uint8_t)0x00
#define TRANSITIONAL (uint8_t)0x80
#define MIRROR (uint8_t)0x08
#define SEGMENT_ON (uint8_t)0x04
#define REVERSE (uint8_t)0x02
#define SELECTED (uint8_t)0x01
#define IS_TRANSITIONAL ((SEGMENT.options & TRANSITIONAL) == TRANSITIONAL)
#define IS_MIRROR ((SEGMENT.options & MIRROR ) == MIRROR )
#define IS_SEGMENT_ON ((SEGMENT.options & SEGMENT_ON ) == SEGMENT_ON )
#define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE )
#define IS_SELECTED ((SEGMENT.options & SELECTED ) == SELECTED )
#define MODE_COUNT 103
#define MODE_COUNT 114
#define FX_MODE_STATIC 0
#define FX_MODE_BLINK 1
@@ -203,6 +221,17 @@
#define FX_MODE_HEARTBEAT 100
#define FX_MODE_PACIFICA 101
#define FX_MODE_CANDLE_MULTI 102
#define FX_MODE_SOLID_GLITTER 103
#define FX_MODE_SUNRISE 104
#define FX_MODE_PHASED 105
#define FX_MODE_TWINKLEUP 106
#define FX_MODE_NOISEPAL 107
#define FX_MODE_SINEWAVE 108
#define FX_MODE_PHASEDNOISE 109
#define FX_MODE_FLOW 110
#define FX_MODE_CHUNCHUN 111
#define FX_MODE_DANCING_SHADOWS 112
#define FX_MODE_WASHING_MACHINE 113
class WS2812FX {
typedef uint16_t (WS2812FX::*mode_ptr)(void);
@@ -219,7 +248,7 @@ class WS2812FX {
uint8_t intensity;
uint8_t palette;
uint8_t mode;
uint8_t options; //bit pattern: msb first: transitional tbd tbd tbd tbd paused reverse selected
uint8_t options; //bit pattern: msb first: transitional needspixelstate tbd tbd (paused) on reverse selected
uint8_t grouping, spacing;
uint8_t opacity;
uint32_t colors[NUM_COLORS];
@@ -255,7 +284,10 @@ class WS2812FX {
uint16_t virtualLength()
{
uint16_t groupLen = groupLength();
return (length() + groupLen -1) / groupLen;
uint16_t vLength = (length() + groupLen - 1) / groupLen;
if (options & MIRROR)
vLength = (vLength + 1) /2; // divide by 2 if mirror, leave at least a single LED
return vLength;
}
} segment;
@@ -394,6 +426,17 @@ class WS2812FX {
_mode[FX_MODE_HEARTBEAT] = &WS2812FX::mode_heartbeat;
_mode[FX_MODE_PACIFICA] = &WS2812FX::mode_pacifica;
_mode[FX_MODE_CANDLE_MULTI] = &WS2812FX::mode_candle_multi;
_mode[FX_MODE_SOLID_GLITTER] = &WS2812FX::mode_solid_glitter;
_mode[FX_MODE_SUNRISE] = &WS2812FX::mode_sunrise;
_mode[FX_MODE_PHASED] = &WS2812FX::mode_phased;
_mode[FX_MODE_TWINKLEUP] = &WS2812FX::mode_twinkleup;
_mode[FX_MODE_NOISEPAL] = &WS2812FX::mode_noisepal;
_mode[FX_MODE_SINEWAVE] = &WS2812FX::mode_sinewave;
_mode[FX_MODE_PHASEDNOISE] = &WS2812FX::mode_phased_noise;
_mode[FX_MODE_FLOW] = &WS2812FX::mode_flow;
_mode[FX_MODE_CHUNCHUN] = &WS2812FX::mode_chunchun;
_mode[FX_MODE_DANCING_SHADOWS] = &WS2812FX::mode_dancing_shadows;
_mode[FX_MODE_WASHING_MACHINE] = &WS2812FX::mode_washing_machine;
_brightness = DEFAULT_BRIGHTNESS;
currentPalette = CRGBPalette16(CRGB::Black);
@@ -409,6 +452,7 @@ class WS2812FX {
init(bool supportWhite, uint16_t countPixels, bool skipFirst),
service(void),
blur(uint8_t),
fill(uint32_t),
fade_out(uint8_t r),
setMode(uint8_t segid, uint8_t m),
setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
@@ -417,16 +461,19 @@ class WS2812FX {
setRange(uint16_t i, uint16_t i2, uint32_t col),
setShowCallback(show_callback cb),
setTransitionMode(bool t),
calcGammaTable(float),
trigger(void),
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
resetSegments(),
setPixelColor(uint16_t n, uint32_t c),
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
show(void),
setRgbwPwm(void);
setRgbwPwm(void),
setColorOrder(uint8_t co),
setPixelSegment(uint8_t n);
bool
reverseMode = false,
reverseMode = false, //is the entire LED strip reversed?
gammaCorrectBri = false,
gammaCorrectCol = true,
applyToAllSelected = true,
@@ -438,7 +485,6 @@ class WS2812FX {
rgbwMode = RGBW_MODE_DUAL,
paletteFade = 0,
paletteBlend = 0,
colorOrder = 0,
milliampsPerLed = 55,
getBrightness(void),
getMode(void),
@@ -448,18 +494,24 @@ class WS2812FX {
getMaxSegments(void),
//getFirstSelectedSegment(void),
getMainSegmentId(void),
getColorOrder(void),
gamma8(uint8_t),
gamma8_cal(uint8_t, float),
get_random_wheel_index(uint8_t);
int8_t
tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec);
uint16_t
ablMilliampsMax,
currentMilliamps,
triwave16(uint16_t);
uint32_t
now,
timebase,
color_wheel(uint8_t),
color_from_palette(uint16_t, bool, bool, uint8_t, uint8_t pbri = 255),
color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255),
color_blend(uint32_t,uint32_t,uint8_t),
gamma32(uint32_t),
getLastShow(void),
@@ -562,7 +614,7 @@ class WS2812FX {
mode_twinklecat(void),
mode_halloween_eyes(void),
mode_static_pattern(void),
mode_tri_static_pattern(void),
mode_tri_static_pattern(void),
mode_spots(void),
mode_spots_fade(void),
mode_glitter(void),
@@ -580,8 +632,18 @@ class WS2812FX {
mode_ripple_rainbow(void),
mode_heartbeat(void),
mode_pacifica(void),
mode_candle_multi(void);
mode_candle_multi(void),
mode_solid_glitter(void),
mode_sunrise(void),
mode_phased(void),
mode_twinkleup(void),
mode_noisepal(void),
mode_sinewave(void),
mode_phased_noise(void),
mode_flow(void),
mode_chunchun(void),
mode_dancing_shadows(void),
mode_washing_machine(void);
private:
NeoPixelWrapper *bus;
@@ -591,7 +653,6 @@ class WS2812FX {
CRGBPalette16 currentPalette;
CRGBPalette16 targetPalette;
uint32_t now;
uint16_t _length, _lengthRaw, _virtualSegmentLength;
uint16_t _rand16seed;
uint8_t _brightness;
@@ -599,9 +660,9 @@ class WS2812FX {
void load_gradient_palette(uint8_t);
void handle_palette(void);
void fill(uint32_t);
bool
shouldStartBus = false,
_useRgbw = false,
_skipFirstMode,
_triggered;
@@ -628,10 +689,13 @@ class WS2812FX {
running(uint32_t, uint32_t),
tricolor_chase(uint32_t, uint32_t),
twinklefox_base(bool),
spots_base(uint16_t);
spots_base(uint16_t),
phased_base(uint8_t);
CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat);
CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff);
void blendPixelColor(uint16_t n, uint32_t color, uint8_t blend);
uint32_t _lastPaletteChange = 0;
uint32_t _lastShow = 0;
@@ -654,7 +718,6 @@ class WS2812FX {
uint16_t realPixelIndex(uint16_t i);
};
//10 names per line
const char JSON_mode_names[] PROGMEM = R"=====([
"Solid","Blink","Breathe","Wipe","Wipe Random","Random Colors","Sweep","Dynamic","Colorloop","Rainbow",
@@ -667,7 +730,8 @@ const char JSON_mode_names[] PROGMEM = R"=====([
"Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple",
"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst",
"Fireworks 1D","Bouncing Balls","Sinelon","Sinelon Dual","Sinelon Rainbow","Popcorn","Drip","Plasma","Percent","Ripple Rainbow",
"Heartbeat","Pacifica","Candle Multi"
"Heartbeat","Pacifica","Candle Multi", "Solid Glitter","Sunrise","Phased","Twinkleup","Noise Pal", "Sine","Phased Noise",
"Flow","Chunchun","Dancing Shadows","Washing Machine"
])=====";
@@ -677,7 +741,7 @@ const char JSON_palette_names[] PROGMEM = R"=====([
"Pastel","Sunset 2","Beech","Vintage","Departure","Landscape","Beach","Sherbet","Hult","Hult 64",
"Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn",
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura",
"Aurora","Atlantica"
"Aurora","Atlantica","C9 2","C9 New"
])=====";
#endif

View File

@@ -72,6 +72,7 @@ void WS2812FX::service() {
now = nowUp + timebase;
if (nowUp - _lastShow < MIN_SHOW_DELAY) return;
bool doShow = false;
for(uint8_t i=0; i < MAX_NUM_SEGMENTS; i++)
{
_segment_index = i;
@@ -80,12 +81,17 @@ void WS2812FX::service() {
if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary
{
if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check
_virtualSegmentLength = SEGMENT.virtualLength();
doShow = true;
handle_palette();
uint16_t delay = (this->*_mode[SEGMENT.mode])();
uint16_t delay = FRAMETIME;
if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen
_virtualSegmentLength = SEGMENT.virtualLength();
handle_palette();
delay = (this->*_mode[SEGMENT.mode])(); //effect function
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
}
SEGENV.next_time = nowUp + delay;
if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++;
}
}
}
@@ -105,16 +111,25 @@ void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
setPixelColor(n, r, g, b, w);
}
#define REV(i) (_length - 1 - (i))
//used to map from segment index to physical pixel, taking into account grouping, offsets, reverse and mirroring
uint16_t WS2812FX::realPixelIndex(uint16_t i) {
int16_t iGroup = i * SEGMENT.groupLength();
/* reverse just an individual segment */
int16_t realIndex = iGroup;
if (IS_REVERSE) realIndex = SEGMENT.length() -iGroup -1;
if (IS_REVERSE) {
if (IS_MIRROR) {
realIndex = (SEGMENT.length() -1) / 2 - iGroup; //only need to index half the pixels
} else {
realIndex = SEGMENT.length() - iGroup - 1;
}
}
realIndex += SEGMENT.start;
/* Reverse the whole string */
if (reverseMode) realIndex = _length - 1 - realIndex;
if (reverseMode) realIndex = REV(realIndex);
return realIndex;
}
@@ -136,16 +151,7 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
}
RgbwColor col;
switch (colorOrder)
{
case 0: col.G = g; col.R = r; col.B = b; break; //0 = GRB, default
case 1: col.G = r; col.R = g; col.B = b; break; //1 = RGB, common for WS2811
case 2: col.G = b; col.R = r; col.B = g; break; //2 = BRG
case 3: col.G = r; col.R = b; col.B = g; break; //3 = RBG
case 4: col.G = b; col.R = g; col.B = r; break; //4 = BGR
default: col.G = g; col.R = b; col.B = r; break; //5 = GBR
}
col.W = w;
col.R = r; col.G = g; col.B = b; col.W = w;
uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0;
if (SEGLEN) {//from segment
@@ -170,14 +176,23 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
int16_t indexSet = realIndex + (reversed ? -j : j);
int16_t indexSetRev = indexSet;
if (reverseMode) indexSetRev = _length - 1 - indexSet;
if (reverseMode) indexSetRev = REV(indexSet);
#ifdef WLED_CUSTOM_LED_MAPPING
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
#endif
if (indexSetRev >= SEGMENT.start && indexSetRev < SEGMENT.stop) bus->SetPixelColor(indexSet + skip, col);
if (indexSetRev >= SEGMENT.start && indexSetRev < SEGMENT.stop) {
bus->SetPixelColor(indexSet + skip, col);
if (IS_MIRROR) { //set the corresponding mirrored pixel
if (reverseMode) {
bus->SetPixelColor(REV(SEGMENT.start) - indexSet + skip + REV(SEGMENT.stop) + 1, col);
} else {
bus->SetPixelColor(SEGMENT.stop - indexSet + skip + SEGMENT.start - 1, col);
}
}
}
}
} else { //live data, etc.
if (reverseMode) i = _length - 1 - i;
if (reverseMode) i = REV(i);
#ifdef WLED_CUSTOM_LED_MAPPING
if (i < customMappingSize) i = customMappingTable[i];
#endif
@@ -233,7 +248,7 @@ void WS2812FX::show(void) {
for (uint16_t i = 0; i < _length; i++) //sum up the usage of each LED
{
RgbwColor c = bus->GetPixelColorRgbw(i);
RgbwColor c = bus->GetPixelColorRaw(i);
if(useWackyWS2815PowerModel)
{
@@ -366,6 +381,24 @@ void WS2812FX::setBrightness(uint8_t b) {
if (_brightness == b) return;
_brightness = (gammaCorrectBri) ? gamma8(b) : b;
_segment_index = 0;
if (b == 0) { //unfreeze all segments on power off
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
_segments[i].setOption(SEG_OPTION_FREEZE, false);
}
#if LEDPIN == LED_BUILTIN
if (!shouldStartBus)
shouldStartBus = true;
#endif
} else {
#if LEDPIN == LED_BUILTIN
if (shouldStartBus) {
shouldStartBus = false;
const uint8_t ty = _useRgbw ? 2 : 1;
bus->Begin((NeoPixelType)ty, _lengthRaw);
}
#endif
}
if (SEGENV.next_time > millis() + 22 && millis() - _lastShow > MIN_SHOW_DELAY) show();//apply brightness change immediately if no refresh soon
}
@@ -400,7 +433,12 @@ uint8_t WS2812FX::getMaxSegments(void) {
uint8_t WS2812FX::getMainSegmentId(void) {
if (mainSegment >= MAX_NUM_SEGMENTS) return 0;
return mainSegment;
if (_segments[mainSegment].isActive()) return mainSegment;
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) //get first active
{
if (_segments[i].isActive()) return i;
}
return 0;
}
uint32_t WS2812FX::getColor(void) {
@@ -419,18 +457,7 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
if (i >= _lengthRaw) return 0;
RgbwColor col = bus->GetPixelColorRgbw(i);
switch (colorOrder)
{
// W G R B
case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default
case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811
case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG
case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG
case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR
case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR
}
return 0;
return bus->GetPixelColorRgbw(i);
}
WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) {
@@ -450,6 +477,14 @@ uint32_t WS2812FX::getLastShow(void) {
return _lastShow;
}
uint8_t WS2812FX::getColorOrder(void) {
return bus->GetColorOrder();
}
void WS2812FX::setColorOrder(uint8_t co) {
bus->SetColorOrder(co);
}
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) {
if (n >= MAX_NUM_SEGMENTS) return;
Segment& seg = _segments[n];
@@ -493,6 +528,7 @@ void WS2812FX::resetSegments() {
_segments[0].colors[0] = DEFAULT_COLOR;
_segments[0].start = 0;
_segments[0].speed = DEFAULT_SPEED;
_segments[0].intensity = DEFAULT_INTENSITY;
_segments[0].stop = _length;
_segments[0].grouping = 1;
_segments[0].setOption(SEG_OPTION_SELECTED, 1);
@@ -505,11 +541,25 @@ void WS2812FX::resetSegments() {
_segments[i].grouping = 1;
_segments[i].setOption(SEG_OPTION_ON, 1);
_segments[i].opacity = 255;
_segments[i].speed = DEFAULT_SPEED;
_segments[i].intensity = DEFAULT_INTENSITY;
_segment_runtimes[i].reset();
}
_segment_runtimes[0].reset();
}
//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply)
void WS2812FX::setPixelSegment(uint8_t n)
{
if (n < MAX_NUM_SEGMENTS) {
_segment_index = n;
_virtualSegmentLength = SEGMENT.length();
} else {
_segment_index = 0;
_virtualSegmentLength = 0;
}
}
void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col)
{
if (i2 >= i)
@@ -528,11 +578,14 @@ void WS2812FX::setShowCallback(show_callback cb)
void WS2812FX::setTransitionMode(bool t)
{
_segment_index = getMainSegmentId();
SEGMENT.setOption(SEG_OPTION_TRANSITIONAL, t);
if (!t) return;
unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled
if (SEGMENT.mode == FX_MODE_STATIC && SEGENV.next_time > waitMax) SEGENV.next_time = waitMax;
for (uint16_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
_segment_index = i;
SEGMENT.setOption(SEG_OPTION_TRANSITIONAL, t);
if (t && SEGMENT.mode == FX_MODE_STATIC && SEGENV.next_time > waitMax) SEGENV.next_time = waitMax;
}
}
/*
@@ -569,6 +622,14 @@ void WS2812FX::fill(uint32_t c) {
}
}
/*
* Blends the specified color with the existing pixel color.
*/
void WS2812FX::blendPixelColor(uint16_t n, uint32_t color, uint8_t blend)
{
setPixelColor(n, color_blend(getPixelColor(n), color, blend));
}
/*
* fade out function, higher rate = quicker fade
*/
@@ -637,6 +698,32 @@ uint16_t WS2812FX::triwave16(uint16_t in)
return 0xFFFF - (in - 0x8000)*2;
}
/*
* Generates a tristate square wave w/ attac & decay
* @param x input value 0-255
* @param pulsewidth 0-127
* @param attdec attac & decay, max. pulsewidth / 2
* @returns signed waveform value
*/
int8_t WS2812FX::tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) {
int8_t a = 127;
if (x > 127) {
a = -127;
x -= 127;
}
if (x < attdec) { //inc to max
return (int16_t) x * a / attdec;
}
else if (x < pulsewidth - attdec) { //max
return a;
}
else if (x < pulsewidth) { //dec to 0
return (int16_t) (pulsewidth - x) * a / attdec;
}
return 0;
}
/*
* Put a value 0 to 255 in to get a color value.
* The colours are a transition r -> g -> b -> back to r
@@ -706,26 +793,28 @@ void WS2812FX::handle_palette(void)
_segment_index_palette_last = _segment_index;
byte paletteIndex = SEGMENT.palette;
if (SEGMENT.mode == FX_MODE_GLITTER && paletteIndex == 0) paletteIndex = 11;
if (paletteIndex == 0) //default palette. Differs depending on effect
{
switch (SEGMENT.mode)
{
case FX_MODE_FIRE_2012 : paletteIndex = 35; break; //heat palette
case FX_MODE_COLORWAVES : paletteIndex = 26; break; //landscape 33
case FX_MODE_FILLNOISE8 : paletteIndex = 9; break; //ocean colors
case FX_MODE_NOISE16_1 : paletteIndex = 20; break; //Drywet
case FX_MODE_NOISE16_2 : paletteIndex = 43; break; //Blue cyan yellow
case FX_MODE_NOISE16_3 : paletteIndex = 35; break; //heat palette
case FX_MODE_NOISE16_4 : paletteIndex = 26; break; //landscape 33
case FX_MODE_GLITTER : paletteIndex = 11; break; //rainbow colors
case FX_MODE_SUNRISE : paletteIndex = 35; break; //heat palette
case FX_MODE_FLOW : paletteIndex = 6; break; //party
}
}
if (SEGMENT.mode >= FX_MODE_METEOR && paletteIndex == 0) paletteIndex = 4;
switch (paletteIndex)
{
case 0: {//default palette. Differs depending on effect
switch (SEGMENT.mode)
{
case FX_MODE_FIRE_2012 : load_gradient_palette(22); break;//heat palette
case FX_MODE_COLORWAVES : load_gradient_palette(13); break;//landscape 33
case FX_MODE_FILLNOISE8 : targetPalette = OceanColors_p; break;
case FX_MODE_NOISE16_1 : load_gradient_palette(17); break;//Drywet
case FX_MODE_NOISE16_2 : load_gradient_palette(30); break;//Blue cyan yellow
case FX_MODE_NOISE16_3 : load_gradient_palette(22); break;//heat palette
case FX_MODE_NOISE16_4 : load_gradient_palette(13); break;//landscape 33
//case FX_MODE_GLITTER : targetPalette = RainbowColors_p; break;
default: targetPalette = PartyColors_p; break;//palette, bpm
}
break;}
case 0: //default palette. Exceptions for specific effects above
targetPalette = PartyColors_p; break;
case 1: {//periodically replace palette with a random one. Doesn't work with multiple FastLED segments
if (!singleSegmentMode)
{
@@ -777,10 +866,10 @@ void WS2812FX::handle_palette(void)
case 12: //Rainbow stripe colors
targetPalette = RainbowStripeColors_p; break;
default: //progmem palettes
load_gradient_palette(SEGMENT.palette -13);
load_gradient_palette(paletteIndex -13);
}
if (singleSegmentMode && paletteFade) //only blend if just one segment uses FastLED mode
if (singleSegmentMode && paletteFade && SEGENV.call > 0) //only blend if just one segment uses FastLED mode
{
nblendPaletteTowardPalette(currentPalette, targetPalette, 48);
} else
@@ -789,6 +878,16 @@ void WS2812FX::handle_palette(void)
}
}
/*
* Gets a single color from the currently selected palette.
* @param i Palette Index (if mapping is true, the full palette will be SEGLEN long, if false, 255). Will wrap around automatically.
* @param mapping if true, LED position in segment is considered for color
* @param wrap FastLED palettes will usally wrap back to the start smoothly. Set false to get a hard edge
* @param mcol If the default palette 0 is selected, return the standard color 0, 1 or 2 instead. If >2, Party palette is used instead
* @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling)
* @returns Single color from palette
*/
uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri)
{
if (SEGMENT.palette == 0 && mcol < 3) return SEGCOLOR(mcol); //WS2812FX default
@@ -800,6 +899,7 @@ uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8
return fastled_col.r*65536 + fastled_col.g*256 + fastled_col.b;
}
//@returns `true` if color, mode, speed, intensity and palette match
bool WS2812FX::segmentsAreIdentical(Segment* a, Segment* b)
{
//if (a->start != b->start) return false;
@@ -823,27 +923,30 @@ void WS2812FX::setRgbwPwm(void) {
_analogLastShow = nowUp;
RgbwColor color = bus->GetPixelColorRgbw(0);
RgbwColor c;
uint32_t col = bus->GetPixelColorRgbw(0);
c.R = col >> 16; c.G = col >> 8; c.B = col; c.W = col >> 24;
byte b = getBrightness();
if (color == _analogLastColor && b == _analogLastBri) return;
// check color values for Warm / Cold white mix (for RGBW) // EsplanexaDevice.cpp
#ifdef WLED_USE_5CH_LEDS
if (color.R == 255 && color.G == 255 && color.B == 255 && color.W == 255) {
bus->SetRgbwPwm(0, 0, 0, 0, color.W * b / 255);
} else if (color.R == 127 && color.G == 127 && color.B == 127 && color.W == 255) {
bus->SetRgbwPwm(0, 0, 0, color.W * b / 512, color.W * b / 255);
} else if (color.R == 0 && color.G == 0 && color.B == 0 && color.W == 255) {
bus->SetRgbwPwm(0, 0, 0, color.W * b / 255, 0);
} else if (color.R == 130 && color.G == 90 && color.B == 0 && color.W == 255) {
bus->SetRgbwPwm(0, 0, 0, color.W * b / 255, color.W * b / 512);
} else if (color.R == 255 && color.G == 153 && color.B == 0 && color.W == 255) {
bus->SetRgbwPwm(0, 0, 0, color.W * b / 255, 0);
if (c.R == 255 && c.G == 255 && c.B == 255 && c.W == 255) {
bus->SetRgbwPwm(0, 0, 0, 0, c.W * b / 255);
} else if (c.R == 127 && c.G == 127 && c.B == 127 && c.W == 255) {
bus->SetRgbwPwm(0, 0, 0, c.W * b / 512, c.W * b / 255);
} else if (c.R == 0 && c.G == 0 && c.B == 0 && c.W == 255) {
bus->SetRgbwPwm(0, 0, 0, c.W * b / 255, 0);
} else if (c.R == 130 && c.G == 90 && c.B == 0 && c.W == 255) {
bus->SetRgbwPwm(0, 0, 0, c.W * b / 255, c.W * b / 512);
} else if (c.R == 255 && c.G == 153 && c.B == 0 && c.W == 255) {
bus->SetRgbwPwm(0, 0, 0, c.W * b / 255, 0);
} else { // not only white colors
bus->SetRgbwPwm(color.R * b / 255, color.G * b / 255, color.B * b / 255, color.W * b / 255);
bus->SetRgbwPwm(c.R * b / 255, c.G * b / 255, c.B * b / 255, c.W * b / 255);
}
#else
bus->SetRgbwPwm(color.R * b / 255, color.G * b / 255, color.B * b / 255, color.W * b / 255);
bus->SetRgbwPwm(c.R * b / 255, c.G * b / 255, c.B * b / 255, c.W * b / 255);
#endif
_analogLastColor = color;
_analogLastBri = b;
@@ -852,8 +955,8 @@ void WS2812FX::setRgbwPwm(void) {
void WS2812FX::setRgbwPwm() {}
#endif
//gamma 2.4 lookup table used for color correction
const byte gammaT[] = {
//gamma 2.8 lookup table used for color correction
byte gammaT[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
@@ -871,6 +974,17 @@ const byte gammaT[] = {
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
uint8_t WS2812FX::gamma8_cal(uint8_t b, float gamma) {
return (int)(pow((float)b / 255.0, gamma) * 255 + 0.5);
}
void WS2812FX::calcGammaTable(float gamma)
{
for (uint16_t i = 0; i < 256; i++) {
gammaT[i] = gamma8_cal(i, gamma);
}
}
uint8_t WS2812FX::gamma8(uint8_t b)
{
return gammaT[b];

View File

@@ -14,13 +14,19 @@
//#define WLED_USE_ANALOG_LEDS //Uncomment for using "dumb" PWM controlled LEDs (see pins below, default R: gpio5, G: 12, B: 15, W: 13)
//#define WLED_USE_H801 //H801 controller. Please uncomment #define WLED_USE_ANALOG_LEDS as well
//#define WLED_USE_5CH_LEDS //5 Channel H801 for cold and warm white
//#define WLED_USE_BWLT11
//#define WLED_USE_SHOJO_PCB
#ifndef BTNPIN
#define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended)
#endif
#ifndef IR_PIN
#define IR_PIN 4 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
#ifndef TOUCHPIN
//#define TOUCHPIN T0 //touch pin. Behaves the same as button. ESP32 only.
#endif
#ifndef IRPIN
#define IRPIN 4 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
#endif
#ifndef RLYPIN
@@ -35,11 +41,22 @@
#define RLYMDE 1 //mode for relay, 0: LOW if LEDs are on 1: HIGH if LEDs are on
#endif
//enable color order override for a specific range of the strip
//This can be useful if you want to chain multiple strings with incompatible color order
//#define COLOR_ORDER_OVERRIDE
#define COO_MIN 0
#define COO_MAX 27 //not inclusive, this would set the override for LEDs 0-26
#define COO_ORDER COL_ORDER_GRB
//END CONFIGURATION
#if defined(USE_APA102) || defined(USE_WS2801) || defined(USE_LPD8806) || defined(USE_P9813)
#define CLKPIN 0
#define DATAPIN 2
#ifndef CLKPIN
#define CLKPIN 0
#endif
#ifndef DATAPIN
#define DATAPIN 2
#endif
#if BTNPIN == CLKPIN || BTNPIN == DATAPIN
#undef BTNPIN // Deactivate button pin if it conflicts with one of the APA102 pins.
#endif
@@ -54,27 +71,44 @@
#define WPIN 14 //W pin for analog LED strip
#define W2PIN 04 //W2 pin for analog LED strip
#undef BTNPIN
#undef IR_PIN
#define IR_PIN 0 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
#undef IRPIN
#define IRPIN 0 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
#elif defined(WLED_USE_BWLT11)
//PWM pins - to use with BW-LT11
#define RPIN 12 //R pin for analog LED strip
#define GPIN 4 //G pin for analog LED strip
#define BPIN 14 //B pin for analog LED strip
#define WPIN 5 //W pin for analog LED strip
#elif defined(SHOJO_PCB)
#elif defined(WLED_USE_SHOJO_PCB)
//PWM pins - to use with Shojo PCB (https://www.bastelbunker.de/esp-rgbww-wifi-led-controller-vbs-edition/)
#define RPIN 14 //R pin for analog LED strip
#define GPIN 4 //G pin for analog LED strip
#define BPIN 5 //B pin for analog LED strip
#define WPIN 15 //W pin for analog LED strip
#define W2PIN 12 //W2 pin for analog LED strip
#elif defined(WLED_USE_PLJAKOBS_PCB)
// PWM pins - to use with esp_rgbww_controller from patrickjahns/pljakobs (https://github.com/pljakobs/esp_rgbww_controller)
#define RPIN 12 //R pin for analog LED strip
#define GPIN 13 //G pin for analog LED strip
#define BPIN 14 //B pin for analog LED strip
#define WPIN 4 //W pin for analog LED strip
#define W2PIN 5 //W2 pin for analog LED strip
#undef IRPIN
#else
//Enable override of Pins by using the platformio_override.ini file
//PWM pins - PINs 5,12,13,15 are used with Magic Home LED Controller
#define RPIN 5 //R pin for analog LED strip
#define GPIN 12 //G pin for analog LED strip
#define BPIN 15 //B pin for analog LED strip
#define WPIN 13 //W pin for analog LED strip
#ifndef RPIN
#define RPIN 5 //R pin for analog LED strip
#endif
#ifndef GPIN
#define GPIN 12 //G pin for analog LED strip
#endif
#ifndef BPIN
#define BPIN 15 //B pin for analog LED strip
#endif
#ifndef WPIN
#define WPIN 13 //W pin for analog LED strip
#endif
#endif
#undef RLYPIN
#define RLYPIN -1 //disable as pin 12 is used by analog LEDs
@@ -124,7 +158,10 @@
#define PIXELFEATURE4 DotStarLbgrFeature
#elif defined(USE_LPD8806)
#define PIXELFEATURE3 Lpd8806GrbFeature
#define PIXELFEATURE4 Lpd8806GrbFeature
#define PIXELFEATURE4 Lpd8806GrbFeature
#elif defined(USE_WS2801)
#define PIXELFEATURE3 NeoRbgFeature
#define PIXELFEATURE4 NeoRbgFeature
#elif defined(USE_TM1814)
#define PIXELFEATURE3 NeoWrgbTm1814Feature
#define PIXELFEATURE4 NeoWrgbTm1814Feature
@@ -138,6 +175,7 @@
#include <NeoPixelBrightnessBus.h>
#include "const.h"
enum NeoPixelType
{
@@ -266,23 +304,41 @@ public:
}
}
void SetPixelColor(uint16_t indexPixel, RgbwColor color)
void SetPixelColor(uint16_t indexPixel, RgbwColor c)
{
RgbwColor col;
uint8_t co = _colorOrder;
#ifdef COLOR_ORDER_OVERRIDE
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
#endif
//reorder channels to selected order
switch (co)
{
case 0: col.G = c.G; col.R = c.R; col.B = c.B; break; //0 = GRB, default
case 1: col.G = c.R; col.R = c.G; col.B = c.B; break; //1 = RGB, common for WS2811
case 2: col.G = c.B; col.R = c.R; col.B = c.G; break; //2 = BRG
case 3: col.G = c.R; col.R = c.B; col.B = c.G; break; //3 = RBG
case 4: col.G = c.B; col.R = c.G; col.B = c.R; break; //4 = BGR
default: col.G = c.G; col.R = c.B; col.B = c.R; break; //5 = GBR
}
col.W = c.W;
switch (_type) {
case NeoPixelType_Grb: {
_pGrb->SetPixelColor(indexPixel, RgbColor(color.R,color.G,color.B));
_pGrb->SetPixelColor(indexPixel, RgbColor(col.R,col.G,col.B));
}
break;
case NeoPixelType_Grbw: {
#ifdef USE_LPD8806
_pGrbw->SetPixelColor(indexPixel, RgbColor(color.R,color.G,color.B));
#if defined(USE_LPD8806) || defined(USE_WS2801)
_pGrbw->SetPixelColor(indexPixel, RgbColor(col.R,col.G,col.B));
#else
_pGrbw->SetPixelColor(indexPixel, color);
_pGrbw->SetPixelColor(indexPixel, col);
#endif
}
break;
}
}
}
void SetBrightness(byte b)
@@ -293,9 +349,15 @@ public:
}
}
// NOTE: Due to feature differences, some support RGBW but the method name
// here needs to be unique, thus GetPixeColorRgbw
RgbwColor GetPixelColorRgbw(uint16_t indexPixel) const
void SetColorOrder(byte colorOrder) {
_colorOrder = colorOrder;
}
uint8_t GetColorOrder() {
return _colorOrder;
}
RgbwColor GetPixelColorRaw(uint16_t indexPixel) const
{
switch (_type) {
case NeoPixelType_Grb: return _pGrb->GetPixelColor(indexPixel); break;
@@ -304,6 +366,34 @@ public:
return 0;
}
// NOTE: Due to feature differences, some support RGBW but the method name
// here needs to be unique, thus GetPixeColorRgbw
uint32_t GetPixelColorRgbw(uint16_t indexPixel) const
{
RgbwColor col(0,0,0,0);
switch (_type) {
case NeoPixelType_Grb: col = _pGrb->GetPixelColor(indexPixel); break;
case NeoPixelType_Grbw: col = _pGrbw->GetPixelColor(indexPixel); break;
}
uint8_t co = _colorOrder;
#ifdef COLOR_ORDER_OVERRIDE
if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER;
#endif
switch (co)
{
// W G R B
case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default
case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811
case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG
case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG
case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR
case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR
}
return 0;
}
uint8_t* GetPixels(void)
{
switch (_type) {
@@ -321,6 +411,8 @@ private:
NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>* _pGrb;
NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>* _pGrbw;
byte _colorOrder = 0;
void cleanup()
{
switch (_type) {

View File

@@ -46,7 +46,7 @@ void onAlexaChange(EspalexaDevice* dev)
bri = briLast;
colorUpdated(NOTIFIER_CALL_MODE_ALEXA);
}
} else applyMacro(macroAlexaOn);
} else applyPreset(macroAlexaOn);
} else if (m == EspalexaDeviceProperty::off)
{
if (!macroAlexaOff)
@@ -57,7 +57,7 @@ void onAlexaChange(EspalexaDevice* dev)
bri = 0;
colorUpdated(NOTIFIER_CALL_MODE_ALEXA);
}
} else applyMacro(macroAlexaOff);
} else applyPreset(macroAlexaOff);
} else if (m == EspalexaDeviceProperty::bri)
{
bri = espalexaDevice->getValue();
@@ -85,6 +85,7 @@ void onAlexaChange(EspalexaDevice* dev)
col[0] = ((color >> 16) & 0xFF);
col[1] = ((color >> 8) & 0xFF);
col[2] = ( color & 0xFF);
col[3] = 0;
}
colorUpdated(NOTIFIER_CALL_MODE_ALEXA);
}

View File

@@ -11,17 +11,28 @@ void shortPressAction()
toggleOnOff();
colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
} else {
applyMacro(macroButton);
applyPreset(macroButton);
}
}
bool isButtonPressed()
{
#if defined(BTNPIN) && BTNPIN > -1
if (digitalRead(BTNPIN) == LOW) return true;
#endif
#ifdef TOUCHPIN
if (touchRead(TOUCHPIN) <= TOUCH_THRESHOLD) return true;
#endif
return false;
}
void handleButton()
{
#ifdef BTNPIN
#if (defined(BTNPIN) && BTNPIN > -1) || defined(TOUCHPIN)
if (!buttonEnabled) return;
if (digitalRead(BTNPIN) == LOW) //pressed
if (isButtonPressed()) //pressed
{
if (!buttonPressedBefore) buttonPressedTime = millis();
buttonPressedBefore = true;
@@ -30,14 +41,14 @@ void handleButton()
{
if (!buttonLongPressed)
{
if (macroLongPress) {applyMacro(macroLongPress);}
if (macroLongPress) {applyPreset(macroLongPress);}
else _setRandomColor(false,true);
buttonLongPressed = true;
}
}
}
else if (digitalRead(BTNPIN) == HIGH && buttonPressedBefore) //released
else if (!isButtonPressed() && buttonPressedBefore) //released
{
long dur = millis() - buttonPressedTime;
if (dur < 50) {buttonPressedBefore = false; return;} //too short "press", debounce
@@ -51,7 +62,7 @@ void handleButton()
else if (!buttonLongPressed) { //short press
if (macroDoublePress)
{
if (doublePress) applyMacro(macroDoublePress);
if (doublePress) applyPreset(macroDoublePress);
else buttonWaitTime = millis();
} else shortPressAction();
}
@@ -76,7 +87,7 @@ void handleIO()
{
lastOnTime = millis();
if (offMode)
{
{
#if RLYPIN >= 0
digitalWrite(RLYPIN, RLYMDE);
#endif
@@ -84,9 +95,15 @@ void handleIO()
}
} else if (millis() - lastOnTime > 600)
{
#if RLYPIN >= 0
if (!offMode) digitalWrite(RLYPIN, !RLYMDE);
#endif
if (!offMode) {
#if LEDPIN == LED_BUILTIN
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
#endif
#if RLYPIN >= 0
digitalWrite(RLYPIN, !RLYMDE);
#endif
}
offMode = true;
}

680
wled00/cfg.cpp Normal file
View File

@@ -0,0 +1,680 @@
#include "wled.h"
/*
* Serializes and parses the cfg.json and wsec.json settings files, stored in internal FS.
* The structure of the JSON is not to be considered an official API and may change without notice.
*/
//simple macro for ArduinoJSON's or syntax
#define CJSON(a,b) a = b | a
void getStringFromJson(char* dest, const char* src, size_t len) {
if (src != nullptr) strlcpy(dest, src, len);
}
void deserializeConfig() {
bool fromeep = false;
bool success = deserializeConfigSec();
if (!success) { //if file does not exist, try reading from EEPROM
deEEPSettings();
fromeep = true;
}
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
DEBUG_PRINTLN(F("Reading settings from /cfg.json..."));
success = readObjectFromFile("/cfg.json", nullptr, &doc);
if (!success) { //if file does not exist, try reading from EEPROM
if (!fromeep) deEEPSettings();
return;
}
//deserializeJson(doc, json);
//int rev_major = doc[F("rev")][0]; // 1
//int rev_minor = doc[F("rev")][1]; // 0
//long vid = doc[F("vid")]; // 2010020
JsonObject id = doc[F("id")];
getStringFromJson(cmDNS, id[F("mdns")], 33);
getStringFromJson(serverDescription, id[F("name")], 33);
getStringFromJson(alexaInvocationName, id[F("inv")], 33);
JsonObject nw_ins_0 = doc["nw"][F("ins")][0];
getStringFromJson(clientSSID, nw_ins_0[F("ssid")], 33);
//int nw_ins_0_pskl = nw_ins_0[F("pskl")];
//The WiFi PSK is normally not contained in the regular file for security reasons.
//If it is present however, we will use it
getStringFromJson(clientPass, nw_ins_0["psk"], 65);
JsonArray nw_ins_0_ip = nw_ins_0[F("ip")];
JsonArray nw_ins_0_gw = nw_ins_0[F("gw")];
JsonArray nw_ins_0_sn = nw_ins_0[F("sn")];
for (byte i = 0; i < 4; i++) {
CJSON(staticIP[i], nw_ins_0_ip[i]);
CJSON(staticGateway[i], nw_ins_0_gw[i]);
CJSON(staticSubnet[i], nw_ins_0_sn[i]);
}
JsonObject ap = doc[F("ap")];
getStringFromJson(apSSID, ap[F("ssid")], 33);
getStringFromJson(apPass, ap["psk"] , 65); //normally not present due to security
//int ap_pskl = ap[F("pskl")];
CJSON(apChannel, ap[F("chan")]);
if (apChannel > 13 || apChannel < 1) apChannel = 1;
CJSON(apHide, ap[F("hide")]);
if (apHide > 1) apHide = 1;
CJSON(apBehavior, ap[F("behav")]);
/*
JsonArray ap_ip = ap[F("ip")];
for (byte i = 0; i < 4; i++) {
apIP[i] = ap_ip;
}*/
noWifiSleep = doc[F("wifi")][F("sleep")] | !noWifiSleep; // inverted
noWifiSleep = !noWifiSleep;
//int wifi_phy = doc[F("wifi")][F("phy")]; //force phy mode n?
JsonObject hw = doc[F("hw")];
JsonObject hw_led = hw[F("led")];
CJSON(ledCount, hw_led[F("total")]);
if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
CJSON(strip.reverseMode, hw_led[F("rev")]);
JsonObject hw_led_ins_0 = hw_led[F("ins")][0];
//bool hw_led_ins_0_en = hw_led_ins_0[F("en")]; // true
//int hw_led_ins_0_start = hw_led_ins_0[F("start")]; // 0
//int hw_led_ins_0_len = hw_led_ins_0[F("len")]; // 1200
//int hw_led_ins_0_pin_0 = hw_led_ins_0[F("pin")][0]; // 2
strip.setColorOrder(hw_led_ins_0[F("order")]);
//bool hw_led_ins_0_rev = hw_led_ins_0[F("rev")]; // false
skipFirstLed = hw_led_ins_0[F("skip")]; // 0
useRGBW = (hw_led_ins_0[F("type")] == TYPE_SK6812_RGBW);
JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0];
buttonEnabled = hw_btn_ins_0[F("en")] | buttonEnabled;
//int hw_btn_ins_0_pin_0 = hw_btn_ins_0[F("pin")][0]; // 0
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0[F("macros")];
CJSON(macroButton, hw_btn_ins_0_macros[0]);
CJSON(macroLongPress,hw_btn_ins_0_macros[1]);
CJSON(macroDoublePress, hw_btn_ins_0_macros[2]);
//int hw_btn_ins_0_type = hw_btn_ins_0[F("type")]; // 0
//int hw_ir_pin = hw[F("ir")][F("pin")]; // 4
CJSON(irEnabled, hw[F("ir")][F("type")]); // 0
//int hw_relay_pin = hw[F("relay")][F("pin")]; // 12
//bool hw_relay_rev = hw[F("relay")][F("rev")]; // false
//int hw_status_pin = hw[F("status")][F("pin")]; // -1
JsonObject light = doc[F("light")];
CJSON(briMultiplier, light[F("scale-bri")]);
CJSON(strip.paletteBlend, light[F("pal-mode")]);
float light_gc_bri = light[F("gc")]["bri"];
float light_gc_col = light[F("gc")][F("col")]; // 2.8
if (light_gc_bri > 1.5) strip.gammaCorrectBri = true;
else if (light_gc_bri > 0.5) strip.gammaCorrectBri = false;
if (light_gc_col > 1.5) strip.gammaCorrectCol = true;
else if (light_gc_col > 0.5) strip.gammaCorrectCol = false;
JsonObject light_tr = light[F("tr")];
CJSON(fadeTransition, light_tr[F("mode")]);
int tdd = light_tr[F("dur")] | -1;
if (tdd >= 0) transitionDelayDefault = tdd * 100;
CJSON(strip.paletteFade, light_tr[F("pal")]);
JsonObject light_nl = light["nl"];
CJSON(nightlightMode, light_nl[F("mode")]);
CJSON(nightlightDelayMinsDefault, light_nl[F("dur")]);
nightlightDelayMins = nightlightDelayMinsDefault;
CJSON(nightlightTargetBri, light_nl[F("tbri")]);
CJSON(macroNl, light_nl[F("macro")]);
JsonObject def = doc[F("def")];
CJSON(bootPreset, def[F("ps")]);
CJSON(turnOnAtBoot, def["on"]); // true
CJSON(briS, def["bri"]); // 128
if (briS == 0) briS = 255;
JsonObject def_cy = def[F("cy")];
CJSON(presetCyclingEnabled, def_cy["on"]);
CJSON(presetCycleMin, def_cy[F("range")][0]);
CJSON(presetCycleMax, def_cy[F("range")][1]);
tdd = def_cy[F("dur")] | -1;
if (tdd >= 0) presetCycleTime = tdd * 100;
JsonObject interfaces = doc["if"];
JsonObject if_sync = interfaces[F("sync")];
CJSON(udpPort, if_sync[F("port0")]); // 21324
CJSON(udpPort2, if_sync[F("port1")]); // 65506
JsonObject if_sync_recv = if_sync[F("recv")];
CJSON(receiveNotificationBrightness, if_sync_recv["bri"]);
CJSON(receiveNotificationColor, if_sync_recv[F("col")]);
CJSON(receiveNotificationEffects, if_sync_recv[F("fx")]);
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
JsonObject if_sync_send = if_sync[F("send")];
CJSON(notifyDirectDefault, if_sync_send[F("dir")]);
notifyDirect = notifyDirectDefault;
CJSON(notifyButton, if_sync_send[F("btn")]);
CJSON(notifyAlexa, if_sync_send[F("va")]);
CJSON(notifyHue, if_sync_send[F("hue")]);
CJSON(notifyMacro, if_sync_send[F("macro")]);
CJSON(notifyTwice, if_sync_send[F("twice")]);
JsonObject if_live = interfaces[F("live")];
CJSON(receiveDirect, if_live[F("en")]);
CJSON(e131Port, if_live[F("port")]); // 5568
CJSON(e131Multicast, if_live[F("mc")]);
JsonObject if_live_dmx = if_live[F("dmx")];
CJSON(e131Universe, if_live_dmx[F("uni")]);
CJSON(e131SkipOutOfSequence, if_live_dmx[F("seqskip")]);
CJSON(DMXAddress, if_live_dmx[F("addr")]);
CJSON(DMXMode, if_live_dmx[F("mode")]);
tdd = if_live[F("timeout")] | -1;
if (tdd >= 0) realtimeTimeoutMs = tdd * 100;
CJSON(arlsForceMaxBri, if_live[F("maxbri")]);
CJSON(arlsDisableGammaCorrection, if_live[F("no-gc")]); // false
CJSON(arlsOffset, if_live[F("offset")]); // 0
CJSON(alexaEnabled, interfaces[F("va")][F("alexa")]); // false
CJSON(macroAlexaOn, interfaces[F("va")][F("macros")][0]);
CJSON(macroAlexaOff, interfaces[F("va")][F("macros")][1]);
const char* apikey = interfaces[F("blynk")][F("token")] | "Hidden";
tdd = strnlen(apikey, 36);
if (tdd > 20 || tdd == 0)
getStringFromJson(blynkApiKey, apikey, 36); //normally not present due to security
JsonObject if_mqtt = interfaces[F("mqtt")];
CJSON(mqttEnabled, if_mqtt[F("en")]);
getStringFromJson(mqttServer, if_mqtt[F("broker")], 33);
CJSON(mqttPort, if_mqtt[F("port")]); // 1883
getStringFromJson(mqttUser, if_mqtt[F("user")], 41);
getStringFromJson(mqttPass, if_mqtt["psk"], 41); //normally not present due to security
getStringFromJson(mqttClientID, if_mqtt[F("cid")], 41);
getStringFromJson(mqttDeviceTopic, if_mqtt[F("topics")][F("device")], 33); // "wled/test"
getStringFromJson(mqttGroupTopic, if_mqtt[F("topics")][F("group")], 33); // ""
JsonObject if_hue = interfaces[F("hue")];
CJSON(huePollingEnabled, if_hue[F("en")]);
CJSON(huePollLightId, if_hue[F("id")]);
tdd = if_hue[F("iv")] | -1;
if (tdd >= 2) huePollIntervalMs = tdd * 100;
JsonObject if_hue_recv = if_hue[F("recv")];
CJSON(hueApplyOnOff, if_hue_recv["on"]);
CJSON(hueApplyBri, if_hue_recv["bri"]);
CJSON(hueApplyColor, if_hue_recv[F("col")]);
JsonArray if_hue_ip = if_hue[F("ip")];
for (byte i = 0; i < 4; i++)
CJSON(hueIP[i], if_hue_ip[i]);
JsonObject if_ntp = interfaces[F("ntp")];
CJSON(ntpEnabled, if_ntp[F("en")]);
getStringFromJson(ntpServerName, if_ntp[F("host")], 33); // "1.wled.pool.ntp.org"
CJSON(currentTimezone, if_ntp[F("tz")]);
CJSON(utcOffsetSecs, if_ntp[F("offset")]);
CJSON(useAMPM, if_ntp[F("ampm")]);
JsonObject ol = doc[F("ol")];
CJSON(overlayDefault ,ol[F("clock")]); // 0
CJSON(countdownMode, ol[F("cntdwn")]);
overlayCurrent = overlayDefault;
JsonArray ol_cntdwn = ol[F("cntdwn")]; //[20,12,31,23,59,59]
//timed macro rules
JsonObject tm = doc[F("timers")];
JsonObject cntdwn = tm[F("cntdwn")];
JsonArray cntdwn_goal = cntdwn[F("goal")];
CJSON(countdownYear, cntdwn_goal[0]);
CJSON(countdownMonth, cntdwn_goal[1]);
CJSON(countdownDay, cntdwn_goal[2]);
CJSON(countdownHour, cntdwn_goal[3]);
CJSON(countdownMin, cntdwn_goal[4]);
CJSON(countdownSec, cntdwn_goal[5]);
CJSON(macroCountdown, cntdwn[F("macro")]);
JsonArray timers = tm[F("ins")];
uint8_t it = 0;
for (JsonObject timer : timers) {
if (it > 7) break;
CJSON(timerHours[it], timer[F("hour")]);
CJSON(timerMinutes[it], timer[F("min")]);
CJSON(timerMacro[it], timer[F("macro")]);
byte dowPrev = timerWeekday[it];
bool actPrev = timerWeekday[it] & 0x01;
CJSON(timerWeekday[it], timer[F("dow")]);
if (timerWeekday[it] != dowPrev) { //present in JSON
timerWeekday[it] <<= 1; //add active bit
bool act = timer[F("en")] | actPrev;
if (act) timerWeekday[it]++;
}
it++;
}
JsonObject ota = doc["ota"];
const char* pwd = ota["psk"]; //normally not present due to security
bool pwdCorrect = !otaLock; //always allow access if ota not locked
if (pwd != nullptr && strncmp(otaPass, pwd, 33) == 0) pwdCorrect = true;
if (pwdCorrect) { //only accept these values from cfg.json if ota is unlocked (else from wsec.json)
CJSON(otaLock, ota[F("lock")]);
CJSON(wifiLock, ota[F("lock-wifi")]);
CJSON(aOtaEnabled, ota[F("aota")]);
getStringFromJson(otaPass, pwd, 33); //normally not present due to security
}
#ifdef WLED_ENABLE_DMX
JsonObject dmx = doc["dmx"];
CJSON(DMXChannels, dmx[F("chan")]);
CJSON(DMXGap,dmx[F("gap")]);
CJSON(DMXStart, dmx[F("start")]);
CJSON(DMXStartLED,dmx[F("start-led")]);
JsonArray dmx_fixmap = dmx.createNestedArray("fixmap");
it = 0;
for (int i : dmx_fixmap) {
if (it > 14) break;
DMXFixtureMap[i] = i;
it++;
}
#endif
JsonObject usermods_settings = doc["um"];
usermods.readFromConfig(usermods_settings);
}
void serializeConfig() {
serializeConfigSec();
DEBUG_PRINTLN(F("Writing settings to /cfg.json..."));
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
//{ //scope this to reduce stack size
JsonArray rev = doc.createNestedArray("rev");
rev.add(1); //major settings revision
rev.add(0); //minor settings revision
doc[F("vid")] = VERSION;
JsonObject id = doc.createNestedObject("id");
id[F("mdns")] = cmDNS;
id[F("name")] = serverDescription;
id[F("inv")] = alexaInvocationName;
JsonObject nw = doc.createNestedObject("nw");
JsonArray nw_ins = nw.createNestedArray("ins");
JsonObject nw_ins_0 = nw_ins.createNestedObject();
nw_ins_0[F("ssid")] = clientSSID;
nw_ins_0[F("pskl")] = strlen(clientPass);
JsonArray nw_ins_0_ip = nw_ins_0.createNestedArray("ip");
JsonArray nw_ins_0_gw = nw_ins_0.createNestedArray("gw");
JsonArray nw_ins_0_sn = nw_ins_0.createNestedArray("sn");
for (byte i = 0; i < 4; i++) {
nw_ins_0_ip.add(staticIP[i]);
nw_ins_0_gw.add(staticGateway[i]);
nw_ins_0_sn.add(staticSubnet[i]);
}
JsonObject ap = doc.createNestedObject("ap");
ap[F("ssid")] = apSSID;
ap[F("pskl")] = strlen(apPass);
ap[F("chan")] = apChannel;
ap[F("behav")] = apBehavior;
JsonArray ap_ip = ap.createNestedArray("ip");
ap_ip.add(4);
ap_ip.add(3);
ap_ip.add(2);
ap_ip.add(1);
JsonObject wifi = doc.createNestedObject("wifi");
wifi[F("sleep")] = !noWifiSleep;
wifi[F("phy")] = 1;
JsonObject hw = doc.createNestedObject("hw");
JsonObject hw_led = hw.createNestedObject("led");
hw_led[F("total")] = ledCount;
hw_led[F("maxpwr")] = strip.ablMilliampsMax;
hw_led[F("ledma")] = strip.milliampsPerLed;
hw_led[F("rev")] = strip.reverseMode;
JsonArray hw_led_ins = hw_led.createNestedArray("ins");
JsonObject hw_led_ins_0 = hw_led_ins.createNestedObject();
hw_led_ins_0[F("en")] = true;
hw_led_ins_0[F("start")] = 0;
hw_led_ins_0[F("len")] = ledCount;
JsonArray hw_led_ins_0_pin = hw_led_ins_0.createNestedArray("pin");
hw_led_ins_0_pin.add(LEDPIN);
#ifdef DATAPIN
hw_led_ins_0_pin.add(DATAPIN);
#endif
hw_led_ins_0[F("order")] = strip.getColorOrder();
hw_led_ins_0[F("rev")] = false;
hw_led_ins_0[F("skip")] = skipFirstLed ? 1 : 0;
//this is very crude and temporary
byte ledType = TYPE_WS2812_RGB;
if (useRGBW) ledType = TYPE_SK6812_RGBW;
#ifdef USE_WS2801
ledType = TYPE_WS2801;
#endif
#ifdef USE_APA102
ledType = TYPE_APA102;
#endif
#ifdef USE_LPD8806
ledType = TYPE_LPD8806;
#endif
#ifdef USE_P9813
ledType = TYPE_P9813;
#endif
#ifdef USE_TM1814
ledType = TYPE_TM1814;
#endif
hw_led_ins_0[F("type")] = ledType;
JsonObject hw_btn = hw.createNestedObject("btn");
JsonArray hw_btn_ins = hw_btn.createNestedArray("ins");
#if defined(BTNPIN) && BTNPIN > -1
JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject();
hw_btn_ins_0[F("type")] = (buttonEnabled) ? BTN_TYPE_PUSH : BTN_TYPE_NONE;
JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin");
hw_btn_ins_0_pin.add(BTNPIN);
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros");
hw_btn_ins_0_macros.add(macroButton);
hw_btn_ins_0_macros.add(macroLongPress);
hw_btn_ins_0_macros.add(macroDoublePress);
#endif
#if defined(IRPIN) && IRPIN > -1
JsonObject hw_ir = hw.createNestedObject("ir");
hw_ir[F("pin")] = IRPIN;
hw_ir[F("type")] = 0;
#endif
#if defined(RLYPIN) && RLYPIN > -1
JsonObject hw_relay = hw.createNestedObject("relay");
hw_relay[F("pin")] = RLYPIN;
hw_relay[F("rev")] = (RLYMDE) ? false : true;
JsonObject hw_status = hw.createNestedObject("status");
hw_status[F("pin")] = -1;
#endif
JsonObject light = doc.createNestedObject("light");
light[F("scale-bri")] = briMultiplier;
light[F("pal-mode")] = strip.paletteBlend;
JsonObject light_gc = light.createNestedObject("gc");
light_gc["bri"] = (strip.gammaCorrectBri) ? 2.8 : 1.0;
light_gc[F("col")] = (strip.gammaCorrectCol) ? 2.8 : 1.0;
JsonObject light_tr = light.createNestedObject("tr");
light_tr[F("mode")] = fadeTransition;
light_tr[F("dur")] = transitionDelayDefault / 100;
light_tr[F("pal")] = strip.paletteFade;
JsonObject light_nl = light.createNestedObject("nl");
light_nl[F("mode")] = nightlightMode;
light_nl[F("dur")] = nightlightDelayMinsDefault;
light_nl[F("tbri")] = nightlightTargetBri;
light_nl[F("macro")] = macroNl;
JsonObject def = doc.createNestedObject("def");
def[F("ps")] = bootPreset;
def["on"] = turnOnAtBoot;
def["bri"] = briS;
//to be removed once preset cycles are presets
if (saveCurrPresetCycConf) {
JsonObject def_cy = def.createNestedObject("cy");
def_cy["on"] = presetCyclingEnabled;
JsonArray def_cy_range = def_cy.createNestedArray("range");
def_cy_range.add(presetCycleMin);
def_cy_range.add(presetCycleMax);
def_cy[F("dur")] = presetCycleTime / 100;
}
JsonObject interfaces = doc.createNestedObject("if");
JsonObject if_sync = interfaces.createNestedObject("sync");
if_sync[F("port0")] = udpPort;
if_sync[F("port1")] = udpPort2;
JsonObject if_sync_recv = if_sync.createNestedObject("recv");
if_sync_recv["bri"] = receiveNotificationBrightness;
if_sync_recv[F("col")] = receiveNotificationColor;
if_sync_recv[F("fx")] = receiveNotificationEffects;
JsonObject if_sync_send = if_sync.createNestedObject("send");
if_sync_send[F("dir")] = notifyDirect;
if_sync_send[F("btn")] = notifyButton;
if_sync_send[F("va")] = notifyAlexa;
if_sync_send[F("hue")] = notifyHue;
if_sync_send[F("macro")] = notifyMacro;
if_sync_send[F("twice")] = notifyTwice;
JsonObject if_live = interfaces.createNestedObject("live");
if_live[F("en")] = receiveDirect;
if_live[F("port")] = e131Port;
if_live[F("mc")] = e131Multicast;
JsonObject if_live_dmx = if_live.createNestedObject("dmx");
if_live_dmx[F("uni")] = e131Universe;
if_live_dmx[F("seqskip")] = e131SkipOutOfSequence;
if_live_dmx[F("addr")] = DMXAddress;
if_live_dmx[F("mode")] = DMXMode;
if_live[F("timeout")] = realtimeTimeoutMs / 100;
if_live[F("maxbri")] = arlsForceMaxBri;
if_live[F("no-gc")] = arlsDisableGammaCorrection;
if_live[F("offset")] = arlsOffset;
JsonObject if_va = interfaces.createNestedObject("va");
if_va[F("alexa")] = alexaEnabled;
JsonArray if_va_macros = if_va.createNestedArray("macros");
if_va_macros.add(macroAlexaOn);
if_va_macros.add(macroAlexaOff);
JsonObject if_blynk = interfaces.createNestedObject("blynk");
if_blynk[F("token")] = strlen(blynkApiKey) ? "Hidden":"";
JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
if_mqtt[F("en")] = mqttEnabled;
if_mqtt[F("broker")] = mqttServer;
if_mqtt[F("port")] = mqttPort;
if_mqtt[F("user")] = mqttUser;
if_mqtt[F("pskl")] = strlen(mqttPass);
if_mqtt[F("cid")] = mqttClientID;
JsonObject if_mqtt_topics = if_mqtt.createNestedObject("topics");
if_mqtt_topics[F("device")] = mqttDeviceTopic;
if_mqtt_topics[F("group")] = mqttGroupTopic;
JsonObject if_hue = interfaces.createNestedObject("hue");
if_hue[F("en")] = huePollingEnabled;
if_hue[F("id")] = huePollLightId;
if_hue[F("iv")] = huePollIntervalMs / 100;
JsonObject if_hue_recv = if_hue.createNestedObject("recv");
if_hue_recv["on"] = hueApplyOnOff;
if_hue_recv["bri"] = hueApplyBri;
if_hue_recv[F("col")] = hueApplyColor;
JsonArray if_hue_ip = if_hue.createNestedArray("ip");
for (byte i = 0; i < 4; i++) {
if_hue_ip.add(hueIP[i]);
}
JsonObject if_ntp = interfaces.createNestedObject("ntp");
if_ntp[F("en")] = ntpEnabled;
if_ntp[F("host")] = ntpServerName;
if_ntp[F("tz")] = currentTimezone;
if_ntp[F("offset")] = utcOffsetSecs;
if_ntp[F("ampm")] = useAMPM;
JsonObject ol = doc.createNestedObject("ol");
ol[F("clock")] = overlayDefault;
ol[F("cntdwn")] = countdownMode;
JsonObject timers = doc.createNestedObject("timers");
JsonObject cntdwn = timers.createNestedObject("cntdwn");
JsonArray goal = cntdwn.createNestedArray("goal");
goal.add(countdownYear); goal.add(countdownMonth); goal.add(countdownDay);
goal.add(countdownHour); goal.add(countdownMin); goal.add(countdownSec);
cntdwn[F("macro")] = macroCountdown;
JsonArray timers_ins = timers.createNestedArray("ins");
for (byte i = 0; i < 8; i++) {
if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue;
JsonObject timers_ins0 = timers_ins.createNestedObject();
timers_ins0[F("en")] = (timerWeekday[i] & 0x01);
timers_ins0[F("hour")] = timerHours[i];
timers_ins0[F("min")] = timerMinutes[i];
timers_ins0[F("macro")] = timerMacro[i];
timers_ins0[F("dow")] = timerWeekday[i] >> 1;
}
JsonObject ota = doc.createNestedObject("ota");
ota[F("lock")] = otaLock;
ota[F("lock-wifi")] = wifiLock;
ota[F("pskl")] = strlen(otaPass);
ota[F("aota")] = aOtaEnabled;
#ifdef WLED_ENABLE_DMX
JsonObject dmx = doc.createNestedObject("dmx");
dmx[F("chan")] = DMXChannels;
dmx[F("gap")] = DMXGap;
dmx[F("start")] = DMXStart;
dmx[F("start-led")] = DMXStartLED;
JsonArray dmx_fixmap = dmx.createNestedArray("fixmap");
for (byte i = 0; i < 15; i++)
dmx_fixmap.add(DMXFixtureMap[i]);
#endif
//}
JsonObject usermods_settings = doc.createNestedObject("um");
usermods.addToConfig(usermods_settings);
File f = WLED_FS.open("/cfg.json", "w");
if (f) serializeJson(doc, f);
f.close();
}
//settings in /wsec.json, not accessible via webserver, for passwords and tokens
bool deserializeConfigSec() {
DEBUG_PRINTLN(F("Reading settings from /wsec.json..."));
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
bool success = readObjectFromFile("/wsec.json", nullptr, &doc);
if (!success) return false;
JsonObject nw_ins_0 = doc["nw"][F("ins")][0];
getStringFromJson(clientPass, nw_ins_0["psk"], 65);
JsonObject ap = doc[F("ap")];
getStringFromJson(apPass, ap["psk"] , 65);
JsonObject interfaces = doc["if"];
const char* apikey = interfaces["blynk"][F("token")] | "Hidden";
int tdd = strnlen(apikey, 36);
if (tdd > 20 || tdd == 0)
getStringFromJson(blynkApiKey, apikey, 36);
JsonObject if_mqtt = interfaces[F("mqtt")];
getStringFromJson(mqttPass, if_mqtt["psk"], 41);
getStringFromJson(hueApiKey, interfaces[F("hue")][F("key")], 47);
JsonObject ota = doc["ota"];
getStringFromJson(otaPass, ota[F("pwd")], 33);
CJSON(otaLock, ota[F("lock")]);
CJSON(wifiLock, ota[F("lock-wifi")]);
CJSON(aOtaEnabled, ota[F("aota")]);
return true;
}
void serializeConfigSec() {
DEBUG_PRINTLN(F("Writing settings to /wsec.json..."));
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
JsonObject nw = doc.createNestedObject("nw");
JsonArray nw_ins = nw.createNestedArray("ins");
JsonObject nw_ins_0 = nw_ins.createNestedObject();
nw_ins_0["psk"] = clientPass;
JsonObject ap = doc.createNestedObject("ap");
ap["psk"] = apPass;
JsonObject interfaces = doc.createNestedObject("if");
JsonObject if_blynk = interfaces.createNestedObject("blynk");
if_blynk[F("token")] = blynkApiKey;
JsonObject if_mqtt = interfaces.createNestedObject("mqtt");
if_mqtt["psk"] = mqttPass;
JsonObject if_hue = interfaces.createNestedObject("hue");
if_hue[F("key")] = hueApiKey;
JsonObject ota = doc.createNestedObject("ota");
ota[F("pwd")] = otaPass;
ota[F("lock")] = otaLock;
ota[F("lock-wifi")] = wifiLock;
ota[F("aota")] = aOtaEnabled;
File f = WLED_FS.open("/wsec.json", "w");
if (f) serializeJson(doc, f);
f.close();
}

View File

@@ -62,7 +62,31 @@ void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
}
void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb
void colorKtoRGB(uint16_t kelvin, byte* rgb) //white spectrum to rgb, calc
{
float r = 0, g = 0, b = 0;
float temp = kelvin / 100;
if (temp <= 66) {
r = 255;
g = round(99.4708025861 * log(temp) - 161.1195681661);
if (temp <= 19) {
b = 0;
} else {
b = round(138.5177312231 * log((temp - 10)) - 305.0447927307);
}
} else {
r = round(329.698727446 * pow((temp - 60), -0.1332047592));
g = round(288.1221695283 * pow((temp - 60), -0.0755148492));
b = 255;
}
g += 15; //mod by Aircoookie, a bit less accurate but visibly less pinkish
rgb[0] = (uint8_t) constrain(r, 0, 255);
rgb[1] = (uint8_t) constrain(g, 0, 255);
rgb[2] = (uint8_t) constrain(b, 0, 255);
rgb[3] = 0;
}
void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb, bins
{
//this is only an approximation using WS2812B with gamma correction enabled
if (mired > 475) {
@@ -140,7 +164,7 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www
rgb[0] = 255.0*r;
rgb[1] = 255.0*g;
rgb[2] = 255.0*b;
if (useRGBW) colorRGBtoRGBW(col);
if (useRGBW && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
}
void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
@@ -153,7 +177,7 @@ void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.develo
}
#endif // WLED_DISABLE_HUESYNC
//RRGGBB / WWRRGGBB order for hex
void colorFromDecOrHexString(byte* rgb, char* in)
{
if (in[0] == 0) return;
@@ -174,6 +198,27 @@ void colorFromDecOrHexString(byte* rgb, char* in)
rgb[2] = c & 0xFF;
}
//contrary to the colorFromDecOrHexString() function, this uses the more standard RRGGBB / RRGGBBWW order
bool colorFromHexString(byte* rgb, const char* in) {
if (in == nullptr) return false;
size_t inputSize = strnlen(in, 9);
if (inputSize != 6 && inputSize != 8) return false;
uint32_t c = strtoul(in, NULL, 16);
if (inputSize == 6) {
rgb[0] = (c >> 16) & 0xFF;
rgb[1] = (c >> 8) & 0xFF;
rgb[2] = c & 0xFF;
} else {
rgb[0] = (c >> 24) & 0xFF;
rgb[1] = (c >> 16) & 0xFF;
rgb[2] = (c >> 8) & 0xFF;
rgb[3] = c & 0xFF;
}
return true;
}
float minf (float v, float w)
{
if (w > v) return v;

View File

@@ -10,6 +10,18 @@
#define DEFAULT_AP_PASS "wled1234"
#define DEFAULT_OTA_PASS "wledota"
//increase if you need more
#define WLED_MAX_USERMODS 4
//Usermod IDs
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
#define USERMOD_ID_EXAMPLE 2 //Usermod "usermod_v2_example.h"
#define USERMOD_ID_TEMPERATURE 3 //Usermod "usermod_temperature.h"
#define USERMOD_ID_FIXNETSERVICES 4 //Usermod "usermod_Fix_unreachable_netservices.h"
#define USERMOD_ID_PIRSWITCH 5 //Usermod "usermod_PIR_sensor_switch.h"
#define USERMOD_ID_IMU 6 //Usermod "usermod_mpu6050_imu.h"
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
#define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost)
@@ -44,6 +56,8 @@
#define REALTIME_MODE_E131 4
#define REALTIME_MODE_ADALIGHT 5
#define REALTIME_MODE_ARTNET 6
#define REALTIME_MODE_TPM2NET 7
#define REALTIME_MODE_DDP 8
//realtime override modes
#define REALTIME_OVERRIDE_NONE 0
@@ -58,20 +72,55 @@
#define DMX_MODE_MULTIPLE_RGB 4 //every LED is addressed with its own RGB (ledCount * 3 channels)
#define DMX_MODE_MULTIPLE_DRGB 5 //every LED is addressed with its own RGB and share a master dimmer (ledCount * 3 + 1 channels)
//Light capability byte (unused)
//Light capability byte (unused) 0bRRCCTTTT
//bits 0/1/2/3: specifies a type of LED driver. A single "driver" may have different chip models but must have the same protocol/behavior
//bits 4/5: specifies the class of LED driver - 0b00 (dec. 0-15) unconfigured/reserved
// - 0b01 (dec. 16-31) digital (data pin only)
// - 0b10 (dec. 32-47) analog (PWM)
// - 0b11 (dec. 48-63) digital (data + clock / SPI)
//bits 6/7 are reserved and set to 0b00
#define TYPE_NONE 0 //light is not configured
#define TYPE_RESERVED 1 //unused. Might indicate a "virtual" light
#define TYPE_WS2812_RGB 2
#define TYPE_SK6812_RGBW 3
#define TYPE_WS2812_WWA 4 //amber + warm + cold white
#define TYPE_WS2801 5
#define TYPE_ANALOG_1CH 6 //single channel PWM. Uses value of brightest RGBW channel
#define TYPE_ANALOG_2CH 7 //analog WW + CW
#define TYPE_ANALOG_3CH 8 //analog RGB
#define TYPE_ANALOG_4CH 9 //analog RGBW
#define TYPE_ANALOG_5CH 10 //analog RGB + WW + CW
#define TYPE_APA102 11
#define TYPE_LPD8806 12
//Digital types (data pin only) (16-31)
#define TYPE_WS2812_1CH 20 //white-only chips
#define TYPE_WS2812_WWA 21 //amber + warm + cold white
#define TYPE_WS2812_RGB 22
#define TYPE_GS8608 23 //same driver as WS2812, but will require signal 2x per second (else displays test pattern)
#define TYPE_WS2811_400KHZ 24 //half-speed WS2812 protocol, used by very old WS2811 units
#define TYPE_SK6812_RGBW 30
//"Analog" types (PWM) (32-47)
#define TYPE_ONOFF 40 //binary output (relays etc.)
#define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel
#define TYPE_ANALOG_2CH 42 //analog WW + CW
#define TYPE_ANALOG_3CH 43 //analog RGB
#define TYPE_ANALOG_4CH 44 //analog RGBW
#define TYPE_ANALOG_5CH 45 //analog RGB + WW + CW
//Digital types (data + clock / SPI) (48-63)
#define TYPE_WS2801 50
#define TYPE_APA102 51
#define TYPE_LPD8806 52
#define TYPE_P9813 53
#define TYPE_TM1814 54
//Color orders
#define COL_ORDER_GRB 0 //GRB(w),defaut
#define COL_ORDER_RGB 1 //common for WS2811
#define COL_ORDER_BRG 2
#define COL_ORDER_RBG 3
#define COL_ORDER_BGR 4
#define COL_ORDER_GBR 5
//Button type
#define BTN_TYPE_NONE 0
#define BTN_TYPE_RESERVED 1
#define BTN_TYPE_PUSH 2
#define BTN_TYPE_PUSH_ACT_HIGH 3 //not implemented
#define BTN_TYPE_SWITCH 4 //not implemented
#define BTN_TYPE_SWITCH_ACT_HIGH 5 //not implemented
//Hue error codes
#define HUE_ERROR_INACTIVE 0
@@ -86,15 +135,34 @@
#define SEG_OPTION_SELECTED 0
#define SEG_OPTION_REVERSED 1
#define SEG_OPTION_ON 2
#define SEG_OPTION_MIRROR 3 //Indicates that the effect will be mirrored within the segment
#define SEG_OPTION_NONUNITY 4 //Indicates that the effect does not use FRAMETIME or needs getPixelColor
#define SEG_OPTION_FREEZE 5 //Segment contents will not be refreshed
#define SEG_OPTION_TRANSITIONAL 7
//EEPROM size
#define EEPSIZE 2560 //Maximum is 4096
// WLED Error modes
#define ERR_NONE 0 // All good :)
#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?)
#define ERR_JSON 9 // JSON parsing failed (input too large?)
#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?)
#define ERR_FS_QUOTA 11 // The FS is full or the maximum file size is reached
#define ERR_FS_PLOAD 12 // It was attempted to load a preset that does not exist
#define ERR_FS_GENERAL 19 // A general unspecified filesystem error occured
//Timer mode types
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
#define NL_MODE_FADE 1 //Fade to target brightness gradually
#define NL_MODE_COLORFADE 2 //Fade to target brightness and secondary color gradually
#define NL_MODE_SUN 3 //Sunrise/sunset. Target brightness is set immediately, then Sunrise effect is started. Max 60 min.
#define NTP_PACKET_SIZE 48
// maximum number of LEDs - MAX_LEDS is coming from the JSON response getting too big, MAX_LEDS_DMA will become a timing issue
// maximum number of LEDs - more than 1500 LEDs (or 500 DMA "LEDPIN 3" driven ones) will cause a low memory condition on ESP8266
#ifndef MAX_LEDS
#define MAX_LEDS 1500
#endif
#define MAX_LEDS_DMA 500
// string temp buffer (now stored in stack locally)
@@ -104,4 +172,14 @@
#define ABL_MILLIAMPS_DEFAULT 850; // auto lower brightness to stay close to milliampere limit
#define TOUCH_THRESHOLD 32 // limit to recognize a touch, higher value means more sensitive
// Size of buffer for API JSON object (increase for more segments)
#ifdef ESP8266
#define JSON_BUFFER_SIZE 9216
#else
#define JSON_BUFFER_SIZE 16384
#endif
#endif

47
wled00/data/404.htm Normal file
View File

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content='width=device-width' name='viewport'>
<meta name="theme-color" content="#222222">
<title>Not found</title>
<style>
body {
font-family: Verdana, Helvetica, sans-serif;
text-align: center;
background-color: #222;
margin: 0;
color: #fff;
}
img {
width: 400px;
max-width: 50%;
image-rendering: pixelated;
image-rendering: crisp-edges;
margin: 25px 0 -10px 0;
}
button {
outline: none;
cursor: pointer;
padding: 8px;
margin: 10px;
width: 230px;
text-transform: uppercase;
font-family: helvetica;
font-size: 19px;
background-color: #333;
color: white;
border: 0px solid white;
border-radius: 25px;
}
</style>
</head>
<body>
<img alt="" src=" data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsEAAA7BAbiRa+0AAAFMSURBVFhH7ZTfbYNADMaPKDNUrJA85CEjdIjOgNQV+sASlZgmI/AIK6AuQfngnDrmjtpHItQ/P+l0juHsz2cH9+fJ/G7nreldfnDnp+ln/ZIlxbIfQmIwJOekCrEJ8FUvASEWEXoBiuSERcTO75uhuwFWff86bi57n3ZC+rW3YLqB5rn11ldCEPNr2LwFJgHHy8G1bTsu3oKYX4N5BrQ8ZAYewSoBGDjr0ElWCUC/rT2X7MqynL7tG4Dc45BwEYM9H5w7DqHMdfNCURR9nue3Iobk55MtOYeLoOQ8vmoG6o+0FaLrOm9FwC3wayLgx5I2WHpGIGYorulfgPYQ3AZLz4hQ9TMBVVVleJGrRUWz2YgQOg8bPjzzrit7vwcRQb5NTiARRPPzMYItoCpoWZITMkao+mRkddpqQ6z6FN+DfwFJrOm55GfewC/CuU/E4tQYg7BPYQAAAABJRU5ErkJggg==">
<h1>404 Not Found</h1>
<b>Akemi does not know where you are headed...</b><br><br>
<button onclick="window.location.href='/sliders'">Back to controls</button>
</body>
</html>

28
wled00/data/dmxmap.htm Normal file
View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html><head><meta content='width=device-width' name='viewport'>
<title>DMX Map</title>
<script>function B(){window.history.back()};function RS(){window.location = "/settings";}function RP(){top.location.href="/";}function FM() {
var dmxlabels = ["SET 0","RED","GREEN","BLUE","WHITE","SHUTTER","SET 255", "DISABLED"];
var dmxchans = [];
for (i=0;i<512;i++) {
dmxchans.push(7); // set all to DISABLED
}
for (i=0;i<LC;i++) {
FS = CS + (CG * i);
for (j=0;j<CN;j++) {
DA=FS+j;
dmxchans[DA-1] = CH[j];
}
}
DMXMap = "";
for (i=0;i<512;i++) {
isstart = "";
if ((i+1) % 10 == 0) {
isstart="S"
}
DMXMap += "<div class=\"anytype " + isstart + " type" + dmxchans[i] + "\">" + String(i+1) + "<br />" + dmxlabels[dmxchans[i]] + "</div>";
}
document.getElementById("map").innerHTML = DMXMap;
}</script>
<style>.anytype{border: 1px solid white; margin: 1px; float: left; width: 100px; height: 100px;}.S { margin: 0px; border: 2px solid white;} .type7{color: #888; border: 1px dotted grey;}.type6{color: #FFF;}.type4{color: #FFF; font-weight: bold; }.type3{color: #00F; font-weight: bold; }.type2{color: #0F0; font-weight: bold; }.type1{color: #F00; font-weight: bold; } .bt{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}</style></head>
<body onload="FM();"><div id="map">...</div></body></html>

File diff suppressed because one or more lines are too long

View File

@@ -1,56 +1,36 @@
<!DOCTYPE html>
<html><head>
<html>
<head>
<meta content='width=device-width' name='viewport'>
<title>WLED Message</title>
<script>
function B() {
window.history.back();
}
function RS() {
window.location = "/settings";
}
function RP() {
top.location.href="/";
}
</script>
<script>function B() { window.history.back() }; function RS() { window.location = "/settings"; } function RP() { top.location.href = "/"; }</script>
<style>
:root {
--aCol: #D9B310;
--bCol: #0B3C5D;
--cCol: #1D2731;
--dCol: #328CC1;
--sCol: #000;
--tCol: #328CC1;
--cFn: Verdana;
}
.bt {
background: var(--bCol);
color: var(--tCol);
border: 0.3ch solid var(--bCol);
background: #333;
color: #fff;
font-family: Verdana, sans-serif;
border: .3ch solid #333;
display: inline-block;
filter: drop-shadow( -5px -5px 5px var(--sCol) );
font-family: var(--cFn), sans-serif;
font-size: 20px;
margin: 8px;
margin-top: 12px;
margin-top: 12px
}
input[type=file] {
font-size: 16px;
}
body {
font-family: var(--cFn), sans-serif;
font-family: Verdana, sans-serif;
text-align: center;
background: var(--cCol);
color: var(--tCol);
line-height: 200%;
margin: 0;
background-attachment: fixed;
background: #222;
color: #fff;
line-height: 200%%;
margin: 0
}
</style>
</head>
<body>
<h2>Sample message.</h2>
Sample detail.
<h2>Sample Message.</h2>
Sample Detail.
</body>
</html>
</html>

View File

@@ -3,34 +3,23 @@
<head><meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>WLED Settings</title>
<style>
:root {
--aCol: #D9B310;
--bCol: #0B3C5D;
--cCol: #1D2731;
--dCol: #328CC1;
--sCol: #000;
--tCol: #328CC1;
--cFn: Verdana;
}
body {
text-align: center;
background: var(--cCol);
height: 100%;
background: #222;
height: 100;
margin: 0;
background-attachment: fixed;
}
html {
--h:11.55vh;
--h: 11.55vh;
}
button {
background: var(--bCol);
color: var(--tCol);
font-family: var(--cFn), Helvetica, sans-serif;
border: 0.3ch solid var(--bCol);
background: #333;
color: #fff;
font-family: Verdana, Helvetica, sans-serif;
border: 0.3ch solid #333;
display: inline-block;
filter: drop-shadow( -5px -5px 5px var(--sCol) );
font-size: 8vmin;
height:var(--h);
height: var(--h);
width: 95%;
margin-top: 2.4vh;
}

View File

@@ -0,0 +1,59 @@
<!DOCTYPE html>
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>DMX Settings</title>
<script>
function GCH(num) {
d=document;
d.getElementById('dmxchannels').innerHTML += "";
for (i=0;i<num;i++) {
d.getElementById('dmxchannels').innerHTML += "<span id=CH" + (i+1) + "s >Channel " + (i+1) + ": <select name=CH" + (i+1) + " id=\"CH" + (i+1) + "\"><option value=0>Set to 0</option><option value=1>Red</option><option value=2>Green</option><option value=3>Blue</option><option value=4>White</option><option value=5>Shutter (Brightness)</option><option value=6>Set to 255</option></select></span><br />\n";
}
}
function mMap(){
d=document;
numCh=document.Sf.CN.value;
numGap=document.Sf.CG.value;
if (parseInt(numCh)>parseInt(numGap)) {
d.getElementById("gapwarning").style.display="block";
} else {
d.getElementById("gapwarning").style.display="none";
}
for (i=0;i<15;i++) {
if (i>=numCh) {
d.getElementById("CH"+(i+1) + "s").style.opacity = "0.5";
d.getElementById("CH"+(i+1)).disabled = true;
} else {
d.getElementById("CH"+(i+1) + "s").style.opacity = "1";
d.getElementById("CH"+(i+1)).disabled = false;
}
}
}
function S(){GCH(15);GetV();mMap();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}function B(){window.history.back();}
function GetV(){}
</script>
<style>
@import url("style.css");
</style>
</head>
<body onload="S()">
<form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<h2>Imma firin ma lazer (if it has DMX support)</h2><!-- TODO: Change to something less-meme-related //-->
Proxy Universe <input name=PU type=number min=0 max=63999 required> from E1.31 to DMX (0=disabled)<br>
<i>This will disable the LED data output to DMX configurable below</i><br><br>
<i>Number of fixtures is taken from LED config page</i><br>
Channels per fixture (15 max): <input type="number" min="1" max="15" name="CN" maxlength="2" onchange="mMap();"><br />
Start channel: <input type="number" min="1" max="512" name="CS" maxlength="2"><br />
Spacing between start channels: <input type="number" min="1" max="512" name="CG" maxlength="2" onchange="mMap();"> [ <a href="javascript:alert('if set to 10, first fixture will start at 10,\nsecond will start at 20 etc.\nRegardless of the channel count.\nMakes memorizing channel numbers easier.');">info</a> ]<br>
<div id="gapwarning" style="color: orange; display: none;">WARNING: Channel gap is lower than channels per fixture.<br />This will cause overlap.</div>
<button type="button" onclick="location.href='/dmxmap';">DMX Map</button><br>
DMX fixtures start LED: <input type="number" min="0" max="1500" name="SL">
<h3>Channel functions</h3>
<div id="dmxchannels"></div>
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
</form>
</body>
</html>

Binary file not shown.

View File

@@ -2,6 +2,7 @@
<html>
<head>
<meta name="viewport" content="width=500">
<meta charset="utf-8">
<title>Misc Settings</title>
<script>
function H()
@@ -22,51 +23,7 @@
}
</script>
<style>
:root {
--aCol: #D9B310;
--bCol: #0B3C5D;
--cCol: #1D2731;
--dCol: #328CC1;
--sCol: #000;
}
body {
font-family: Verdana, Helvetica, sans-serif;
text-align: center;
background: var(--cCol);
color: var(--dCol);
line-height: 2em;
font-size: 16px;
margin: 0;
background-attachment: fixed;
}
hr {
border-color: var(--dCol);
filter: drop-shadow( -5px -5px 5px var(--sCol) );
}
button {
background: var(--bCol);
color: var(--dCol);
border: 0.3ch solid var(--bCol);
display: inline-block;
filter: drop-shadow( -5px -5px 5px var(--sCol) );
font-size: 20px;
margin: 8px;
margin-top: 12px;
}
.helpB {
text-align: left;
position: absolute;
width:60px;
}
input {
background: var(--bCol);
color: var(--dCol);
border: 0.5ch solid var(--bCol);
filter: drop-shadow( -5px -5px 5px var(--sCol) );
}
input[type=number] {
width: 3em;
}
@import url("style.css");
</style>
</head>
<body onload="GetV()">
@@ -88,11 +45,11 @@
<button type="button" onclick="U()">Manual OTA Update</button><br>
Enable ArduinoOTA: <input type="checkbox" name="AO"><br>
<h3>About</h3>
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.10.0<br><br>
<a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> version ##VERSION##<!-- Autoreplaced from package.json --><br><br>
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-&-About" target="_blank">Contributors, dependencies and special thanks</a><br>
A huge thank you to everyone who helped me create WLED!<br><br>
(c) 2016-2019 Christian Schwinne <br>
<i>Licensed under the MIT license</i><br><br>
(c) 2016-2020 Christian Schwinne <br>
<i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">MIT license</a></i><br><br>
Server message: <span class="sip"> Response error! </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
</form>

View File

@@ -1,14 +1,15 @@
<!DOCTYPE html>
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>Sync Settings</title>
<script>var d=document;
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings");}function B(){window.open("/settings","_self");}function GetV(){var d=document;}
function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.DA.value == 1) d.Sf.DA.value = 0; if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;}
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings");}function B(){window.open("/settings","_self");}
function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.DA.value == 1) d.Sf.DA.value = 0; if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;}
else if (d.Sf.DI.value == 5568) {if (d.Sf.DA.value == 0) d.Sf.DA.value = 1; if (d.Sf.EU.value == 0) d.Sf.EU.value = 1;} }
function SP(){var p = d.Sf.DI.value; d.getElementById("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;}
function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; }; SP();}
function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; case 4048: d.Sf.DI.value = 4048; break; }; SP();}
function S(){GetV();SetVal();}
function GetV(){var d=document;}
</script>
<style>body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%;margin:0}hr{border-color:#666}button{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}.helpB{text-align:left;position:absolute;width:60px}input{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}input[type=number]{width:4em}select{background:#333;color:#fff;font-family:Verdana,sans-serif;border:0.5ch solid #333}td{padding:2px;}.d5{width:4.5em !important;}</style></head>
<style>@import url("style.css");</style></head>
<body onload="S()">
<form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
@@ -25,24 +26,28 @@ Infrared remote:
<option value=4>44-key RGB</option>
<option value=5>21-key RGB</option>
<option value=6>6-key black</option>
<option value=7>9-key red</option>
</select><br>
<a href="https://github.com/Aircoookie/WLED/wiki/Infrared-Control" target="_blank">IR info</a>
<h3>WLED Broadcast</h3>
UDP Port: <input name="UP" type="number" min="1" max="65535" class="d5" required><br>
2nd Port: <input name="U2" type="number" min="1" max="65535" class="d5" required><br>
Receive <input type="checkbox" name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input type="checkbox" name="RX">Effects<br>
Send notifications on direct change: <input type="checkbox" name="SD"><br>
Send notifications on button press: <input type="checkbox" name="SB"><br>
Send Alexa notifications: <input type="checkbox" name="SA"><br>
Send Philips Hue change notifications: <input type="checkbox" name="SH"><br>
Send Macro notifications: <input type="checkbox" name="SM"><br>
Send notifications twice: <input type="checkbox" name="S2">
Send notifications twice: <input type="checkbox" name="S2"><br>
<i>Reboot required to apply changes. </i>
<h3>Realtime</h3>
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
<i>Network DMX input</i><br>
Type:
Type:
<select name=DI onchange="SP(); adj();">
<option value=5568>E1.31 (sACN)</option>
<option value=6454>Art-Net</option>
<option value=4048>DDP</option>
<option value=0 selected>Custom port</option>
</select><br>
<div id=xp>Port: <input name="EP" type="number" min="1" max="65535" value="5568" class="d5" required><br></div>
@@ -58,7 +63,7 @@ DMX mode:
<option value=2>Single DRGB</option>
<option value=3>Effect</option>
<option value=4>Multi RGB</option>
<option value=5>Multi DRGB</option>
<option value=5>Dimmer + Multi RGB</option>
</select><br>
<a href="https://github.com/Aircoookie/WLED/wiki/E1.31-DMX" target="_blank">E1.31 info</a><br>
Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
@@ -98,7 +103,7 @@ Hue Bridge IP:<br>
<input name="H3" type="number" min="0" max="255" ><br>
<b>Press the pushlink button on the bridge, after that save this page!</b><br>
(when first connecting)<br>
Hue status: <span class="hms"> Disabled in this build </span><hr>
Hue status: <span class="sip"> Disabled in this build </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
</form>
</body>

View File

@@ -2,6 +2,7 @@
<html>
<head>
<meta name="viewport" content="width=500">
<meta charset="utf-8">
<title>Time Settings</title>
<script>
var d=document;
@@ -42,10 +43,10 @@
}
function BTa()
{
var ih="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Macro</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";
var ih="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Preset</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";
for (i=0;i<8;i++)
{
ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" type=\"number\" min=\"0\" max=\"16\"></td>";
ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" type=\"number\" min=\"0\" max=\"250\"></td>";
for (j=1;j<8;j++) ih+="<td><input id=\"W"+i+j+"\" type=\"checkbox\"></td>";
}
gId("TMT").innerHTML=ih;
@@ -76,64 +77,7 @@
}
</script>
<style>
:root {
--aCol: #D9B310;
--bCol: #0B3C5D;
--cCol: #1D2731;
--dCol: #328CC1;
--sCol: #000;
--tCol: #328CC1;
--cFn: Verdana;
}
body {
font-family: var(--cFn), sans-serif;
text-align: center;
background: var(--cCol);
color: var(--dCol);
line-height: 200%;
margin: 0;
background-attachment: fixed;
}
hr {
border-color: var(--dCol);
filter: drop-shadow( -5px -5px 5px var(--sCol) );
}
button {
background: var(--bCol);
color: var(--dCol);
border: 0.3ch solid var(--bCol);
font-family: var(--cFn), sans-serif;
display: inline-block;
filter: drop-shadow( -5px -5px 5px var(--sCol) );
font-size: 20px;
margin: 8px;
margin-top: 12px;
}
.helpB {
text-align: left;
position: absolute;
width:60px;
}
input {
background: var(--bCol);
color: var(--dCol);
font-family: var(--cFn), sans-serif;
border: 0.5ch solid var(--bCol);
filter: drop-shadow( -5px -5px 5px var(--sCol) );
}
select {
background: var(--bCol);
color: var(--dCol);
border: 0.5ch solid var(--bCol);
font-family: var(--cFn), sans-serif;
filter: drop-shadow( -5px -5px 5px var(--sCol) );
}
td {
padding:2px;
}
input[type=number] {
width: 4em;
}
@import url("style.css");
</style>
</head>
<body onload="S()">
@@ -159,7 +103,12 @@
<option value="10">JST(KST)</option>
<option value="11">AEST/AEDT</option>
<option value="12">NZST/NZDT</option>
<option value="13">North Korea</option>
<option value="13">North Korea</option>
<option value="14">IST (India)</option>
<option value="15">CA-Saskatchewan</option>
<option value="16">ACST</option>
<option value="17">ACST/ACDT</option>
<option value="18">HST (Hawaii)</option>
</select><br>
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
Current local time is <span class="times">unknown</span>.
@@ -186,31 +135,17 @@
Countdown Goal:<br>
Year: 20 <input name="CY" type="number" min="0" max="99" required> Month: <input name="CI" type="number" min="1" max="12" required> Day: <input name="CD" type="number" min="1" max="31" required><br>
Hour: <input name="CH" type="number" min="0" max="23" required> Minute: <input name="CM" type="number" min="0" max="59" required> Second: <input name="CS" type="number" min="0" max="59" required><br>
<h3>Advanced Macros</h3>
Define API macros here:<br>
1: <input name="M1" maxlength="64"><br>
2: <input name="M2" maxlength="64"><br>
3: <input name="M3" maxlength="64"><br>
4: <input name="M4" maxlength="64"><br>
5: <input name="M5" maxlength="64"><br>
6: <input name="M6" maxlength="64"><br>
7: <input name="M7" maxlength="64"><br>
8: <input name="M8" maxlength="64"><br>
9: <input name="M9" maxlength="64"><br>
10: <input name="M10" maxlength="64"><br>
11: <input name="M11" maxlength="64"><br>
12: <input name="M12" maxlength="64"><br>
13: <input name="M13" maxlength="64"><br>
14: <input name="M14" maxlength="64"><br>
15: <input name="M15" maxlength="64"><br>
16: <input name="M16" maxlength="64"><br><br>
<i>Use 0 for the default action instead of a macro</i><br>
Boot Macro: <input name="MB" type="number" min="0" max="16" required><br>
Alexa On/Off Macros: <input name="A0" type="number" min="0" max="16" required> <input name="A1" type="number" min="0" max="16" required><br>
Button Macro: <input name="MP" type="number" min="0" max="16" required> Long Press: <input name="ML" type="number" min="0" max="16" required><br>
Countdown-Over Macro: <input name="MC" type="number" min="0" max="16" required><br>
Timed-Light-Over Macro: <input name="MN" type="number" min="0" max="16" required><br>
Time-Controlled Macros:<br>
<h3>Macro presets</h3>
<b>Macros have moved!</b><br>
<i>Presets now also can be used as macros to save both JSON and HTTP API commands.<br>
Just enter the preset id below!</i>
<i>Use 0 for the default action instead of a preset</i><br>
Alexa On/Off Preset: <input name="A0" type="number" min="0" max="250" required> <input name="A1" type="number" min="0" max="250" required><br>
Button short press Preset: <input name="MP" type="number" min="0" max="250" required><br>
Long Press: <input name="ML" type="number" min="0" max="250" required> Double press: <input name="MD" type="number" min="0" max="250" required><br>
Countdown-Over Preset: <input name="MC" type="number" min="0" max="250" required><br>
Timed-Light-Over Presets: <input name="MN" type="number" min="0" max="250" required><br>
<h3>Time-controlled presets</h3>
<div style="display: inline-block">
<table id="TMT">
</table></div><hr>

View File

@@ -1,16 +1,152 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=500">
<title>UI Settings</title>
<script>
var d = document;
var initial_ds, initial_st;
var sett = null;
var l = {
"comp":{
"labels":"Show button labels",
"colors":{
"LABEL":"Color selection methods",
"picker": "Color Wheel",
"rgb": "RGB sliders",
"quick": "Quick color selectors",
"hex": "HEX color input"
},
"pcmbot": "Show bottom tab bar in PC mode"
},
"theme":{
"alpha": {
"bg":"Background opacity",
"tab":"Button opacity"
},
"bg":{
"url":"BG image URL"
},
"color":{
"bg":"BG HEX color"
}
}
};
function gId(s)
{
return document.getElementById(s);
return d.getElementById(s);
}
function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
}
function set(path, obj, val) {
var tar = obj;
var pList = path.split('_');
var len = pList.length;
for(var i = 0; i < len-1; i++) {
var elem = pList[i];
if( !tar[elem] ) tar[elem] = {}
tar = tar[elem];
}
tar[pList[len-1]] = val;
}
function addRec(s, path = "", label = null)
{
var str = "";
for (i in s)
{
var fk = path + (path?'_':'') + i;
if (isObject(s[i])) {
if (label && label[i] && label[i]["LABEL"]) str += `<h3>${label[i]["LABEL"]}</h3>`;
str += addRec(s[i], fk, label? label[i] : null);
} else {
var lb = fk;
if (label && label[i]) lb = label[i];
else if (s[i+'LABEL']) lb = s[i+'LABEL'];
if (i.indexOf('LABEL') > 0) continue;
var t = typeof s[i];
if (gId(fk)) { //already exists
if(t === 'boolean')
{
gId(fk).checked = s[i];
} else {
gId(fk).value = s[i];
}
if (gId(fk).previousElementSibling.matches('.l')) {
gId(fk).previousElementSibling.innerHTML = lb;
}
} else {
if(t === 'boolean')
{
str += `${lb}: <input class="agi cb" type="checkbox" id=${fk} ${s[i]?"checked":""}><br>`;
} else if (t === 'number')
{
str += `${lb}: <input class="agi" type="number" id=${fk} value=${s[i]}><br>`;
} else if (t === 'string')
{
str += `${lb}:<br><input class="agi" id=${fk} value=${s[i]}><br>`;
}
}
}
}
return str;
}
function genForm(s) {
var str = "";
str = addRec(s,"",l);
gId('gen').innerHTML = str;
}
function GetLS()
{
sett = localStorage.getItem('wledUiCfg');
if (!sett) gId('lserr').style.display = "inline";
try {
sett = JSON.parse(sett);
} catch (e) {
sett = {};
gId('lserr').style.display = "inline";
gId('lserr').innerHTML = "&#9888; Settings JSON parsing failed. (" + e + ")";
}
genForm(sett);
gId('dm').checked = (gId('theme_base').value === 'light');
}
function SetLS()
{
var l = d.querySelectorAll('.agi');
for (var i = 0; i < l.length; i++) {
var e = l[i];
var val = e.classList.contains('cb') ? e.checked : e.value;
set(e.id, sett, val);
console.log(`${e.id} set to ${val}`);
}
try {
localStorage.setItem('wledUiCfg', JSON.stringify(sett));
gId('lssuc').style.display = "inline";
} catch (e) {
gId('lssuc').style.display = "none";
gId('lserr').style.display = "inline";
gId('lserr').innerHTML = "&#9888; Settings JSON saving failed. (" + e + ")";
}
}
function Save() {
SetLS();
if (d.Sf.DS.value != initial_ds || d.Sf.ST.checked != initial_st) d.Sf.submit();
}
function S()
{
GetV();Ct();
GetV();
initial_ds = d.Sf.DS.value;
initial_st = d.Sf.ST.checked;
GetLS();
}
function H()
{
@@ -20,87 +156,48 @@
{
window.open("/settings","_self");
}
function Ct()
function UI()
{
if (gId("co").selected)
{
gId("cth").style.display="block";
} else
{
gId("cth").style.display="none";
}
gId('idonthateyou').style.display = (gId('dm').checked) ? 'inline':'none';
var f = gId('theme_base');
if (f) f.value = (gId('dm').checked) ? 'light':'dark';
}
function GetV()
{
var d = document;
}
</script>
<style>
:root {
--aCol: #666;
--bCol: #333;
--cCol: #222;
--dCol: #666;
--tCol: #fff;
--sCol: #0000;
--cFn: Verdana;
}
body {
font-family: var(--cFn), Helvetica, sans-serif;
text-align: center;
background: var(--cCol);
color: var(--tCol);
line-height: 200%;
margin: 0;
background-attachment: fixed;
}
hr {
border-color: var(--dCol);
filter: drop-shadow( -5px -5px 5px var(--sCol) );
}
button {
background: var(--bCol);
color: var(--tCol);
border: 0.3ch solid var(--bCol);
display: inline-block;
font-family: var(--cFn), Helvetica, sans-serif;
filter: drop-shadow( -5px -5px 5px var(--sCol) );
font-size: 20px;
margin: 8px;
margin-top: 12px;
}
.helpB {
text-align: left;
position: absolute;
width:60px;
}
input {
background: var(--bCol);
color: var(--dCol);
border: 0.5ch solid var(--bCol);
filter: drop-shadow( -5px -5px 5px var(--sCol) );
font-family: var(--cFn), Helvetica, sans-serif;
}
select {
background: var(--bCol);
color: var(-tCol);
border: 0.5ch solid var(--bCol);
filter: drop-shadow( -5px -5px 5px var(--sCol) );
font-family: var(--cFn), Helvetica, sans-serif;
}
input[type=number] {
width: 3em;
}
@import url("style.css");
</style>
</head>
<body onload="S()">
<form id="form_s" name="Sf" method="post">
<div style="position:sticky;top:0;background-color:#222;">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<button type="button" onclick="B()">Back</button><button type="button" onclick="Save()">Save</button><br>
<span id="lssuc" style="color:green; display:none">&#10004; Local UI settings saved!</span>
<span id="lserr" style="color:red; display:none">&#9888; Could not access local storage. Make sure it is enabled in your browser.</span><hr>
</div>
<h2>Web Setup</h2>
Server description: <input name="DS" maxlength="32"><br>
Sync button toggles both send and receive: <input type="checkbox" name="ST"><br><br>
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
Sync button toggles both send and receive: <input type="checkbox" name="ST"><br>
<i>The following UI customization settings are unique both to the WLED device and this browser.<br>
You will need to set them again if using a different browser, device or WLED IP address.<br>
Refresh the main UI to apply changes.</i><br>
<div id="gen">Loading settings...</div>
<h3>UI Appearance</h3>
<span class="l"></span>: <input type="checkbox" id="comp_labels" class="agi cb"><br>
<span class="l"></span>: <input type="checkbox" id="comp_pcmbot" class="agi cb"><br>
I hate dark mode: <input type="checkbox" id="dm" onchange="UI()"><br>
<span id="idonthateyou" style="display:none"><i>Why would you? </i>&#x1F97A;<br></span>
<span class="l"></span>: <input type="number" min=0.0 max=1.0 step=0.01 id="theme_alpha_tab" class="agi"><br>
<span class="l"></span>: <input type="number" min=0.0 max=1.0 step=0.01 id="theme_alpha_bg" class="agi"><br>
<span class="l"></span>: <input id="theme_color_bg" maxlength="9" class="agi"><br>
<span class="l">BG image URL</span>: <input id="theme_bg_url" class="agi">
<input id="theme_base" class="agi" style="display:none">
<hr><button type="button" onclick="B()">Back</button><button type="button" onclick="Save()">Save</button>
</form>
</body>
</html>

View File

@@ -1,6 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=500">
<title>WiFi Settings</title>
<script>
@@ -18,57 +19,13 @@
}
</script>
<style>
:root {
--aCol: #D9B310;
--bCol: #0B3C5D;
--cCol: #1D2731;
--dCol: #328CC1;
--sCol: #000;
--cFn: Verdana;
}
body {
font-family: Verdana, Helvetica, sans-serif;
text-align: center;
background: var(--cCol);
color: var(--dCol);
line-height: 200%;
margin: 0;
background-attachment: fixed;
}
hr {
border-color: var(--dCol);
filter: drop-shadow( -5px -5px 5px var(--sCol) );
}
button {
background: var(--bCol);
color: var(--dCol);
border: 0.3ch solid var(--bCol);
display: inline-block;
filter: drop-shadow( -5px -5px 5px var(--sCol) );
font-size: 20px;
margin: 8px;
margin-top: 12px;
}
.helpB {
text-align: left;
position: absolute;
width:60px;
}
input {
background: var(--bCol);
color: var(--dCol);
border: 0.5ch solid var(--bCol);
filter: drop-shadow( -5px -5px 5px var(--sCol) );
}
input[type=number] {
width: 3em;
}
@import url("style.css");
</style>
</head>
<body onload="GetV()">
<form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button><hr>
<h2>WiFi setup</h2>
<h3>Connect to existing network</h3>
Network name (SSID, empty to not connect): <br><input name="CS" maxlength="32"><br>
@@ -102,8 +59,13 @@
<option value="1">Disconnected</option>
<option value="2">Always</option>
<option value="3">Never (not recommended)</option></select><br>
AP IP: <span class="sip"> Not active </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
AP IP: <span class="sip"> Not active </span><br>
<h3>Experimental</h3>
Disable WiFi sleep: <input type="checkbox" name="WS"><br>
<i>Can help with connectivity issues.<br>
Do not enable if WiFi is working correctly, increases power consumption.</i>
<hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button>
</form>
</body>
</html>

47
wled00/data/style.css Normal file
View File

@@ -0,0 +1,47 @@
body {
font-family: Verdana, sans-serif;
text-align: center;
background: #222;
color: #fff;
line-height: 200%;
margin: 0;
}
hr {
border-color: #666;
}
button {
background: #333;
color: #fff;
font-family: Verdana, sans-serif;
border: 0.3ch solid #333;
display: inline-block;
font-size: 20px;
margin: 8px;
margin-top: 12px;
}
.helpB {
text-align: left;
position: absolute;
width: 60px;
}
input {
background: #333;
color: #fff;
font-family: Verdana, sans-serif;
border: 0.5ch solid #333;
}
input[type="number"] {
width: 4em;
}
select {
background: #333;
color: #fff;
font-family: Verdana, sans-serif;
border: 0.5ch solid #333;
}
td {
padding: 2px;
}
.d5 {
width: 4.5em !important;
}

View File

@@ -1,4 +1,43 @@
<!DOCTYPE html>
<html><head><meta content='width=device-width' name='viewport'><title>WLED Message</title><script>function B(){window.history.back()}</script>
<style>:root{--aCol:#D9B310;--bCol:#0B3C5D;--cCol:#1D2731;--dCol:#328CC1;--sCol:#000;--tCol:#328CC1;--cFn:Verdana;}.bt{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:20px;margin:8px;margin-top:12px}input[type=file]{font-size:16px}body{font-family:var(--cFn),sans-serif;text-align:center;background:var(--cCol);color:var(--tCol);line-height:200%}</style></head>
<body><h2>WLED Software Update</h2>Installed version: 0.8.5-dev<br>Download the latest binary: <a href="https://github.com/Aircoookie/WLED/releases"><img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a><br><form method='POST' action='/update' enctype='multipart/form-data'><input type='file' class="bt" name='update' required><br><input type='submit' class="bt" value='Update!'></form><button type="button" class="bt" onclick="B()">Back</button></body></html>
<html>
<head>
<meta content='width=device-width' name='viewport'>
<title>WLED Update</title>
<script>function B() { window.history.back() }</script>
<style>
.bt {
background: #333;
color: #fff;
font-family: Verdana, sans-serif;
border: .3ch solid #333;
display: inline-block;
font-size: 20px;
margin: 8px;
margin-top: 12px
}
input[type=file] {
font-size: 16px
}
body {
font-family: Verdana, sans-serif;
text-align: center;
background: #222;
color: #fff;
line-height: 200%
}
</style>
</head>
<body>
<h2>WLED Software Update</h2>Installed version: ##VERSION##<br>Download the latest binary: <a
href="https://github.com/Aircoookie/WLED/releases" target="_blank"><img
src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a><br>
<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' class="bt" name='update'
required><br><input type='submit' class="bt" value='Update!'></form><button type="button" class="bt"
onclick="B()">Back</button>
</body>
</html>

6
wled00/data/usermod.htm Normal file
View File

@@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>No usermod custom web page set.</body>
</html>

View File

@@ -3,13 +3,13 @@
<head>
<meta charset="utf-8">
<meta content='width=device-width' name='viewport'>
<meta name="theme-color" content="#333333">
<title>WLED Setup</title>
<meta name="theme-color" content="#222222">
<title>Welcome!</title>
<style>
body {
font-family: Verdana, Helvetica, sans-serif;
text-align: center;
background-color: #333;
background-color: #222;
margin: 0;
color: #fff;
}
@@ -23,32 +23,42 @@
text-transform: uppercase;
font-family: helvetica;
font-size: 19px;
background-color: #222;
background-color: #333;
color: white;
border: 0px solid white;
border-radius: 5px;
border-radius: 25px;
filter: drop-shadow(0px 0px 1px #000);
}
svg {
fill: #fff;
}
img {
width: 999px;
max-width: 85%;
image-rendering: pixelated;
image-rendering: crisp-edges;
margin: 25px 0 -10px 0;
animation: fi 1s;
}
@keyframes fi {
from { opacity: 0; }
to { opacity: 1; }
}
.main {
animation: fi 1.5s .7s both;
}
</style>
</head>
<body>
<svg style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="lnr-smile" viewBox="0 0 1024 1024"><path d="M486.4 1024c-129.922 0-252.067-50.594-343.936-142.464s-142.464-214.014-142.464-343.936c0-129.923 50.595-252.067 142.464-343.936s214.013-142.464 343.936-142.464c129.922 0 252.067 50.595 343.936 142.464s142.464 214.014 142.464 343.936-50.594 252.067-142.464 343.936c-91.869 91.87-214.014 142.464-343.936 142.464zM486.4 102.4c-239.97 0-435.2 195.23-435.2 435.2s195.23 435.2 435.2 435.2 435.2-195.23 435.2-435.2-195.23-435.2-435.2-435.2z"></path><path d="M332.8 409.6c-42.347 0-76.8-34.453-76.8-76.8s34.453-76.8 76.8-76.8 76.8 34.453 76.8 76.8-34.453 76.8-76.8 76.8zM332.8 307.2c-14.115 0-25.6 11.485-25.6 25.6s11.485 25.6 25.6 25.6 25.6-11.485 25.6-25.6-11.485-25.6-25.6-25.6z"></path><path d="M640 409.6c-42.349 0-76.8-34.453-76.8-76.8s34.451-76.8 76.8-76.8 76.8 34.453 76.8 76.8-34.451 76.8-76.8 76.8zM640 307.2c-14.115 0-25.6 11.485-25.6 25.6s11.485 25.6 25.6 25.6 25.6-11.485 25.6-25.6-11.485-25.6-25.6-25.6z"></path><path d="M486.4 870.4c-183.506 0-332.8-149.294-332.8-332.8 0-14.139 11.462-25.6 25.6-25.6s25.6 11.461 25.6 25.6c0 155.275 126.325 281.6 281.6 281.6s281.6-126.325 281.6-281.6c0-14.139 11.461-25.6 25.6-25.6s25.6 11.461 25.6 25.6c0 183.506-149.294 332.8-332.8 332.8z"></path></symbol>
</defs></svg>
<br><br>
<svg><use xlink:href="#lnr-smile"></use></svg>
<img alt="" src=" data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAAjCAYAAACjOOUsAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsAAAA7AAWrWiQkAAATfSURBVGhD7ZlPaBVHHMdnS2Ox5iKYGIyYJwQlUTHG6kUwtSAIBsEiBopgKR5i68mbIPgEwZun0uYgouIlobQIKQheIsSLaBSaRFoEc3gtMa9HLaiH7X4n81tn583u/HkTaZ/7gR+zMzvv93bfZ3/777GSkpL/AJFo3Tg/H7OuPtGxY7CTsZnjkd/3lRTi/qMKgfGXt8TAO6KfT2TG1f7u6ROlyBXgI9HaQRW4+JR3ox92Z1p1XO3PLCUVORHHvFMSDDeJBuJvH4mlZdS+C3c7B+Ln3fvivw59w0MMOzP/FYvj75K4PMhDDDszdbM7rk1V4hcPD/MQw858MbEnPvJgf3x29hQPMdwUbqc2qRIhCBVGrQk+Lzm9mq6NkIe2t20N7xOf7NjK2w13rlltM+Sh7VvLu+/YOMib6NyMVR7IQ9u7qY33ibb2bbxd/9mvVnkgD217ZTXvE72fbuHtle1X3VxIuH1QOZ2mmG5yaH4yr0giBKryVCDTJBICG+SpJDJNIiFQlacCmSaREKjKU4FMX5F+p1NIk8OExTwbgeD1b7+zotOrlUBQm2FFp1cbgeDtyzlWdHq1EQie/fMH8z29Br0myiwdr7PkWpSGC2se/8IqtWnRa+y7Ur+Q3FF97/X7ZFjV/4B1Dz1Pw5WrlZ/Y7T330gjFikkE9Xo9jSJ0Vah+Ru7nVWNRFWq3Iacai6qQ9kfOl1eNuirUfZ7wrcbgEqkCOyc6MmEDVdyrXUd5ENR3rUiqwI6LnTx8oQp8M783E66cWjiWCarMZlnRSix5PwSTSBXY0WFXdf9HfK+FKlSBoX6rjEQ8XMutD3nn+1Yg5L755Mrzk0qkh2xMwLOYr0iXa6CJZu9KQ+N7LSSoAuma6EKRn1TiwaUn0bO3r/gy7v42/3nf+cEzxFGq5jD1TYTYJhAqj4pt3iI/mdMpTbQRqD4HhqhA9S40r28L3ZWmz4kUjlAFNvucSNBzomtF5vlJJVarVb53mMgHLMBRRBEaNWez3xFqW5vN0+znyQ/5Ahlho6OjcVdXl+jxiVmhHn8Gq+jendq+cpPRvUO1fuUmo3mHavvKTUb3DtX2lZtM3jtUWRqQ3TRMBrLMjMgVkAiB2waX/1nwgURygTv885BICOzrH+BjPpBICBzo38nHfJBFksDFxUU2NjaWjhMNAwSJ1Ems/n2RDQ0NsQNzn4sVjF1vvyGWGOvp6cmsk+frJLpWISFXo1cVElI1+lQhIVejTxUSajVCYp5AoB0k6AhIRQqJo7OnGRe87gIfxl9N1Y8nlpcTKpUK+/rlSdFLDghpft5fUTho0GJD5WW0RetUWi1PgwMNmbtTFdhXaRBowdj2H3kuVGQeyIkg5GVQtE6mFfPoPMgUSqSjgo4Gdqk/whfxpGeSaqJIxjFGsbCwkF2fBHJh3ZH5RpE2RxtBedJtkmi1PLSMdXwgh0KJAIkBEiLQV5MODw9ndiBvp/I2VIwZd5T4EPJQLvRNGCVSYgr0xSotIyMjYkkPfV7eUFNOHa2cx+X3BkaJAIkoxJAWCBwfHxc9PdhBbFzSRgixzHfahVbNA2x/b8JKoi0QaKpE7KC8cVjGmOha06p5fAgq0aYSS8ITROLk5GRUq9UyAt/XUVgSGNyl0kNrMyBHchCUeSwJejotKSkp+VBh7F9fIy7OdlOyMwAAAABJRU5ErkJggg==">
<div class="main">
<h1>Welcome to WLED!</h1>
<h3>Thank you for installing my application!</h3>
If you encounter a bug or have a question/feature suggestion, feel free to open a GitHub issue!<br><br>
<b>Next steps:</b><br><br>
Connect the module to your local WiFi here!<br>
<button onclick="window.location.href='/settings/wifi'">WiFi settings</button><br>
<i>Just trying this out in AP mode?</i><br>
<button onclick="window.location.href='/sliders'">To the controls!</button>
<button onclick="window.location.href='/sliders'">To the controls!</button><br>
</div>
</body>
</html>

View File

@@ -8,11 +8,12 @@
*/
#ifdef WLED_ENABLE_DMX
#include "src/dependencies/dmx/ESPDMX.h"
DMXESPSerial dmx;
void handleDMX()
{
// don't act, when in DMX Proxy mode
if (e131ProxyUniverse != 0) return;
// TODO: calculate brightness manually if no shutter channel is set
uint8_t brightness = strip.getBrightness();
@@ -61,6 +62,10 @@ void initDMX() {
dmx.init(512); // initialize with bus length
}
#if (LEDPIN == 2)
#pragma message "Pin conflict compiling with DMX and LEDs on pin 2. Please set a different LEDPIN."
#endif
#else
void handleDMX() {}
void initDMX() {}

View File

@@ -1,35 +1,88 @@
#include "wled.h"
#define MAX_LEDS_PER_UNIVERSE 170
#define MAX_CHANNELS_PER_UNIVERSE 512
/*
* E1.31 handler
*/
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
//E1.31 protocol support
//DDP protocol support, called by handleE131Packet
//handles RGB data only
void handleDDPPacket(e131_packet_t* p) {
int lastPushSeq = e131LastSequenceNumber[0];
//reject late packets belonging to previous frame (assuming 4 packets max. before push)
if (e131SkipOutOfSequence && lastPushSeq) {
int sn = p->sequenceNum & 0xF;
if (sn) {
if (lastPushSeq > 5) {
if (sn > (lastPushSeq -5) && sn < lastPushSeq) return;
} else {
if (sn > (10 + lastPushSeq) || sn < lastPushSeq) return;
}
}
}
uint32_t start = htonl(p->channelOffset) /3;
start += DMXAddress /3;
uint16_t stop = start + htons(p->dataLen) /3;
uint8_t* data = p->data;
uint16_t c = 0;
if (p->flags & DDP_TIMECODE_FLAG) c = 4; //packet has timecode flag, we do not support it, but data starts 4 bytes later
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP);
for (uint16_t i = start; i < stop; i++) {
setRealtimePixel(i, data[c++], data[c++], data[c++], 0);
}
bool push = p->flags & DDP_PUSH_FLAG;
if (push) {
e131NewData = true;
byte sn = p->sequenceNum & 0xF;
if (sn) e131LastSequenceNumber[0] = sn;
}
}
//E1.31 and Art-Net protocol support
void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
uint16_t uni = 0, dmxChannels = 0;
uint8_t* e131_data = nullptr;
uint8_t seq = 0, mde = REALTIME_MODE_E131;
if (isArtnet)
if (protocol == P_ARTNET)
{
uni = p->art_universe;
dmxChannels = htons(p->art_length);
e131_data = p->art_data;
seq = p->art_sequence_number;
mde = REALTIME_MODE_ARTNET;
} else {
} else if (protocol == P_E131) {
uni = htons(p->universe);
dmxChannels = htons(p->property_value_count) -1;
e131_data = p->property_values;
seq = p->sequence_number;
} else { //DDP
realtimeIP = clientIP;
handleDDPPacket(p);
return;
}
#ifdef WLED_ENABLE_DMX
// does not act on out-of-order packets yet
if (e131ProxyUniverse > 0 && uni == e131ProxyUniverse) {
for (uint16_t i = 1; i <= dmxChannels; i++)
dmx.write(i, e131_data[i]);
dmx.update();
}
#endif
// only listen for universes we're handling & allocated memory
if (uni >= (e131Universe + E131_MAX_UNIVERSE_COUNT)) return;
uint8_t previousUniverses = uni - e131Universe;
uint16_t possibleLEDsInCurrentUniverse;
if (e131SkipOutOfSequence)
if (seq < e131LastSequenceNumber[uni-e131Universe] && seq > 20 && e131LastSequenceNumber[uni-e131Universe] < 250){
@@ -47,7 +100,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
// update status info
realtimeIP = clientIP;
byte wChannel = 0;
switch (DMXMode) {
case DMX_MODE_DISABLED:
return; // nothing to do
@@ -98,67 +151,42 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
colSec[2] = e131_data[DMXAddress+10];
if (dmxChannels-DMXAddress+1 > 11)
{
col[3] = e131_data[DMXAddress+11]; //white
colSec[3] = e131_data[DMXAddress+12];
col[3] = e131_data[DMXAddress+11]; //white
colSec[3] = e131_data[DMXAddress+12];
}
transitionDelayTemp = 0; // act fast
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION); // don't send UDP
return; // don't activate realtime live mode
break;
case DMX_MODE_MULTIPLE_RGB:
realtimeLock(realtimeTimeoutMs, mde);
if (realtimeOverride) return;
if (previousUniverses == 0) {
// first universe of this fixture
possibleLEDsInCurrentUniverse = (dmxChannels - DMXAddress + 1) / 3;
for (uint16_t i = 0; i < ledCount; i++) {
if (i >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s)
setRealtimePixel(i, e131_data[DMXAddress+i*3+0], e131_data[DMXAddress+i*3+1], e131_data[DMXAddress+i*3+2], 0);
}
} else if (previousUniverses > 0 && uni < (e131Universe + E131_MAX_UNIVERSE_COUNT)) {
// additional universe(s) of this fixture
uint16_t numberOfLEDsInPreviousUniverses = ((512 - DMXAddress + 1) / 3); // first universe
if (previousUniverses > 1) numberOfLEDsInPreviousUniverses += (512 / 3) * (previousUniverses - 1); // extended universe(s) before current
possibleLEDsInCurrentUniverse = dmxChannels / 3;
for (uint16_t i = numberOfLEDsInPreviousUniverses; i < ledCount; i++) {
uint8_t j = i - numberOfLEDsInPreviousUniverses;
if (j >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s)
setRealtimePixel(i, e131_data[j*3+1], e131_data[j*3+2], e131_data[j*3+3], 0);
}
}
break;
case DMX_MODE_MULTIPLE_DRGB:
realtimeLock(realtimeTimeoutMs, mde);
if (realtimeOverride) return;
if (previousUniverses == 0) {
// first universe of this fixture
if (DMXOldDimmer != e131_data[DMXAddress+0]) {
DMXOldDimmer = e131_data[DMXAddress+0];
bri = e131_data[DMXAddress+0];
strip.setBrightness(bri);
case DMX_MODE_MULTIPLE_RGB:
{
realtimeLock(realtimeTimeoutMs, mde);
if (realtimeOverride) return;
uint16_t previousLeds, dmxOffset;
if (previousUniverses == 0) {
if (dmxChannels-DMXAddress < 1) return;
dmxOffset = DMXAddress;
previousLeds = 0;
// First DMX address is dimmer in DMX_MODE_MULTIPLE_DRGB mode.
if (DMXMode == DMX_MODE_MULTIPLE_DRGB) {
strip.setBrightness(e131_data[dmxOffset++]);
}
} else {
// All subsequent universes start at the first channel.
dmxOffset = (protocol == P_ARTNET) ? 0 : 1;
uint16_t ledsInFirstUniverse = (MAX_CHANNELS_PER_UNIVERSE - DMXAddress) / 3;
previousLeds = ledsInFirstUniverse + (previousUniverses - 1) * MAX_LEDS_PER_UNIVERSE;
}
possibleLEDsInCurrentUniverse = (dmxChannels - DMXAddress) / 3;
for (uint16_t i = 0; i < ledCount; i++) {
if (i >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s)
setRealtimePixel(i, e131_data[DMXAddress+i*3+1], e131_data[DMXAddress+i*3+2], e131_data[DMXAddress+i*3+3], 0);
}
} else if (previousUniverses > 0 && uni < (e131Universe + E131_MAX_UNIVERSE_COUNT)) {
// additional universe(s) of this fixture
uint16_t numberOfLEDsInPreviousUniverses = ((512 - DMXAddress + 1) / 3); // first universe
if (previousUniverses > 1) numberOfLEDsInPreviousUniverses += (512 / 3) * (previousUniverses - 1); // extended universe(s) before current
possibleLEDsInCurrentUniverse = dmxChannels / 3;
for (uint16_t i = numberOfLEDsInPreviousUniverses; i < ledCount; i++) {
uint8_t j = i - numberOfLEDsInPreviousUniverses;
if (j >= possibleLEDsInCurrentUniverse) break; // more LEDs will follow in next universe(s)
setRealtimePixel(i, e131_data[j*3+1], e131_data[j*3+2], e131_data[j*3+3], 0);
uint16_t ledsTotal = previousLeds + (dmxChannels - dmxOffset +1) / 3;
for (uint16_t i = previousLeds; i < ledsTotal; i++) {
setRealtimePixel(i, e131_data[dmxOffset++], e131_data[dmxOffset++], e131_data[dmxOffset++], 0);
}
break;
}
break;
default:
DEBUG_PRINTLN("unknown E1.31 DMX mode");
DEBUG_PRINTLN(F("unknown E1.31 DMX mode"));
return; // nothing to do
break;
}

Some files were not shown because too many files have changed in this diff Show More