Merge pull request #1139 from Aircoookie/master-to-fs
Merge master to filesystem branch
27
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal 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!
|
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an improvement idea for WLED!
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
||||
Thank you for your ideas for making WLED better!
|
19
.github/ISSUE_TEMPLATE/question.md
vendored
Normal 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.
|
1
.gitignore
vendored
@ -9,3 +9,4 @@
|
||||
.DS_Store
|
||||
.gitignore
|
||||
.clang-format
|
||||
node_modules
|
||||
|
@ -40,4 +40,4 @@ install:
|
||||
- platformio update
|
||||
script:
|
||||
# - platformio ci --project-conf=./platformio.ini
|
||||
- platformio run
|
||||
- platformio run
|
123
CHANGELOG.md
@ -1,5 +1,128 @@
|
||||
## WLED changelog
|
||||
|
||||
### Development versions after the 0.10.2 release
|
||||
|
||||
#### 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
@ -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
|
BIN
images/macbook-pro-space-gray-on-the-wooden-table.jpg
Normal file
After Width: | Height: | Size: 490 KiB |
BIN
images/walking-with-iphone-x.jpg
Normal file
After Width: | Height: | Size: 500 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
BIN
images/wled_logo_akemi.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
images/wled_logo_clean.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
2233
package-lock.json
generated
Normal file
31
package.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.10.2",
|
||||
"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": "^4.0.0",
|
||||
"inliner": "^1.13.1",
|
||||
"nodemon": "^2.0.4",
|
||||
"zlib": "^1.0.5"
|
||||
}
|
||||
}
|
@ -15,11 +15,11 @@ extra_configs =
|
||||
# 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
|
||||
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
|
||||
|
||||
# Single binaries (uncomment your board)
|
||||
; default_envs = nodemcuv2
|
||||
@ -27,7 +27,7 @@ extra_configs =
|
||||
; default_envs = esp01_1m_ota
|
||||
; default_envs = esp01_1m_full
|
||||
; default_envs = esp07
|
||||
default_envs = d1_mini
|
||||
; default_envs = d1_mini
|
||||
; default_envs = heltec_wifi_kit_8
|
||||
; default_envs = h803wf
|
||||
; default_envs = d1_mini_debug
|
||||
@ -38,6 +38,7 @@ default_envs = d1_mini
|
||||
; default_envs = esp8285_5CH_H801
|
||||
; default_envs = d1_mini_5CH_Shojo_PCB
|
||||
; default_envs = wemos_shield_esp32
|
||||
; default_envs = m5atom
|
||||
|
||||
[common]
|
||||
# ------------------------------------------------------------------------------
|
||||
@ -66,14 +67,19 @@ 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_0 = espressif8266@2.5.0
|
||||
arduino_core_2_7_1 = espressif8266@2.5.1
|
||||
arduino_core_2_7_2 = espressif8266@2.6.0
|
||||
arduino_core_2_7_3 = espressif8266@2.6.1
|
||||
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 to use for ESP8266
|
||||
platform_latest = ${common.arduino_core_2_6_3}
|
||||
platform_wled_default = ${common.arduino_core_2_7_4}
|
||||
# We use 2.7.0+ on analog boards because of PWM flicker fix
|
||||
platform_latest = ${common.arduino_core_2_7_4}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# FLAGS: DEBUG
|
||||
@ -120,6 +126,16 @@ build_flags = -g -w -DMQTT_MAX_PACKET_SIZE=1024 -DPIO_FRAMEWORK_ARDUINO_LWIP_HIG
|
||||
build_flags_esp8266 = ${common.build_flags} -DESP8266
|
||||
build_flags_esp32 = ${common.build_flags} -DARDUINO_ARCH_ESP32
|
||||
|
||||
# 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
|
||||
|
||||
ldscript_512k = eagle.flash.512k.ld ;for older versions change this to eagle.flash.512k0.ld
|
||||
ldscript_1m0m = eagle.flash.1m.ld ;for older versions change this to eagle.flash.1m0.ld
|
||||
ldscript_2m1m = eagle.flash.2m1m.ld
|
||||
@ -151,10 +167,12 @@ lib_deps =
|
||||
FastLED@3.3.2
|
||||
NeoPixelBus@2.5.7
|
||||
ESPAsyncTCP@1.2.0
|
||||
ESPAsyncUDP@697c75a025
|
||||
ESPAsyncUDP
|
||||
AsyncTCP@1.0.3
|
||||
Esp Async WebServer@1.2.0
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer
|
||||
IRremoteESP8266@2.7.3
|
||||
#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
|
||||
@ -170,56 +188,60 @@ lib_ignore =
|
||||
|
||||
[env:nodemcuv2]
|
||||
board = nodemcuv2
|
||||
platform = ${common.platform_latest}
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
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}
|
||||
board_build.ldscript = ${common.ldscript_512k}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -D WLED_DISABLE_ALEXA -D WLED_DISABLE_BLYNK
|
||||
-D WLED_DISABLE_CRONIXIE -D WLED_DISABLE_HUESYNC -D WLED_DISABLE_INFRARED
|
||||
-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}
|
||||
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_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}
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_1m0m}
|
||||
build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA
|
||||
|
||||
[env:esp07]
|
||||
board = esp07
|
||||
platform = ${common.platform_latest}
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
[env:d1_mini]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
platform = ${common.platform_wled_default}
|
||||
upload_speed = 921600
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
[env:heltec_wifi_kit_8]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
[env:h803wf]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=1 -D WLED_DISABLE_INFRARED
|
||||
|
||||
[env:esp32dev]
|
||||
board = esp32dev
|
||||
platform = espressif32@1.11.2
|
||||
platform = espressif32@1.12.4
|
||||
build_flags = ${common.build_flags_esp32}
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
@ -256,7 +278,7 @@ build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D WLED_USE_
|
||||
[env:d1_mini_debug]
|
||||
board = d1_mini
|
||||
build_type = debug
|
||||
platform = ${common.platform_latest}
|
||||
platform = ${common.platform_wled_default}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} ${common.debug_flags}
|
||||
|
||||
@ -265,7 +287,7 @@ 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}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266}
|
||||
|
||||
@ -285,6 +307,13 @@ platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=16
|
||||
|
||||
|
||||
[env:custom_LEDPIN_3]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
board_build.ldscript = ${common.ldscript_4m1m}
|
||||
build_flags = ${common.build_flags_esp8266} -D LEDPIN=3
|
||||
|
||||
[env:custom_APA102]
|
||||
board = d1_mini
|
||||
platform = ${common.platform_latest}
|
||||
@ -299,7 +328,7 @@ build_flags = ${common.build_flags_esp8266} -D USE_WS2801
|
||||
|
||||
[env:custom32_LEDPIN_16]
|
||||
board = esp32dev
|
||||
platform = espressif32@1.11.2
|
||||
platform = espressif32@1.12.4
|
||||
build_flags = ${common.build_flags_esp32} -D LEDPIN=16
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
@ -307,7 +336,7 @@ lib_ignore =
|
||||
|
||||
[env:wemos_shield_esp32]
|
||||
board = esp32dev
|
||||
platform = espressif32@1.11.2
|
||||
platform = espressif32@1.12.4
|
||||
upload_port = /dev/cu.SLAB_USBtoUART
|
||||
monitor_port = /dev/cu.SLAB_USBtoUART
|
||||
upload_speed = 460800
|
||||
@ -315,3 +344,25 @@ build_flags = ${common.build_flags_esp32} -D LEDPIN=16 -D RLYPIN=19 -D BTNPIN=17
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
|
||||
[env:m5atom]
|
||||
board = esp32dev
|
||||
build_flags = ${common.build_flags_esp32} -D LEDPIN=27 -D BTNPIN=39
|
||||
lib_ignore =
|
||||
ESPAsyncTCP
|
||||
ESPAsyncUDP
|
||||
platform = espressif32@1.12.4
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# travis test board configurations
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
[env:travis_esp8266]
|
||||
extends = env:d1_mini
|
||||
build_type = debug
|
||||
build_flags = ${common.build_flags_esp8266} ${common.debug_flags} ${common.build_flags_all_features}
|
||||
|
||||
[env:travis_esp32]
|
||||
extends = env:esp32dev
|
||||
build_type = debug
|
||||
build_flags = ${common.build_flags_esp32} ${common.debug_flags} ${common.build_flags_all_features}
|
||||
|
@ -4,6 +4,9 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Please visit documentation: https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
default_envs = esp8266_1m_custom
|
||||
|
||||
[env:esp8266_1m_custom]
|
||||
board = esp01_1m
|
||||
platform = ${common.arduino_core_2_4_2}
|
||||
@ -25,6 +28,9 @@ build_flags = ${common.build_flags_esp8266}
|
||||
; -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
|
||||
|
68
readme.md
@ -1,16 +1,17 @@
|
||||

|
||||
<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://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>
|
||||
</p>
|
||||
|
||||
# Welcome to my project WLED! ✨
|
||||
|
||||
[](https://github.com/Aircoookie/WLED/releases)
|
||||
[](https://wled.discourse.group)
|
||||
[](https://discord.gg/KuqP7NE)
|
||||
[](https://github.com/Aircoookie/WLED/wiki)
|
||||
[](https://github.com/Aircoookie/WLED-App)
|
||||
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812, APA102) LEDs or also SPI based chipsets like the WS2801!
|
||||
|
||||
## Welcome to my project WLED!
|
||||
|
||||
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
|
||||
@ -25,22 +26,22 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
|
||||
- Configurable analog clock + support for the Cronixie kit by Diamex
|
||||
- Configurable Auto Brightness limit for safer operation
|
||||
|
||||
### 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 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)!
|
||||
|
||||
@ -54,18 +55,47 @@ Russian speakers, check out the videos by Room31:
|
||||
[WLED Firmware Overview: Interface and Settings](https://youtu.be/h7lKsczEI7E)
|
||||
[ESP8266 based LED controller for WS2812b strip. WLED Firmware + OpenHAB](https://youtu.be/K4ioTt3XvGc)
|
||||
|
||||
### Other
|
||||
## 🖼️ 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%">
|
||||
|
||||
## 💾 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 |
|
||||
|
||||
## 🧊 Compatibe 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://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.
|
||||
|
396
tools/cdata.js
Normal file
@ -0,0 +1,396 @@
|
||||
/**
|
||||
* 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").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: "favicon.ico",
|
||||
name: "favicon",
|
||||
method: "binary",
|
||||
},
|
||||
],
|
||||
"wled00/html_other.h"
|
||||
);
|
10
usermods/EXAMPLE_v2/readme.md
Normal 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)_
|
||||
|
119
usermods/EXAMPLE_v2/usermod_v2_example.h
Normal file
@ -0,0 +1,119 @@
|
||||
#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!"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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!
|
||||
};
|
54
usermods/Fix_unreachable_netservices_v2/readme.md
Normal 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
|
@ -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":{"⚡ Ping fix pings": m_pingCount} to the info object
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray infoArr = user.createNestedArray("⚡ Ping fix pings"); //name
|
||||
infoArr.add(m_pingCount); //value
|
||||
|
||||
//this code adds "u":{"⚡ Reconnects": m_connectedWiFi - 1} to the info object
|
||||
infoArr = user.createNestedArray("⚡ 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!
|
||||
};
|
17
usermods/Fix_unreachable_webserver/readme.md
Normal 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.
|
||||
|
||||
|
43
usermods/Fix_unreachable_webserver/usermod.cpp
Normal 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();
|
||||
}
|
||||
}
|
9
usermods/PIR_sensor_mqtt_v1/README.md
Normal 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.
|
55
usermods/PIR_sensor_mqtt_v1/usermod.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
75
usermods/PIR_sensor_switch/readme.md
Normal file
@ -0,0 +1,75 @@
|
||||
# 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());
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Have fun - @gegu
|
249
usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h
Normal file
@ -0,0 +1,249 @@
|
||||
#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) {
|
||||
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":{"⏲ 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("⏲ 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":{"⏲ switch off timer":uiDomString} to the info object
|
||||
infoArr = user.createNestedArray("⏲ 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!
|
||||
};
|
77
usermods/TTGO-T-Display/README.md
Normal 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
|
||||

|
||||
|
||||
## 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
|
BIN
usermods/TTGO-T-Display/assets/ttgo_hardware1.png
Normal file
After Width: | Height: | Size: 686 KiB |
8
usermods/TTGO-T-Display/platformio_override.ini
Normal 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 IR_PIN=4
|
||||
; -D RLYPIN=12
|
||||
; -D RLYMDE=1
|
214
usermods/TTGO-T-Display/usermod.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
40
usermods/Temperature/readme.md
Normal file
@ -0,0 +1,40 @@
|
||||
# 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.
|
||||
|
||||
## Installation
|
||||
|
||||
Copy `usermod_temperature.h` to the wled00 directory.
|
||||
Uncomment the corresponding lines in `usermods_list.cpp` and compile!
|
||||
If this is the only v2 usermod you plan to use, you can alternatively replace `usermods_list.h` in wled00 with the one in this folder.
|
||||
|
||||
## Project link
|
||||
|
||||
* [QuinLED-Dig-Uno](https://quinled.info/2018/09/15/quinled-dig-uno/) - Project link
|
||||
|
||||
### PlatformIO requirements
|
||||
|
||||
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
|
||||
...
|
||||
```
|
79
usermods/Temperature/usermod_temperature.h
Normal file
@ -0,0 +1,79 @@
|
||||
#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
|
||||
|
||||
#define TEMP_CELSIUS // Comment out for Fahrenheit
|
||||
|
||||
#define MEASUREMENT_INTERVAL 60000 //1 Minute
|
||||
|
||||
OneWire oneWire(TEMPERATURE_PIN);
|
||||
DallasTemperature sensor(&oneWire);
|
||||
|
||||
class UsermodTemperature : public Usermod {
|
||||
private:
|
||||
//set last reading as "40 sec before boot", so first reading is taken after 20 sec
|
||||
unsigned long lastMeasurement = UINT32_MAX - 40000;
|
||||
float temperature = 0.0f;
|
||||
public:
|
||||
void getReading() {
|
||||
sensor.requestTemperatures();
|
||||
#ifdef TEMP_CELSIUS
|
||||
temperature = sensor.getTempCByIndex(0);
|
||||
#else
|
||||
temperature = sensor.getTempFByIndex(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void setup() {
|
||||
sensor.begin();
|
||||
sensor.setResolution(9);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (millis() - lastMeasurement > MEASUREMENT_INTERVAL)
|
||||
{
|
||||
getReading();
|
||||
|
||||
if (WLED_MQTT_CONNECTED) {
|
||||
char subuf[38];
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat(subuf, "/temperature");
|
||||
mqtt->publish(subuf, 0, true, String(temperature).c_str());
|
||||
}
|
||||
lastMeasurement = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void addToJsonInfo(JsonObject& root) {
|
||||
JsonObject user = root["u"];
|
||||
if (user.isNull()) user = root.createNestedObject("u");
|
||||
|
||||
JsonArray temp = user.createNestedArray("Temperature");
|
||||
if (temperature == DEVICE_DISCONNECTED_C) {
|
||||
temp.add(0);
|
||||
temp.add(" Sensor Error!");
|
||||
return;
|
||||
}
|
||||
|
||||
temp.add(temperature);
|
||||
#ifdef TEMP_CELSIUS
|
||||
temp.add("°C");
|
||||
#else
|
||||
temp.add("°F");
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t getId()
|
||||
{
|
||||
return USERMOD_ID_TEMPERATURE;
|
||||
}
|
||||
};
|
25
usermods/Temperature/usermods_list.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "wled.h"
|
||||
/*
|
||||
* Register your v2 usermods here!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Add/uncomment your usermod filename here (and once more below)
|
||||
* || || ||
|
||||
* \/ \/ \/
|
||||
*/
|
||||
//#include "usermod_v2_example.h"
|
||||
#include "usermod_temperature.h"
|
||||
//#include "usermod_v2_empty.h"
|
||||
|
||||
void registerUsermods()
|
||||
{
|
||||
/*
|
||||
* Add your usermod class name here
|
||||
* || || ||
|
||||
* \/ \/ \/
|
||||
*/
|
||||
//usermods.add(new MyExampleUsermod());
|
||||
usermods.add(new UsermodTemperature());
|
||||
//usermods.add(new UsermodRenameMe());
|
||||
}
|
15
usermods/UserModv2_SunRiseAndSet/README.md
Normal 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.
|
166
usermods/UserModv2_SunRiseAndSet/UserMod_SunRiseAndSet.h
Normal 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, you’ll 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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
94
usermods/mpu6050_imu/readme.md
Normal 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());
|
||||
}
|
||||
```
|
274
usermods/mpu6050_imu/usermod_mpu6050_imu.h
Normal 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;
|
||||
}
|
||||
|
||||
};
|
11
usermods/photoresistor_sensor_mqtt_v1/README.md
Normal 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.
|
70
usermods/photoresistor_sensor_mqtt_v1/usermod.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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 :)
|
||||
|
211
usermods/rotary_encoder_change_brightness/usermode_rotary_set.h
Normal 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!
|
||||
};
|
BIN
usermods/word-clock-matrix/Word Clock Baffle.stl
Normal file
6
usermods/word-clock-matrix/readme.md
Normal 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.
|
846
usermods/word-clock-matrix/word clock stencil.svg
Normal 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 |
305
usermods/word-clock-matrix/word-clock-matrix.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
402
wled00/FX.cpp
@ -869,6 +869,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;
|
||||
}
|
||||
@ -2246,7 +2247,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 +2312,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();
|
||||
@ -3238,6 +3240,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 +3262,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 +3311,7 @@ uint16_t WS2812FX::mode_pacifica()
|
||||
setPixelColor(i, c.red, c.green, c.blue);
|
||||
}
|
||||
|
||||
now = nowOld;
|
||||
return FRAMETIME;
|
||||
}
|
||||
|
||||
@ -3322,3 +3330,385 @@ 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
70
wled00/FX.h
@ -31,6 +31,7 @@
|
||||
#include "const.h"
|
||||
|
||||
#define FASTLED_INTERNAL //remove annoying pragma messages
|
||||
#define USE_GET_MILLISECOND_TIMER
|
||||
#include "FastLED.h"
|
||||
|
||||
#define DEFAULT_BRIGHTNESS (uint8_t)127
|
||||
@ -84,21 +85,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 113
|
||||
|
||||
#define FX_MODE_STATIC 0
|
||||
#define FX_MODE_BLINK 1
|
||||
@ -203,6 +207,16 @@
|
||||
#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
|
||||
|
||||
class WS2812FX {
|
||||
typedef uint16_t (WS2812FX::*mode_ptr)(void);
|
||||
@ -219,7 +233,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 +269,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 +411,16 @@ 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;
|
||||
|
||||
_brightness = DEFAULT_BRIGHTNESS;
|
||||
currentPalette = CRGBPalette16(CRGB::Black);
|
||||
@ -409,6 +436,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),
|
||||
@ -423,10 +451,11 @@ class WS2812FX {
|
||||
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),
|
||||
setPixelSegment(uint8_t n);
|
||||
|
||||
bool
|
||||
reverseMode = false,
|
||||
reverseMode = false, //is the entire LED strip reversed?
|
||||
gammaCorrectBri = false,
|
||||
gammaCorrectCol = true,
|
||||
applyToAllSelected = true,
|
||||
@ -457,9 +486,10 @@ class WS2812FX {
|
||||
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 +592,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 +610,17 @@ 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);
|
||||
|
||||
private:
|
||||
NeoPixelWrapper *bus;
|
||||
@ -591,7 +630,6 @@ class WS2812FX {
|
||||
CRGBPalette16 currentPalette;
|
||||
CRGBPalette16 targetPalette;
|
||||
|
||||
uint32_t now;
|
||||
uint16_t _length, _lengthRaw, _virtualSegmentLength;
|
||||
uint16_t _rand16seed;
|
||||
uint8_t _brightness;
|
||||
@ -599,7 +637,6 @@ class WS2812FX {
|
||||
|
||||
void load_gradient_palette(uint8_t);
|
||||
void handle_palette(void);
|
||||
void fill(uint32_t);
|
||||
|
||||
bool
|
||||
_useRgbw = false,
|
||||
@ -628,10 +665,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 +694,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 +706,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"
|
||||
])=====";
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
@ -135,6 +150,7 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
}
|
||||
}
|
||||
|
||||
//reorder channels to selected order
|
||||
RgbwColor col;
|
||||
switch (colorOrder)
|
||||
{
|
||||
@ -170,14 +186,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
|
||||
@ -366,6 +391,12 @@ 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 (SEGENV.next_time > millis() + 22 && millis() - _lastShow > MIN_SHOW_DELAY) show();//apply brightness change immediately if no refresh soon
|
||||
}
|
||||
|
||||
@ -400,7 +431,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) {
|
||||
@ -510,6 +546,18 @@ void WS2812FX::resetSegments() {
|
||||
_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 +576,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 +620,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
|
||||
*/
|
||||
@ -706,26 +765,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,7 +838,7 @@ 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
|
||||
@ -789,6 +850,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 +871,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;
|
||||
|
@ -40,8 +40,12 @@
|
||||
//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
|
||||
@ -71,6 +75,14 @@
|
||||
#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 IR_PIN
|
||||
#else
|
||||
//PWM pins - PINs 5,12,13,15 are used with Magic Home LED Controller
|
||||
#define RPIN 5 //R pin for analog LED strip
|
||||
@ -126,7 +138,9 @@
|
||||
#define PIXELFEATURE4 DotStarLbgrFeature
|
||||
#elif defined(USE_LPD8806)
|
||||
#define PIXELFEATURE3 Lpd8806GrbFeature
|
||||
#define PIXELFEATURE4 Lpd8806GrbFeature
|
||||
#elif defined(USE_WS2801)
|
||||
#define PIXELFEATURE3 NeoRbgFeature
|
||||
#define PIXELFEATURE4 NeoRbgFeature
|
||||
#elif defined(USE_TM1814)
|
||||
#define PIXELFEATURE3 NeoWrgbTm1814Feature
|
||||
#define PIXELFEATURE4 NeoWrgbTm1814Feature
|
||||
@ -276,7 +290,7 @@ public:
|
||||
}
|
||||
break;
|
||||
case NeoPixelType_Grbw: {
|
||||
#ifdef USE_LPD8806
|
||||
#if defined(USE_LPD8806) || defined(USE_WS2801)
|
||||
_pGrbw->SetPixelColor(indexPixel, RgbColor(color.R,color.G,color.B));
|
||||
#else
|
||||
_pGrbw->SetPixelColor(indexPixel, color);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,7 @@
|
||||
#define REALTIME_MODE_E131 4
|
||||
#define REALTIME_MODE_ADALIGHT 5
|
||||
#define REALTIME_MODE_ARTNET 6
|
||||
#define REALTIME_MODE_TPM2NET 7
|
||||
|
||||
//realtime override modes
|
||||
#define REALTIME_OVERRIDE_NONE 0
|
||||
@ -86,8 +99,17 @@
|
||||
#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
|
||||
|
||||
//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.
|
||||
|
||||
//EEPROM size
|
||||
#define EEPSIZE 2560 //Maximum is 4096
|
||||
|
||||
|
28
wled00/data/dmxmap.htm
Normal 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>
|
@ -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>
|
@ -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;
|
||||
}
|
||||
|
59
wled00/data/settings_dmx.htm
Normal 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>
|
@ -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,7 +45,7 @@
|
||||
<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>
|
||||
|
@ -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 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,6 +26,7 @@ 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>
|
||||
@ -39,7 +41,7 @@ Send notifications twice: <input type="checkbox" name="S2">
|
||||
<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>
|
||||
@ -58,7 +60,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 +100,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>
|
||||
|
@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=500">
|
||||
<meta charset="utf-8">
|
||||
<title>Time Settings</title>
|
||||
<script>
|
||||
var d=document;
|
||||
@ -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()">
|
||||
@ -207,7 +151,8 @@
|
||||
<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>
|
||||
Button short press macro: Macro: <input name="MP" type="number" min="0" max="16" required><br>
|
||||
Long Press: <input name="ML" type="number" min="0" max="16" required> Double press: <input name="MD" type="number" min="0" max="16" required><br>
|
||||
Countdown-Over Macro: <input name="MC" type="number" min="0" max="16" required><br>
|
||||
Timed-Light-Over Macro: <input name="MN" type="number" min="0" max="16" required><br>
|
||||
Time-Controlled Macros:<br>
|
||||
|
@ -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 = "⚠ 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 = "⚠ 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">✔ Local UI settings saved!</span>
|
||||
<span id="lserr" style="color:red; display:none">⚠ 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>🥺<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>
|
@ -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
@ -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;
|
||||
}
|
@ -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"><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
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<body>No usermod custom web page set.</body>
|
||||
|
||||
</html>
|
@ -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() {}
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include "wled.h"
|
||||
|
||||
#define MAX_LEDS_PER_UNIVERSE 170
|
||||
#define MAX_CHANNELS_PER_UNIVERSE 512
|
||||
|
||||
/*
|
||||
* E1.31 handler
|
||||
*/
|
||||
@ -25,11 +28,19 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, bool isArtnet){
|
||||
seq = p->sequence_number;
|
||||
}
|
||||
|
||||
#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 +58,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,65 +109,40 @@ 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 = isArtnet ? 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) / 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");
|
||||
return; // nothing to do
|
||||
|
@ -62,8 +62,10 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len);
|
||||
|
||||
//ir.cpp
|
||||
bool decodeIRCustom(uint32_t code);
|
||||
void applyRepeatActions();
|
||||
void relativeChange(byte* property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF);
|
||||
void changeEffectSpeed(int8_t amount);
|
||||
void changeBrightness(int8_t amount);
|
||||
void changeEffectIntensity(int8_t amount);
|
||||
void decodeIR(uint32_t code);
|
||||
void decodeIR24(uint32_t code);
|
||||
@ -73,6 +75,7 @@ void decodeIR40(uint32_t code);
|
||||
void decodeIR44(uint32_t code);
|
||||
void decodeIR21(uint32_t code);
|
||||
void decodeIR6(uint32_t code);
|
||||
void decodeIR9(uint32_t code);
|
||||
|
||||
void initIR();
|
||||
void handleIR();
|
||||
@ -82,7 +85,6 @@ void handleIR();
|
||||
#include "src/dependencies/json/ArduinoJson-v6.h"
|
||||
#include "src/dependencies/json/AsyncJson-v6.h"
|
||||
#include "FX.h"
|
||||
// TODO: AsynicWebServerRequest conflict?
|
||||
|
||||
void deserializeSegment(JsonObject elem, byte it);
|
||||
bool deserializeState(JsonObject root);
|
||||
@ -90,7 +92,7 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id);
|
||||
void serializeState(JsonObject root);
|
||||
void serializeInfo(JsonObject root);
|
||||
void serveJson(AsyncWebServerRequest* request);
|
||||
void serveLiveLeds(AsyncWebServerRequest* request);
|
||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
||||
|
||||
//led.cpp
|
||||
void setValuesFromMainSeg();
|
||||
@ -145,6 +147,40 @@ void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
||||
void handleNotifications();
|
||||
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w);
|
||||
|
||||
//um_manager.cpp
|
||||
class Usermod {
|
||||
public:
|
||||
virtual void loop() {}
|
||||
virtual void setup() {}
|
||||
virtual void connected() {}
|
||||
virtual void addToJsonState(JsonObject& obj) {}
|
||||
virtual void addToJsonInfo(JsonObject& obj) {}
|
||||
virtual void readFromJsonState(JsonObject& obj) {}
|
||||
virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;}
|
||||
};
|
||||
|
||||
class UsermodManager {
|
||||
private:
|
||||
Usermod* ums[WLED_MAX_USERMODS];
|
||||
byte numMods = 0;
|
||||
|
||||
public:
|
||||
void loop();
|
||||
|
||||
void setup();
|
||||
void connected();
|
||||
|
||||
void addToJsonState(JsonObject& obj);
|
||||
void addToJsonInfo(JsonObject& obj);
|
||||
void readFromJsonState(JsonObject& obj);
|
||||
|
||||
bool add(Usermod* um);
|
||||
byte getModCount();
|
||||
};
|
||||
|
||||
//usermods_list.cpp
|
||||
void registerUsermods();
|
||||
|
||||
//usermod.cpp
|
||||
void userSetup();
|
||||
void userConnected();
|
||||
@ -179,9 +215,14 @@ String settingsProcessor(const String& var);
|
||||
String dmxProcessor(const String& var);
|
||||
void serveSettings(AsyncWebServerRequest* request);
|
||||
|
||||
//ws.cpp
|
||||
void handleWs();
|
||||
void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len);
|
||||
void sendDataWs(AsyncWebSocketClient * client = nullptr);
|
||||
|
||||
//xml.cpp
|
||||
char* XML_response(AsyncWebServerRequest *request, char* dest = nullptr);
|
||||
char* URL_response(AsyncWebServerRequest *request);
|
||||
void XML_response(AsyncWebServerRequest *request, char* dest = nullptr);
|
||||
void URL_response(AsyncWebServerRequest *request);
|
||||
void sappend(char stype, const char* key, int val);
|
||||
void sappends(char stype, const char* key, char* val);
|
||||
void getSettingsJS(byte subPage, char* dest);
|
||||
|
@ -1,133 +1,138 @@
|
||||
/*
|
||||
* Various web pages
|
||||
*/
|
||||
* 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!
|
||||
*/
|
||||
|
||||
//USER HTML HERE (/u subpage)
|
||||
const char PAGE_usermod[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><body>No usermod custom web page set.</body></html>)=====";
|
||||
// Autogenerated from wled00/data/usermod.htm, do not edit!!
|
||||
const char PAGE_usermod[] PROGMEM = R"=====(<!DOCTYPE html><html><body>No usermod custom web page set.</body></html>)=====";
|
||||
|
||||
|
||||
//server message
|
||||
const char PAGE_msg[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<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>
|
||||
<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}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}</style></head>
|
||||
<body><h2>%MSG%</body></html>)=====";
|
||||
|
||||
//DMX channel map
|
||||
const char PAGE_dmxmap[] PROGMEM = R"=====(<!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() {%DMXVARS%
|
||||
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>)=====";
|
||||
// Autogenerated from wled00/data/msg.htm, do not edit!!
|
||||
const char PAGE_msg[] PROGMEM = R"=====(<!DOCTYPE html><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><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}body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}
|
||||
</style></head><body><h2>%MSG%</body></html>)=====";
|
||||
|
||||
|
||||
//firmware update page
|
||||
const char PAGE_update[] PROGMEM = R"=====(<!DOCTYPE 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: 0.10.0<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>)=====";
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
|
||||
// Autogenerated from wled00/data/dmxmap.htm, do not edit!!
|
||||
const char PAGE_dmxmap[] PROGMEM = R"=====(<!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() {%DMXVARS%
|
||||
var t=["SET 0","RED","GREEN","BLUE","WHITE","SHUTTER","SET 255","DISABLED"],n=[];for(i=0;i<512;i++)n.push(7);for(i=0;i<LC;i++)for(FS=CS+CG*i,j=0;j<CN;j++)DA=FS+j,n[DA-1]=CH[j];for(DMXMap="",i=0;i<512;i++)isstart="",(i+1)%10==0&&(isstart="S"),DMXMap+='<div class="anytype '+isstart+" type"+n[i]+'">'+String(i+1)+"<br />"+t[n[i]]+"</div>";document.getElementById("map").innerHTML=DMXMap}
|
||||
</script><style>
|
||||
.anytype{border:1px solid #fff;margin:1px;float:left;width:100px;height:100px}.S{margin:0;border:2px solid #fff}.type7{color:#888;border:1px dotted grey}.type6{color:#fff}.type4{color:#fff;font-weight:700}.type3{color:#00f;font-weight:700}.type2{color:#0f0;font-weight:700}.type1{color:red;font-weight:700}.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>)=====";
|
||||
|
||||
|
||||
//new user welcome page
|
||||
const char PAGE_welcome[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta charset=utf-8><meta content='width=device-width' name=viewport><meta name=theme-color content=#333333><title>WLED Setup</title> <style>body{font-family:Verdana,Helvetica,sans-serif;text-align:center;background-color:#333;margin:0;color:#fff}button{outline:0;cursor:pointer}.btn{padding:8px;margin:10px;width:230px;text-transform:uppercase;font-family:helvetica;font-size:19px;background-color:#222;color:white;border:0 solid white;border-radius:5px}svg{fill:#fff}</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><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 class=btn onclick="window.location.href='/settings/wifi'">WiFi settings</button><br> <i>Just trying this out in AP mode?</i><br> <button class=btn onclick="window.location.href='/sliders'">To the controls!</button></body></html>)=====";
|
||||
#else
|
||||
const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
|
||||
#endif
|
||||
|
||||
|
||||
//liveview
|
||||
const char PAGE_liveview[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta name=viewport content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||
<meta charset=utf-8>
|
||||
<meta name=theme-color content=#222222>
|
||||
<title>WLED Live Preview</title>
|
||||
// Autogenerated from wled00/data/update.htm, do not edit!!
|
||||
const char PAGE_update[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta content="width=device-width" name="viewport">
|
||||
<title>WLED Update</title><script>function B(){window.history.back()}</script>
|
||||
<style>
|
||||
body {margin: 0;}
|
||||
#canv {background: black;filter: brightness(175%);width: 100%;height: 100%;position: absolute;}
|
||||
</style></head>
|
||||
<body>
|
||||
<div id="canv" />
|
||||
<script>
|
||||
update();
|
||||
var tmout = null;
|
||||
function update()
|
||||
{
|
||||
if (document.hidden) {
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 250);
|
||||
return;
|
||||
}
|
||||
fetch('/json/live')
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 2500);
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
.then(json => {
|
||||
var str = "linear-gradient(90deg,";
|
||||
var len = json.leds.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
var leddata = json.leds[i];
|
||||
if (leddata.length > 6) leddata = leddata.substring(2);
|
||||
str += "#" + leddata;
|
||||
if (i < len -1) str += ","
|
||||
}
|
||||
str += ")";
|
||||
document.getElementById("canv").style.background = str;
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 40);
|
||||
})
|
||||
.catch(function (error) {
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 2500);
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</body></html>)=====";
|
||||
.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: 0.10.2<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>)=====";
|
||||
|
||||
|
||||
/*
|
||||
* favicon
|
||||
*/
|
||||
// Autogenerated from wled00/data/welcome.htm, do not edit!!
|
||||
const char PAGE_welcome[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta charset="utf-8"><meta
|
||||
content="width=device-width" name="viewport"><meta name="theme-color"
|
||||
content="#333333"><title>WLED Setup</title><style>
|
||||
body{font-family:Verdana,Helvetica,sans-serif;text-align:center;background-color:#333;margin:0;color:#fff}button{outline:0;cursor:pointer;padding:8px;margin:10px;width:230px;text-transform:uppercase;font-family:helvetica;font-size:19px;background-color:#222;color:#fff;border:0 solid #fff;border-radius:5px}svg{fill:#fff}
|
||||
</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><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></body>
|
||||
</html>)=====";
|
||||
|
||||
|
||||
// Autogenerated from wled00/data/liveview.htm, do not edit!!
|
||||
const char PAGE_liveview[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta name="viewport"
|
||||
content="width=device-width,initial-scale=1,minimum-scale=1"><meta
|
||||
charset="utf-8"><meta name="theme-color" content="#222222"><title>
|
||||
WLED Live Preview</title><style>
|
||||
body{margin:0}#canv{background:#000;filter:brightness(175%);width:100%;height:100%;position:absolute}
|
||||
</style></head><body><div id="canv"><script>update();
|
||||
|
||||
var tmout = null;
|
||||
function update()
|
||||
{
|
||||
if (document.hidden) {
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 250);
|
||||
return;
|
||||
}
|
||||
fetch('/json/live')
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 2500);
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
.then(json => {
|
||||
var str = "linear-gradient(90deg,";
|
||||
var len = json.leds.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
var leddata = json.leds[i];
|
||||
if (leddata.length > 6) leddata = leddata.substring(2);
|
||||
str += "#" + leddata;
|
||||
if (i < len -1) str += ","
|
||||
}
|
||||
str += ")";
|
||||
document.getElementById("canv").style.background = str;
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 40);
|
||||
})
|
||||
.catch(function (error) {
|
||||
clearTimeout(tmout);
|
||||
tmout = setTimeout(update, 2500);
|
||||
})
|
||||
|
||||
}</script></body></html>)=====";
|
||||
|
||||
|
||||
// Autogenerated from wled00/data/favicon.ico, do not edit!!
|
||||
const uint16_t favicon_length = 954;
|
||||
const uint8_t favicon[] PROGMEM = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x00,
|
||||
0x18, 0x00, 0x86, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x89, 0x50,
|
||||
0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48,
|
||||
0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x08, 0x06,
|
||||
0x00, 0x00, 0x00, 0x1F, 0xF3, 0xFF, 0x61, 0x00, 0x00, 0x00, 0x4D, 0x49,
|
||||
0x44, 0x41, 0x54, 0x38, 0x8D, 0x63, 0xFC, 0xFF, 0xFF, 0x3F, 0x03, 0xB1,
|
||||
0x80, 0xD1, 0x9E, 0x01, 0x43, 0x31, 0x13, 0xD1, 0xBA, 0x71, 0x00, 0x8A,
|
||||
0x0D, 0x60, 0x21, 0xA4, 0x00, 0xD9, 0xD9, 0xFF, 0x0F, 0x32, 0x30, 0x52,
|
||||
0xDD, 0x05, 0xB4, 0xF1, 0x02, 0xB6, 0xD0, 0xA6, 0x99, 0x0B, 0x68, 0x1F,
|
||||
0x0B, 0xD8, 0x42, 0x9E, 0xAA, 0x2E, 0xA0, 0xD8, 0x00, 0x46, 0x06, 0x3B,
|
||||
0xCC, 0xCC, 0x40, 0xC8, 0xD9, 0x54, 0x75, 0x01, 0xE5, 0x5E, 0x20, 0x25,
|
||||
0x3B, 0x63, 0x03, 0x00, 0x3E, 0xB7, 0x11, 0x5A, 0x8D, 0x1C, 0x07, 0xB4,
|
||||
0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
|
||||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x86, 0x00,
|
||||
0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00,
|
||||
0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x08, 0x06,
|
||||
0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff, 0x61, 0x00, 0x00, 0x00, 0x4d, 0x49, 0x44, 0x41, 0x54, 0x38,
|
||||
0x8d, 0x63, 0xfc, 0xff, 0xff, 0x3f, 0x03, 0xb1, 0x80, 0xd1, 0x9e, 0x01, 0x43, 0x31, 0x13, 0xd1,
|
||||
0xba, 0x71, 0x00, 0x8a, 0x0d, 0x60, 0x21, 0xa4, 0x00, 0xd9, 0xd9, 0xff, 0x0f, 0x32, 0x30, 0x52,
|
||||
0xdd, 0x05, 0xb4, 0xf1, 0x02, 0xb6, 0xd0, 0xa6, 0x99, 0x0b, 0x68, 0x1f, 0x0b, 0xd8, 0x42, 0x9e,
|
||||
0xaa, 0x2e, 0xa0, 0xd8, 0x00, 0x46, 0x06, 0x3b, 0xcc, 0xcc, 0x40, 0xc8, 0xd9, 0x54, 0x75, 0x01,
|
||||
0xe5, 0x5e, 0x20, 0x25, 0x3b, 0x63, 0x03, 0x00, 0x3e, 0xb7, 0x11, 0x5a, 0x8d, 0x1c, 0x07, 0xb4,
|
||||
0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
|
||||
};
|
||||
|
||||
|
@ -1,484 +1,526 @@
|
||||
/*
|
||||
* Settings html
|
||||
*/
|
||||
* 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!
|
||||
*/
|
||||
|
||||
//common CSS of settings pages
|
||||
const char PAGE_settingsCss[] PROGMEM = R"=====(<style>body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}hr{border-color:#666}button{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}.helpB{text-align:left;position:absolute;width:60px}input{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}input[type=number]{width:4em}select{background:#333;color:#fff;font-family:Verdana,sans-serif;border:0.5ch solid #333}td{padding:2px;}.d5{width:4.5em !important;}</style>)=====";
|
||||
// Autogenerated from wled00/data/style.css, do not edit!!
|
||||
const char PAGE_settingsCss[] PROGMEM = R"=====(<style>body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%;margin:0}hr{border-color:#666}button{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:8px;margin-top:12px}.helpB{text-align:left;position:absolute;width:60px}input{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}input[type=number]{width:4em}select{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}td{padding:2px}.d5{width:4.5em!important}</style>)=====";
|
||||
|
||||
//settings menu
|
||||
const char PAGE_settings[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><title>WLED Settings</title><style>body{text-align:center;background:#222;height:100%%;margin:0}html{--h:11.55vh}button{background:#333;color:#fff;font-family:Verdana,Helvetica,sans-serif;border:.3ch solid #333;display:inline-block;font-size:8vmin;height:var(--h);width:95%%;margin-top:2.4vh}</style>
|
||||
<script>function BB(){if(window.frameElement){document.getElementById("b").style.display="none";document.documentElement.style.setProperty("--h","13.86vh")}};</script></head>
|
||||
<body onload=BB()>
|
||||
<form action=/><button type=submit id=b>Back</button></form>
|
||||
<form action=/settings/wifi><button type=submit>WiFi Setup</button></form>
|
||||
<form action=/settings/leds><button type=submit>LED Preferences</button></form>
|
||||
<form action=/settings/ui><button type=submit>User Interface</button></form>%DMXMENU%
|
||||
<form action=/settings/sync><button type=submit>Sync Interfaces</button></form>
|
||||
<form action=/settings/time><button type=submit>Time & Macros</button></form>
|
||||
<form action=/settings/sec><button type=submit>Security & Updates</button></form>
|
||||
|
||||
// Autogenerated from wled00/data/settings.htm, do not edit!!
|
||||
const char PAGE_settings[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta http-equiv="Content-Type"
|
||||
content="text/html; charset=windows-1252"><title>WLED Settings</title><style>
|
||||
body{text-align:center;background:#222;height:100;margin:0}html{--h:11.55vh}button{background:#333;color:#fff;font-family:Verdana,Helvetica,sans-serif;border:.3ch solid #333;display:inline-block;font-size:8vmin;height:var(--h);width:95%%;margin-top:2.4vh}
|
||||
</style><script>
|
||||
function BB(){window.frameElement&&(document.getElementById("b").style.display="none",document.documentElement.style.setProperty("--h","13.86vh"))}
|
||||
</script></head><body onload="BB()"><form action="/"><button type="submit"
|
||||
id="b">Back</button></form><form action="/settings/wifi"><button type="submit">
|
||||
WiFi Setup</button></form><form action="/settings/leds"><button type="submit">
|
||||
LED Preferences</button></form><form action="/settings/ui"><button
|
||||
type="submit">User Interface</button></form>%DMXMENU%<form action="/settings/sync">
|
||||
<button type="submit">Sync Interfaces</button></form><form
|
||||
action="/settings/time"><button type="submit">Time & Macros</button></form><form
|
||||
action="/settings/sec"><button type="submit">Security & Updates</button></form>
|
||||
</body></html>)=====";
|
||||
|
||||
|
||||
//wifi settings
|
||||
const char PAGE_settings_wifi[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8">
|
||||
<title>WiFi Settings</title><script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#wifi-settings");}function B(){window.history.back();}function GetV(){var d=document;
|
||||
// Autogenerated from wled00/data/settings_wifi.htm, do not edit!!
|
||||
const char PAGE_settings_wifi[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport"
|
||||
content="width=500"><title>WiFi Settings</title><script>
|
||||
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#wifi-settings")}function B(){window.open("/settings","_self")}function GetV() {var d=document;
|
||||
%CSS%%SCSS%</head><body onload="GetV()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<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>
|
||||
Network password: <br> <input type="password" name="CP" maxlength="63"><br>
|
||||
Static IP (leave at 0.0.0.0 for DHCP):<br>
|
||||
<input name="I0" type="number" min="0" max="255" required> .
|
||||
<input name="I1" type="number" min="0" max="255" required> .
|
||||
<input name="I2" type="number" min="0" max="255" required> .
|
||||
<input name="I3" type="number" min="0" max="255" required><br>
|
||||
Static gateway:<br>
|
||||
<input name="G0" type="number" min="0" max="255" required> .
|
||||
<input name="G1" type="number" min="0" max="255" required> .
|
||||
<input name="G2" type="number" min="0" max="255" required> .
|
||||
<input name="G3" type="number" min="0" max="255" required><br>
|
||||
Static subnet mask:<br>
|
||||
<input name="S0" type="number" min="0" max="255" required> .
|
||||
<input name="S1" type="number" min="0" max="255" required> .
|
||||
<input name="S2" type="number" min="0" max="255" required> .
|
||||
<input name="S3" type="number" min="0" max="255" required><br>
|
||||
mDNS address (leave empty for no mDNS):<br/>
|
||||
http:// <input name="CM" maxlength="32"> .local<br>
|
||||
Client IP: <span class="sip"> Not connected </span><br>
|
||||
<h3>Configure Access Point</h3>
|
||||
AP name (SSID):<br><input name="AS" maxlength="32"><br>
|
||||
Hide AP name: <input type="checkbox" name="AH"><br>
|
||||
AP password (leave empty for open):<br> <input type="password" name="AP" maxlength="63"><br>
|
||||
Access Point WiFi channel: <input name="AC" type="number" min="1" max="13" required><br>
|
||||
AP opens:
|
||||
<select name="AB">
|
||||
<option value="0">No connection after boot</option>
|
||||
<option value="1">Disconnected</option>
|
||||
<option value="2">Always</option>
|
||||
<option value="3">Never (not recommended)</option></select><br>
|
||||
AP IP: <span class="sip"> Not active </span><br>
|
||||
<h3>Experimental</h3>
|
||||
Disable WiFi sleep: <input type="checkbox" name="WS"><br>
|
||||
<i>Can help with connectivity issues.<br>
|
||||
Do not enable if WiFi is working correctly, increases power consumption.</i>
|
||||
<hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Connect</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>)=====";
|
||||
<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 & 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>Network password:<br><input type="password" name="CP" maxlength="63"><br>
|
||||
Static IP (leave at 0.0.0.0 for DHCP):<br><input name="I0" type="number"
|
||||
min="0" max="255" required> . <input name="I1" type="number" min="0" max="255"
|
||||
required> . <input name="I2" type="number" min="0" max="255" required> . <input
|
||||
name="I3" type="number" min="0" max="255" required><br>Static gateway:<br><input
|
||||
name="G0" type="number" min="0" max="255" required> . <input name="G1"
|
||||
type="number" min="0" max="255" required> . <input name="G2" type="number"
|
||||
min="0" max="255" required> . <input name="G3" type="number" min="0" max="255"
|
||||
required><br>Static subnet mask:<br><input name="S0" type="number" min="0"
|
||||
max="255" required> . <input name="S1" type="number" min="0" max="255" required>
|
||||
. <input name="S2" type="number" min="0" max="255" required> . <input
|
||||
name="S3" type="number" min="0" max="255" required><br>
|
||||
mDNS address (leave empty for no mDNS):<br>http:// <input name="CM"
|
||||
maxlength="32"> .local<br>Client IP: <span class="sip">Not connected</span><br>
|
||||
<h3>Configure Access Point</h3>AP SSID (leave empty for no AP):<br><input
|
||||
name="AS" maxlength="32"><br>Hide AP name: <input type="checkbox" name="AH"><br>
|
||||
AP password (leave empty for open):<br><input type="password" name="AP"
|
||||
maxlength="63"><br>Access Point WiFi channel: <input name="AC" type="number"
|
||||
min="1" max="13" required><br>AP opens: <select name="AB"><option value="0">
|
||||
No connection after boot</option><option value="1">Disconnected</option><option
|
||||
value="2">Always</option><option value="3">Never (not recommended)</option>
|
||||
</select><br>AP IP: <span class="sip">Not active</span><br><h3>Experimental</h3>
|
||||
Disable WiFi sleep: <input type="checkbox" name="WS"><br><i>
|
||||
Can help with connectivity issues.<br>
|
||||
Do not enable if WiFi is working correctly, increases power consumption.</i><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">
|
||||
Save & Connect</button></form></body></html>)=====";
|
||||
|
||||
|
||||
//LED settings
|
||||
const char PAGE_settings_leds[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset=utf-8>
|
||||
<meta name=viewport content="width=500">
|
||||
<title>LED Settings</title>
|
||||
<script>var d=document,laprev=55;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings")}function B(){window.open("/settings","_self")}function S(){GetV();setABL()}
|
||||
function enABL(){var a=d.getElementById("able").checked;d.Sf.LA.value=(a)?laprev:0;d.getElementById("abl").style.display=(a)?"inline":"none";d.getElementById("psu2").style.display=(a)?"inline":"none";if(d.Sf.LA.value>0){setABL()}}function enLA(){var a=d.Sf.LAsel.value;d.Sf.LA.value=a;d.getElementById("LAdis").style.display=(a==50)?"inline":"none";UI()}function setABL(){d.getElementById("able").checked=true;d.Sf.LAsel.value=50;switch(parseInt(d.Sf.LA.value)){case 0:d.getElementById("able").checked=false;enABL();break;case 30:d.Sf.LAsel.value=30;break;case 35:d.Sf.LAsel.value=35;break;case 55:d.Sf.LAsel.value=55;break;case 255:d.Sf.LAsel.value=255;break;default:d.getElementById("LAdis").style.display="inline"}UI()}function UI(){var b=d.querySelectorAll(".wc"),a=b.length;for(i=0;i<a;i++){b[i].style.display=(d.getElementById("rgbw").checked)?"inline":"none"}d.getElementById("ledwarning").style.display=(d.Sf.LC.value>1000)?"inline":"none";d.getElementById("ampwarning").style.display=(d.Sf.MA.value>7200)?"inline":"none";if(d.Sf.LA.value==255){laprev=12} else if(d.Sf.LA.value>0){laprev=d.Sf.LA.value}var j=Math.ceil((100+d.Sf.LC.value*laprev)/500)/2;j=(j>5)?Math.ceil(j):j;var g="";var e=(d.Sf.LAsel.value==30);var i=(d.Sf.LAsel.value==255);if(j<1.02&&!e&&!i){g="ESP 5V pin with 1A USB supply"}else{g+=e?"12V ":i?"WS2815 12V ":"5V ";g+=j;g+="A supply connected to LEDs"}var h=Math.ceil((100+d.Sf.LC.value*laprev)/1500)/2;h=(h>5)?Math.ceil(h):h;var c="(for most effects, ~";c+=h;c+="A is enough)<br>";d.getElementById("psu").innerHTML=g;d.getElementById("psu2").innerHTML=i?"":c}function GetV(){var d=document;
|
||||
%CSS%%SCSS%</head><body onload=S()>
|
||||
<form id=form_s name=Sf method=post>
|
||||
<div class=helpB><button type=button onclick=H()>?</button></div>
|
||||
<button type=button onclick=B()>Back</button><button type=submit>Save</button><hr>
|
||||
<h2>LED setup</h2>
|
||||
LED count: <input name=LC type=number min=1 max=1500 oninput=UI() required><br>
|
||||
<div id=ledwarning style=color:orange;display:none>
|
||||
// Autogenerated from wled00/data/settings_leds.htm, do not edit!!
|
||||
const char PAGE_settings_leds[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport"
|
||||
content="width=500"><title>LED Settings</title><script>
|
||||
var d=document,laprev=55;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#led-settings")}function B(){window.open("/settings","_self")}function S(){GetV(),setABL()}function enABL(){var e=d.getElementById("able").checked;d.Sf.LA.value=e?laprev:0,d.getElementById("abl").style.display=e?"inline":"none",d.getElementById("psu2").style.display=e?"inline":"none",0<d.Sf.LA.value&&setABL()}function enLA(){var e=d.Sf.LAsel.value;d.Sf.LA.value=e,d.getElementById("LAdis").style.display=50==e?"inline":"none",UI()}function setABL(){switch(d.getElementById("able").checked=!0,d.Sf.LAsel.value=50,parseInt(d.Sf.LA.value)){case 0:d.getElementById("able").checked=!1,enABL();break;case 30:d.Sf.LAsel.value=30;break;case 35:d.Sf.LAsel.value=35;break;case 55:d.Sf.LAsel.value=55;break;case 255:d.Sf.LAsel.value=255;break;default:d.getElementById("LAdis").style.display="inline"}UI()}function UI(){var e=d.querySelectorAll(".wc"),l=e.length;for(i=0;i<l;i++)e[i].style.display=d.getElementById("rgbw").checked?"inline":"none";d.getElementById("ledwarning").style.display=1e3<d.Sf.LC.value?"inline":"none",d.getElementById("ampwarning").style.display=7200<d.Sf.MA.value?"inline":"none",255==d.Sf.LA.value?laprev=12:0<d.Sf.LA.value&&(laprev=d.Sf.LA.value);var n=5<(n=Math.ceil((100+d.Sf.LC.value*laprev)/500)/2)?Math.ceil(n):n,t="",a=30==d.Sf.LAsel.value,s=255==d.Sf.LAsel.value;n<1.02&&!a&&!s?t="ESP 5V pin with 1A USB supply":(t+=a?"12V ":s?"WS2815 12V ":"5V ",t+=n,t+="A supply connected to LEDs");var u=Math.ceil((100+d.Sf.LC.value*laprev)/1500)/2,c="(for most effects, ~";c+=u=5<u?Math.ceil(u):u,c+="A is enough)<br>",d.getElementById("psu").innerHTML=t,d.getElementById("psu2").innerHTML=s?"":c}function GetV() {var d=document;
|
||||
%CSS%%SCSS%</head><body onload="S()"><form
|
||||
id="form_s" name="Sf" method="post"><div class="helpB"><button type="button"
|
||||
onclick="H()">?</button></div><button type="button" onclick="B()">Back</button>
|
||||
<button type="submit">Save</button><hr><h2>LED setup</h2>LED count: <input
|
||||
name="LC" type="number" min="1" max="1500" oninput="UI()" required><br><div
|
||||
id="ledwarning" style="color:orange;display:none">
|
||||
⚠ You might run into stability or lag issues.<br>
|
||||
Use less than 1000 LEDs per ESP for the best experience!<br>
|
||||
</div>
|
||||
<i>Recommended power supply for brightest white:</i><br>
|
||||
<b><span id=psu>?</span></b><br>
|
||||
<span id=psu2><br></span>
|
||||
<br>
|
||||
Enable automatic brightness limiter: <input type=checkbox name=ABen onchange=enABL() id=able><br>
|
||||
<div id=abl>
|
||||
Maximum Current: <input name=MA type=number min=250 max=65000 oninput=UI() required> mA<br>
|
||||
<div id=ampwarning style=color:orange;display:none>
|
||||
Use less than 1000 LEDs per ESP for the best experience!<br></div><i>
|
||||
Recommended power supply for brightest white:</i><br><b><span id="psu">?</span>
|
||||
</b><br><span id="psu2"><br></span><br>Enable automatic brightness limiter:
|
||||
<input type="checkbox" name="ABen" onchange="enABL()" id="able"><br><div
|
||||
id="abl">Maximum Current: <input name="MA" type="number" min="250" max="65000"
|
||||
oninput="UI()" required> mA<br><div id="ampwarning"
|
||||
style="color:orange;display:none">
|
||||
⚠ Your power supply provides high current.<br>
|
||||
To improve the safety of your setup,<br>
|
||||
please use thick cables,<br>
|
||||
multiple power injection points and a fuse!<br>
|
||||
</div>
|
||||
<i>Automatically limits brightness to stay close to the limit.<br>
|
||||
To improve the safety of your setup,<br>please use thick cables,<br>
|
||||
multiple power injection points and a fuse!<br></div><i>
|
||||
Automatically limits brightness to stay close to the limit.<br>
|
||||
Keep at <1A if powering LEDs directly from the ESP 5V pin!<br>
|
||||
If you are using an external power supply, enter its rating.<br>
|
||||
(Current estimated usage: <span class=pow>unknown</span>)</i><br><br>
|
||||
LED voltage (Max. current for a single LED):<br>
|
||||
<select name=LAsel onchange=enLA()>
|
||||
<option value=55 selected>5V default (55mA)</option>
|
||||
<option value=35>5V efficient (35mA)</option>
|
||||
<option value=30>12V (30mA)</option>
|
||||
<option value=255>WS2815 (12mA)</option>
|
||||
<option value=50>Custom</option>
|
||||
</select><br>
|
||||
<span id=LAdis style=display:none>Custom max. current per LED: <input name=LA type=number min=0 max=255 id=la oninput=UI() required> mA<br></span>
|
||||
<i>Keep at default if you are unsure about your type of LEDs.</i><br>
|
||||
</div>
|
||||
<br>
|
||||
LEDs are 4-channel type (RGBW): <input type=checkbox name=EW onchange=UI() id=rgbw><br>
|
||||
<span class=wc>
|
||||
Auto-calculate white channel from RGB:<br>
|
||||
<select name=AW>
|
||||
<option value=0>None</option>
|
||||
<option value=1>Brighter</option>
|
||||
<option value=2>Accurate</option>
|
||||
<option value=3>Dual</option>
|
||||
<option value=4>Legacy</option>
|
||||
</select>
|
||||
<br></span>
|
||||
Color order:
|
||||
<select name=CO>
|
||||
<option value=0>GRB</option>
|
||||
<option value=1>RGB</option>
|
||||
<option value=2>BRG</option>
|
||||
<option value=3>RBG</option>
|
||||
<option value=4>BGR</option>
|
||||
<option value=5>GBR</option>
|
||||
</select>
|
||||
<h3>Defaults</h3>
|
||||
Turn LEDs on after power up/reset: <input type=checkbox name=BO><br>
|
||||
Default brightness: <input name=CA type=number min=0 max=255 required> (0-255)<br><br>
|
||||
Apply preset <input name=BP type=number min=0 max=16 required> at boot (0 uses defaults)
|
||||
<br>- <i>or</i> -<br>
|
||||
Set current preset cycle setting as boot default: <input type=checkbox name=PC><br><br>
|
||||
Use Gamma correction for color: <input type=checkbox name=GC> (strongly recommended)<br>
|
||||
Use Gamma correction for brightness: <input type=checkbox name=GB> (not recommended)<br><br>
|
||||
Brightness factor: <input name=BF type=number min=1 max=255 required> %
|
||||
<h3>Transitions</h3>
|
||||
Crossfade: <input type=checkbox name=TF><br>
|
||||
Transition Time: <input name=TD maxlength=5 size=2> ms<br>
|
||||
Enable Palette transitions: <input type=checkbox name=PF>
|
||||
<h3>Timed light</h3>
|
||||
Default Duration: <input name=TL type=number min=1 max=255 required> min<br>
|
||||
Default Target brightness: <input name=TB type=number min=0 max=255 required><br>
|
||||
Fade down: <input type=checkbox name=TW><br>
|
||||
<h3>Advanced</h3>
|
||||
Palette blending:
|
||||
<select name=PB>
|
||||
<option value=0>Linear (wrap if moving)</option>
|
||||
<option value=1>Linear (always wrap)</option>
|
||||
<option value=2>Linear (never wrap)</option>
|
||||
<option value=3>None (not recommended)</option>
|
||||
</select><br>
|
||||
Reverse LED order (rotate 180): <input type=checkbox name=RV><br>
|
||||
Skip first LED: <input type=checkbox name=SL><hr>
|
||||
<button type=button onclick=B()>Back</button><button type=submit>Save</button>
|
||||
</form></body></html>)=====";
|
||||
(Current estimated usage: <span class="pow">unknown</span>)</i><br><br>
|
||||
LED voltage (Max. current for a single LED):<br><select name="LAsel"
|
||||
onchange="enLA()"><option value="55" selected="selected">5V default (55mA)
|
||||
</option><option value="35">5V efficient (35mA)</option><option value="30">
|
||||
12V (30mA)</option><option value="255">WS2815 (12mA)</option><option value="50">
|
||||
Custom</option></select><br><span id="LAdis" style="display:none">
|
||||
Custom max. current per LED: <input name="LA" type="number" min="0" max="255"
|
||||
id="la" oninput="UI()" required> mA<br></span><i>
|
||||
Keep at default if you are unsure about your type of LEDs.</i><br></div><br>
|
||||
LEDs are 4-channel type (RGBW): <input type="checkbox" name="EW"
|
||||
onchange="UI()" id="rgbw"><br><span class="wc">
|
||||
Auto-calculate white channel from RGB:<br><select name="AW"><option value="0">
|
||||
None</option><option value="1">Brighter</option><option value="2">Accurate
|
||||
</option><option value="3">Dual</option><option value="4">Legacy</option>
|
||||
</select><br></span>Color order: <select name="CO"><option value="0">GRB
|
||||
</option><option value="1">RGB</option><option value="2">BRG</option><option
|
||||
value="3">RBG</option><option value="4">BGR</option><option value="5">GBR
|
||||
</option></select><h3>Defaults</h3>Turn LEDs on after power up/reset: <input
|
||||
type="checkbox" name="BO"><br>Default brightness: <input name="CA"
|
||||
type="number" min="0" max="255" required> (0-255)<br><br>Apply preset <input
|
||||
name="BP" type="number" min="0" max="16" required> at boot (0 uses defaults)<br>
|
||||
- <i>or</i> -<br>Set current preset cycle setting as boot default: <input
|
||||
type="checkbox" name="PC"><br><br>Use Gamma correction for color: <input
|
||||
type="checkbox" name="GC"> (strongly recommended)<br>
|
||||
Use Gamma correction for brightness: <input type="checkbox" name="GB">
|
||||
(not recommended)<br><br>Brightness factor: <input name="BF" type="number"
|
||||
min="1" max="255" required> %<h3>Transitions</h3>Crossfade: <input
|
||||
type="checkbox" name="TF"><br>Transition Time: <input name="TD" maxlength="5"
|
||||
size="2"> ms<br>Enable Palette transitions: <input type="checkbox" name="PF">
|
||||
<h3>Timed light</h3>Default Duration: <input name="TL" type="number" min="1"
|
||||
max="255" required> min<br>Default Target brightness: <input name="TB"
|
||||
type="number" min="0" max="255" required><br>Mode: <select name="TW"><option
|
||||
value="0">Wait and set</option><option value="1">Fade</option><option value="2">
|
||||
Fade Color</option><option value="3">Sunrise</option></select><h3>Advanced</h3>
|
||||
Palette blending: <select name="PB"><option value="0">Linear (wrap if moving)
|
||||
</option><option value="1">Linear (always wrap)</option><option value="2">
|
||||
Linear (never wrap)</option><option value="3">None (not recommended)</option>
|
||||
</select><br>Reverse LED order (rotate 180): <input type="checkbox" name="RV">
|
||||
<br>Skip first LED: <input type="checkbox" name="SL"><hr><button type="button"
|
||||
onclick="B()">Back</button><button type="submit">Save</button></form></body>
|
||||
</html>)=====";
|
||||
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
//DMX Output settings
|
||||
const char PAGE_settings_dmx[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>DMX Settings</title><script>
|
||||
function GCH(num) {
|
||||
d=document;
|
||||
|
||||
d.getElementById('dmxchannels').innerHTML += "";
|
||||
for (i=0;i<num;i++) {
|
||||
d.getElementById('dmxchannels').innerHTML += "<span id=CH" + (i+1) + "s >Channel " + (i+1) + ": <select name=CH" + (i+1) + " id=\"CH" + (i+1) + "\"><option value=0>Set to 0</option><option value=1>Red</option><option value=2>Green</option><option value=3>Blue</option><option value=4>White</option><option value=5>Shutter (Brightness)</option><option value=6>Set to 255</option></select></span><br />\n";
|
||||
}
|
||||
}
|
||||
function mMap(){
|
||||
d=document;
|
||||
numCh=document.Sf.CN.value;
|
||||
numGap=document.Sf.CG.value;
|
||||
if (parseInt(numCh)>parseInt(numGap)) {
|
||||
d.getElementById("gapwarning").style.display="block";
|
||||
} else {
|
||||
d.getElementById("gapwarning").style.display="none";
|
||||
}
|
||||
for (i=0;i<15;i++) {
|
||||
if (i>=numCh) {
|
||||
d.getElementById("CH"+(i+1) + "s").style.opacity = "0.5";
|
||||
d.getElementById("CH"+(i+1)).disabled = true;
|
||||
|
||||
} else {
|
||||
d.getElementById("CH"+(i+1) + "s").style.opacity = "1";
|
||||
d.getElementById("CH"+(i+1)).disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
function S(){GCH(15);GetV();mMap();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}function B(){window.history.back();}function GetV(){var d=document;
|
||||
%CSS%%SCSS%</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
<h2>Imma firin ma lazer (if it has DMX support)</h2><!-- TODO: Change to something less-meme-related //-->
|
||||
|
||||
// Autogenerated from wled00/data/settings_dmx.htm, do not edit!!
|
||||
const char PAGE_settings_dmx[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta name="viewport" content="width=500"><meta
|
||||
charset="utf-8"><title>DMX Settings</title><script>
|
||||
function GCH(n){for(d=document,d.getElementById("dmxchannels").innerHTML+="",i=0;i<n;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(){for(d=document,numCh=document.Sf.CN.value,numGap=document.Sf.CG.value,parseInt(numCh)>parseInt(numGap)?d.getElementById("gapwarning").style.display="block":d.getElementById("gapwarning").style.display="none",i=0;i<15;i++)i>=numCh?(d.getElementById("CH"+(i+1)+"s").style.opacity="0.5",d.getElementById("CH"+(i+1)).disabled=!0):(d.getElementById("CH"+(i+1)+"s").style.opacity="1",d.getElementById("CH"+(i+1)).disabled=!1)}function S(){GCH(15),GetV(),mMap()}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX")}function B(){window.history.back()}function GetV() {var d=document;
|
||||
%CSS%%SCSS%</head><body onload="S()"><form
|
||||
id="form_s" name="Sf" method="post"><div class="helpB"><button type="button"
|
||||
onclick="H()">?</button></div><button type="button" onclick="B()">Back</button>
|
||||
<button type="submit">Save</button><hr><h2>
|
||||
Imma firin ma lazer (if it has DMX support)</h2>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>)=====";
|
||||
|
||||
Channels per fixture (15 max): <input type="number" min="1" max="15" name="CN" maxlength="2" onchange="mMap();"><br />
|
||||
Start channel: <input type="number" min="1" max="512" name="CS" maxlength="2"><br />
|
||||
Spacing between start channels: <input type="number" min="1" max="512" name="CG" maxlength="2" onchange="mMap();"> [ <a href="javascript:alert('if set to 10, first fixture will start at 10,\nsecond will start at 20 etc.\nRegardless of the channel count.\nMakes memorizing channel numbers easier.');">info</a> ]<br>
|
||||
<div id="gapwarning" style="color: orange; display: none;">WARNING: Channel gap is lower than channels per fixture.<br />This will cause overlap.</div>
|
||||
<button type="button" onclick="location.href='/dmxmap';">DMX Map</button><br>
|
||||
DMX fixtures start LED: <input type="number" min="0" max="1500" name="SL">
|
||||
<h3>channel functions</h3>
|
||||
<div id="dmxchannels"></div>
|
||||
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>)=====";
|
||||
|
||||
#else
|
||||
const char PAGE_settings_dmx[] PROGMEM = R"=====()=====";
|
||||
#endif
|
||||
|
||||
//User Interface settings
|
||||
const char PAGE_settings_ui[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>UI Settings</title><script>
|
||||
function gId(s){return document.getElementById(s);}function S(){GetV();Ct();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#user-interface-settings");}function B(){window.history.back();}function Ct(){if (gId("co").selected){gId("cth").style.display="block";}else{gId("cth").style.display="none";}}function GetV(){var d=document;
|
||||
%CSS%%SCSS%</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
<h2>Web Setup</h2>
|
||||
Server description: <input name="DS" maxlength="32"><br>
|
||||
Sync button toggles both send and receive: <input type="checkbox" name="ST"><br><br>
|
||||
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>)=====";
|
||||
// Autogenerated from wled00/data/settings_ui.htm, do not edit!!
|
||||
const char PAGE_settings_ui[] PROGMEM = R"=====(<!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 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 = "⚠ 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 = "⚠ 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();
|
||||
initial_ds = d.Sf.DS.value;
|
||||
initial_st = d.Sf.ST.checked;
|
||||
GetLS();
|
||||
}
|
||||
function H()
|
||||
{
|
||||
window.open("https://github.com/Aircoookie/WLED/wiki/Settings#user-interface-settings");
|
||||
}
|
||||
function B()
|
||||
{
|
||||
window.open("/settings","_self");
|
||||
}
|
||||
function UI()
|
||||
{
|
||||
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;
|
||||
%CSS%%SCSS%</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="button" onclick="Save()">Save</button><br><span
|
||||
id="lssuc" style="color:green;display:none">✔ Local UI settings saved!
|
||||
</span> <span id="lserr" style="color:red;display:none">
|
||||
⚠ 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><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>🥺<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>)=====";
|
||||
|
||||
|
||||
|
||||
//sync settings
|
||||
const char PAGE_settings_sync[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name=viewport content="width=500"><meta charset=utf-8><title>Sync Settings</title>
|
||||
<script>var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings")}function B(){window.open("/settings","_self")}function adj(){if(d.Sf.DI.value==6454){if(d.Sf.DA.value==1){d.Sf.DA.value=0}if(d.Sf.EU.value==1){d.Sf.EU.value=0}}else{if(d.Sf.DI.value==5568){if(d.Sf.DA.value==0){d.Sf.DA.value=1}if(d.Sf.EU.value==0){d.Sf.EU.value=1}}}}function SP(){var a=d.Sf.DI.value;d.getElementById("xp").style.display=(a>0)?"none":"block";if(a>0){d.Sf.EP.value=a}}function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568:d.Sf.DI.value=5568;break;case 6454:d.Sf.DI.value=6454;break}SP()}function S(){GetV();SetVal()};function GetV(){
|
||||
%CSS%%SCSS%</head>
|
||||
<body onload=S()>
|
||||
<form id=form_s name=Sf method=post>
|
||||
<div class=helpB><button type=button onclick=H()>?</button></div>
|
||||
<button type=button onclick=B()>Back</button><button type=submit>Save</button><hr>
|
||||
<h2>Sync setup</h2>
|
||||
<h3>Button setup</h3>
|
||||
On/Off button enabled: <input type=checkbox name=BT><br>
|
||||
Infrared remote:
|
||||
<select name=IR>
|
||||
<option value=0>Disabled</option>
|
||||
<option value=1>24-key RGB</option>
|
||||
<option value=2>24-key with CT</option>
|
||||
<option value=3>40-key blue</option>
|
||||
<option value=4>44-key RGB</option>
|
||||
<option value=5>21-key RGB</option>
|
||||
<option value=6>6-key black</option>
|
||||
</select><br>
|
||||
<a href=https://github.com/Aircoookie/WLED/wiki/Infrared-Control target=_blank>IR info</a>
|
||||
<h3>WLED Broadcast</h3>
|
||||
UDP Port: <input name=UP type=number min=1 max=65535 class=d5 required><br>
|
||||
Receive <input type=checkbox name=RB>Brightness, <input type=checkbox name=RC>Color, and <input type=checkbox name=RX>Effects<br>
|
||||
Send notifications on direct change: <input type=checkbox name=SD><br>
|
||||
Send notifications on button press: <input type=checkbox name=SB><br>
|
||||
Send Alexa notifications: <input type=checkbox name=SA><br>
|
||||
Send Philips Hue change notifications: <input type=checkbox name=SH><br>
|
||||
Send Macro notifications: <input type=checkbox name=SM><br>
|
||||
Send notifications twice: <input type=checkbox name=S2>
|
||||
<h3>Realtime</h3>
|
||||
Receive UDP realtime: <input type=checkbox name=RD><br><br>
|
||||
<i>Network DMX input</i><br>
|
||||
Type:
|
||||
<select name=DI onchange=SP();adj()>
|
||||
<option value=5568>E1.31 (sACN)</option>
|
||||
<option value=6454>Art-Net</option>
|
||||
<option value=0 selected>Custom port</option>
|
||||
</select><br>
|
||||
<div id=xp>Port: <input name=EP type=number min=1 max=65535 value=5568 class=d5 required><br></div>
|
||||
Multicast: <input type=checkbox name=EM><br>
|
||||
Start universe: <input name=EU type=number min=0 max=63999 required><br>
|
||||
<i>Reboot required.</i> Check out <a href=https://github.com/ahodges9/LedFx target=_blank>LedFx</a>!<br>
|
||||
Skip out-of-sequence packets: <input type=checkbox name=ES><br>
|
||||
DMX start address: <input name=DA type=number min=0 max=510 required><br>
|
||||
DMX mode:
|
||||
<select name=DM>
|
||||
<option value=0>Disabled</option>
|
||||
<option value=1>Single RGB</option>
|
||||
<option value=2>Single DRGB</option>
|
||||
<option value=3>Effect</option>
|
||||
<option value=4>Multi RGB</option>
|
||||
<option value=5>Multi DRGB</option>
|
||||
</select><br>
|
||||
<a href=https://github.com/Aircoookie/WLED/wiki/E1.31-DMX target=_blank>E1.31 info</a><br>
|
||||
Timeout: <input name=ET type=number min=1 max=65000 required> ms<br>
|
||||
Force max brightness: <input type=checkbox name=FB><br>
|
||||
Disable realtime gamma correction: <input type=checkbox name=RG><br>
|
||||
Realtime LED offset: <input name=WO type=number min=-255 max=255 required>
|
||||
<h3>Alexa Voice Assistant</h3>
|
||||
Emulate Alexa device: <input type=checkbox name=AL><br>
|
||||
Alexa invocation name: <input name=AI maxlength=32>
|
||||
<h3>Blynk</h3>
|
||||
<b>Blynk, MQTT and Hue sync all connect to external hosts!<br>
|
||||
// Autogenerated from wled00/data/settings_sync.htm, do not edit!!
|
||||
const char PAGE_settings_sync[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta name="viewport" content="width=500"><meta
|
||||
charset="utf-8"><title>Sync Settings</title><script>
|
||||
var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#sync-settings")}function B(){window.open("/settings","_self")}function adj(){6454==d.Sf.DI.value?(1==d.Sf.DA.value&&(d.Sf.DA.value=0),1==d.Sf.EU.value&&(d.Sf.EU.value=0)):5568==d.Sf.DI.value&&(0==d.Sf.DA.value&&(d.Sf.DA.value=1),0==d.Sf.EU.value&&(d.Sf.EU.value=1))}function SP(){var e=d.Sf.DI.value;d.getElementById("xp").style.display=0<e?"none":"block",0<e&&(d.Sf.EP.value=e)}function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568:d.Sf.DI.value=5568;break;case 6454:d.Sf.DI.value=6454}SP()}function S(){GetV(),SetVal()}function GetV() {
|
||||
%CSS%%SCSS%</head><body onload="S()"><form
|
||||
id="form_s" name="Sf" method="post"><div class="helpB"><button type="button"
|
||||
onclick="H()">?</button></div><button type="button" onclick="B()">Back</button>
|
||||
<button type="submit">Save</button><hr><h2>Sync setup</h2><h3>Button setup</h3>
|
||||
On/Off button enabled: <input type="checkbox" name="BT"><br>Infrared remote:
|
||||
<select name="IR"><option value="0">Disabled</option><option value="1">
|
||||
24-key RGB</option><option value="2">24-key with CT</option><option value="3">
|
||||
40-key blue</option><option value="4">44-key RGB</option><option value="5">
|
||||
21-key RGB</option><option value="6">6-key black</option><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>Receive <input type="checkbox"
|
||||
name="RB">Brightness, <input type="checkbox" name="RC">Color, and <input
|
||||
type="checkbox" name="RX">Effects<br>Send notifications on direct change: <input
|
||||
type="checkbox" name="SD"><br>Send notifications on button press: <input
|
||||
type="checkbox" name="SB"><br>Send Alexa notifications: <input type="checkbox"
|
||||
name="SA"><br>Send Philips Hue change notifications: <input type="checkbox"
|
||||
name="SH"><br>Send Macro notifications: <input type="checkbox" name="SM"><br>
|
||||
Send notifications twice: <input type="checkbox" name="S2"><h3>Realtime</h3>
|
||||
Receive UDP realtime: <input type="checkbox" name="RD"><br><br><i>
|
||||
Network DMX input</i><br>Type: <select name="DI" onchange="SP(),adj()"><option
|
||||
value="5568">E1.31 (sACN)</option><option value="6454">Art-Net</option><option
|
||||
value="0" selected="selected">Custom port</option></select><br><div id="xp">
|
||||
Port: <input name="EP" type="number" min="1" max="65535" value="5568"
|
||||
class="d5" required><br></div>Multicast: <input type="checkbox" name="EM"><br>
|
||||
Start universe: <input name="EU" type="number" min="0" max="63999" required><br>
|
||||
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx"
|
||||
target="_blank">LedFx</a>!<br>Skip out-of-sequence packets: <input
|
||||
type="checkbox" name="ES"><br>DMX start address: <input name="DA" type="number"
|
||||
min="0" max="510" required><br>DMX mode: <select name="DM"><option value="0">
|
||||
Disabled</option><option value="1">Single RGB</option><option value="2">
|
||||
Single DRGB</option><option value="3">Effect</option><option value="4">Multi RGB
|
||||
</option><option value="5">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>Force max brightness: <input type="checkbox" name="FB"><br>
|
||||
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
|
||||
Realtime LED offset: <input name="WO" type="number" min="-255" max="255"
|
||||
required><h3>Alexa Voice Assistant</h3>Emulate Alexa device: <input
|
||||
type="checkbox" name="AL"><br>Alexa invocation name: <input name="AI"
|
||||
maxlength="32"><h3>Blynk</h3><b>
|
||||
Blynk, MQTT and Hue sync all connect to external hosts!<br>
|
||||
This may impact the responsiveness of the ESP8266.</b><br>
|
||||
For best results, only use one of these services at a time.<br>
|
||||
(alternatively, connect a second ESP to them and use the UDP sync)<br><br>
|
||||
Device Auth token: <input name=BK maxlength=33><br>
|
||||
<i>Clear the token field to disable. </i><a href=https://github.com/Aircoookie/WLED/wiki/Blynk target=_blank>Setup info</a>
|
||||
<h3>MQTT</h3>
|
||||
Enable MQTT: <input type=checkbox name=MQ><br>
|
||||
Broker: <input name=MS maxlength=32>
|
||||
Port: <input name=MQPORT type=number min=1 max=65535 class=d5><br>
|
||||
<b>The MQTT credentials are sent over an unsecured connection.<br>
|
||||
Never use the MQTT password for another service!</b><br>
|
||||
Username: <input name=MQUSER maxlength=40><br>
|
||||
Password: <input type=password input name=MQPASS maxlength=40><br>
|
||||
Client ID: <input name=MQCID maxlength=40><br>
|
||||
Device Topic: <input name=MD maxlength=32><br>
|
||||
Group Topic: <input name=MG maxlength=32><br>
|
||||
<i>Reboot required to apply changes. </i><a href=https://github.com/Aircoookie/WLED/wiki/MQTT target=_blank>MQTT info</a>
|
||||
<h3>Philips Hue</h3>
|
||||
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
|
||||
Poll Hue light <input name=HL type=number min=1 max=99> every <input name=HI type=number min=100 max=65000> ms: <input type=checkbox name=HP><br>
|
||||
Then, receive <input type=checkbox name=HO> On/Off, <input type=checkbox name=HB> Brightness, and <input type=checkbox name=HC> Color<br>
|
||||
Hue Bridge IP:<br>
|
||||
<input name=H0 type=number min=0 max=255> .
|
||||
<input name=H1 type=number min=0 max=255> .
|
||||
<input name=H2 type=number min=0 max=255> .
|
||||
<input name=H3 type=number min=0 max=255><br>
|
||||
<b>Press the pushlink button on the bridge, after that save this page!</b><br>
|
||||
(when first connecting)<br>
|
||||
Hue status: <span class=sip> Disabled in this build </span><hr>
|
||||
<button type=button onclick=B()>Back</button><button type=submit>Save</button>
|
||||
</form>
|
||||
</body></html>)=====";
|
||||
Device Auth token: <input name="BK" maxlength="33"><br><i>
|
||||
Clear the token field to disable. </i><a
|
||||
href="https://github.com/Aircoookie/WLED/wiki/Blynk" target="_blank">Setup info
|
||||
</a><h3>MQTT</h3>Enable MQTT: <input type="checkbox" name="MQ"><br>Broker:
|
||||
<input name="MS" maxlength="32"> Port: <input name="MQPORT" type="number"
|
||||
min="1" max="65535" class="d5"><br><b>
|
||||
The MQTT credentials are sent over an unsecured connection.<br>
|
||||
Never use the MQTT password for another service!</b><br>Username: <input
|
||||
name="MQUSER" maxlength="40"><br>Password: <input type="password" input
|
||||
name="MQPASS" maxlength="40"><br>Client ID: <input name="MQCID" maxlength="40">
|
||||
<br>Device Topic: <input name="MD" maxlength="32"><br>Group Topic: <input
|
||||
name="MG" maxlength="32"><br><i>Reboot required to apply changes. </i><a
|
||||
href="https://github.com/Aircoookie/WLED/wiki/MQTT" target="_blank">MQTT info
|
||||
</a><h3>Philips Hue</h3><i>
|
||||
You can find the bridge IP and the light number in the 'About' section of the hue app.
|
||||
</i><br>Poll Hue light <input name="HL" type="number" min="1" max="99"> every
|
||||
<input name="HI" type="number" min="100" max="65000"> ms: <input
|
||||
type="checkbox" name="HP"><br>Then, receive <input type="checkbox" name="HO">
|
||||
On/Off, <input type="checkbox" name="HB"> Brightness, and <input
|
||||
type="checkbox" name="HC"> Color<br>Hue Bridge IP:<br><input name="H0"
|
||||
type="number" min="0" max="255"> . <input name="H1" type="number" min="0"
|
||||
max="255"> . <input name="H2" type="number" min="0" max="255"> . <input
|
||||
name="H3" type="number" min="0" max="255"><br><b>
|
||||
Press the pushlink button on the bridge, after that save this page!</b><br>
|
||||
(when first connecting)<br>Hue status: <span class="sip">Disabled in this build
|
||||
</span><hr><button type="button" onclick="B()">Back</button><button
|
||||
type="submit">Save</button></form></body></html>)=====";
|
||||
|
||||
|
||||
//time and macro settings
|
||||
const char PAGE_settings_time[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8"><title>Time Settings</title>
|
||||
<script>var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings");}function B(){window.open("/settings","_self");}function S(){BTa();GetV();Cs();FC();}function gId(s){return d.getElementById(s);}function Cs(){gId("cac").style.display="none";gId("coc").style.display="block";gId("ccc").style.display="none";if (gId("ca").selected){gId("cac").style.display="block";}if (gId("cc").selected){gId("coc").style.display="none";gId("ccc").style.display="block";}if (gId("cn").selected){gId("coc").style.display="none";}}
|
||||
function BTa(){var ih="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Macro</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";for (i=0;i<8;i++){ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" type=\"number\" min=\"0\" max=\"16\"></td>";for (j=1;j<8;j++) ih+="<td><input id=\"W"+i+j+"\" type=\"checkbox\"></td>";}gId("TMT").innerHTML=ih;}
|
||||
function FC(){for(j=0;j<8;j++){for(i=0;i<8;i++)gId("W"+i+j).checked=gId("W"+i).value>>j&1;}}
|
||||
function Wd(){a=[0,0,0,0,0,0,0,0];for(i=0;i<8;i++){m=1;for(j=0;j<8;j++){a[i]+=gId("W"+i+j).checked*m;m*=2;}gId("W"+i).value=a[i];}}function GetV(){
|
||||
%CSS%%SCSS%</head>
|
||||
<body onload="S()">
|
||||
<form id="form_s" name="Sf" method="post" onsubmit="Wd()">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
|
||||
<h2>Time setup</h2>
|
||||
Get time from NTP server: <input type="checkbox" name="NT"><br>
|
||||
<input name="NS" maxlength="32"><br>
|
||||
Use 24h format: <input type="checkbox" name="CF"><br>
|
||||
Time zone:
|
||||
<select name="TZ">
|
||||
<option value="0" selected>GMT(UTC)</option>
|
||||
<option value="1">GMT/BST</option>
|
||||
<option value="2">CET/CEST</option>
|
||||
<option value="3">EET/EEST</option>
|
||||
<option value="4">US-EST/EDT</option>
|
||||
<option value="5">US-CST/CDT</option>
|
||||
<option value="6">US-MST/MDT</option>
|
||||
<option value="7">US-AZ</option>
|
||||
<option value="8">US-PST/PDT</option>
|
||||
<option value="9">CST(AWST)</option>
|
||||
<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="14">IST (India)</option>
|
||||
<option value="15">CA-Saskatchewan</option>
|
||||
<option value="16">ACST</option>
|
||||
<option value="17">ACST/ACDT</option>
|
||||
</select><br>
|
||||
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
|
||||
Current local time is <span class="times">unknown</span>.
|
||||
<h3>Clock</h3>
|
||||
Clock Overlay:
|
||||
<select name="OL" onchange="Cs()">
|
||||
<option value="0" id="cn" selected>None</option>
|
||||
<option value="1" id="ca">Analog Clock</option>
|
||||
<option value="2" disabled>-</option>
|
||||
<option value="3" id="cc">Cronixie Clock</option>
|
||||
</select><br>
|
||||
<div id="coc">
|
||||
First LED: <input name="O1" type="number" min="0" max="255" required> Last LED: <input name="O2" type="number" min="0" max="255" required><br>
|
||||
<div id="cac">
|
||||
12h LED: <input name="OM" type="number" min="0" max="255" required><br>
|
||||
Show 5min marks: <input type="checkbox" name="O5"><br></div>
|
||||
Seconds (as trail): <input type="checkbox" name="OS"><br>
|
||||
</div>
|
||||
<div id="ccc">
|
||||
Cronixie Display: <input name="CX" maxlength="6"><br>
|
||||
Cronixie Backlight: <input type="checkbox" name="CB"><br>
|
||||
</div>
|
||||
Countdown Mode: <input type="checkbox" name="CE"><br>
|
||||
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 short press macro: <input name="MP" type="number" min="0" max="16" required><br>
|
||||
Long press: <input name="ML" type="number" min="0" max="16" required> Double press: <input name="MD" type="number" min="0" max="16" required><br>
|
||||
Countdown-Over macro: <input name="MC" type="number" min="0" max="16" required><br>
|
||||
Timed-Light-Over macro: <input name="MN" type="number" min="0" max="16" required><br>
|
||||
Time-Controlled macros:<br>
|
||||
<div style="display: inline-block">
|
||||
<table id="TMT">
|
||||
</table></div><hr>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>)=====";
|
||||
// Autogenerated from wled00/data/settings_time.htm, do not edit!!
|
||||
const char PAGE_settings_time[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta name="viewport" content="width=500"><meta
|
||||
charset="utf-8"><title>Time Settings</title><script>
|
||||
var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings")}function B(){window.open("/settings","_self")}function S(){BTa(),GetV(),Cs(),FC()}function gId(t){return d.getElementById(t)}function Cs(){gId("cac").style.display="none",gId("coc").style.display="block",gId("ccc").style.display="none",gId("ca").selected&&(gId("cac").style.display="block"),gId("cc").selected&&(gId("coc").style.display="none",gId("ccc").style.display="block"),gId("cn").selected&&(gId("coc").style.display="none")}function BTa(){var t="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Macro</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";for(i=0;i<8;i++)for(t+='<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>',j=1;j<8;j++)t+='<td><input id="W'+i+j+'" type="checkbox"></td>';gId("TMT").innerHTML=t}function FC(){for(j=0;j<8;j++)for(i=0;i<8;i++)gId("W"+i+j).checked=gId("W"+i).value>>j&1}function Wd(){for(a=[0,0,0,0,0,0,0,0],i=0;i<8;i++){for(m=1,j=0;j<8;j++)a[i]+=gId("W"+i+j).checked*m,m*=2;gId("W"+i).value=a[i]}}function GetV() {
|
||||
%CSS%%SCSS%</head><body onload="S()"><form
|
||||
id="form_s" name="Sf" method="post" onsubmit="Wd()"><div class="helpB"><button
|
||||
type="button" onclick="H()">?</button></div><button type="button" onclick="B()">
|
||||
Back</button><button type="submit">Save</button><hr><h2>Time setup</h2>
|
||||
Get time from NTP server: <input type="checkbox" name="NT"><br><input name="NS"
|
||||
maxlength="32"><br>Use 24h format: <input type="checkbox" name="CF"><br>
|
||||
Time zone: <select name="TZ"><option value="0" selected="selected">GMT(UTC)
|
||||
</option><option value="1">GMT/BST</option><option value="2">CET/CEST</option>
|
||||
<option value="3">EET/EEST</option><option value="4">US-EST/EDT</option><option
|
||||
value="5">US-CST/CDT</option><option value="6">US-MST/MDT</option><option
|
||||
value="7">US-AZ</option><option value="8">US-PST/PDT</option><option value="9">
|
||||
CST(AWST)</option><option value="10">JST(KST)</option><option value="11">
|
||||
AEST/AEDT</option><option value="12">NZST/NZDT</option><option value="13">
|
||||
North Korea</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>.<h3>Clock</h3>
|
||||
Clock Overlay: <select name="OL" onchange="Cs()"><option value="0" id="cn"
|
||||
selected="selected">None</option><option value="1" id="ca">Analog Clock</option>
|
||||
<option value="2">Single Digit Clock</option><option value="3" id="cc">
|
||||
Cronixie Clock</option></select><br><div id="coc">First LED: <input name="O1"
|
||||
type="number" min="0" max="255" required> Last LED: <input name="O2"
|
||||
type="number" min="0" max="255" required><br><div id="cac">12h LED: <input
|
||||
name="OM" type="number" min="0" max="255" required><br>Show 5min marks: <input
|
||||
type="checkbox" name="O5"><br></div>Seconds (as trail): <input type="checkbox"
|
||||
name="OS"><br></div><div id="ccc">Cronixie Display: <input name="CX"
|
||||
maxlength="6"><br>Cronixie Backlight: <input type="checkbox" name="CB"><br>
|
||||
</div>Countdown Mode: <input type="checkbox" name="CE"><br>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 short press macro: Macro:
|
||||
<input name="MP" type="number" min="0" max="16" required><br>Long Press: <input
|
||||
name="ML" type="number" min="0" max="16" required> Double press: <input
|
||||
name="MD" type="number" min="0" max="16" required><br>Countdown-Over Macro:
|
||||
<input name="MC" type="number" min="0" max="16" required><br>
|
||||
Timed-Light-Over Macro: <input name="MN" type="number" min="0" max="16"
|
||||
required><br>Time-Controlled Macros:<br><div style="display:inline-block"><table
|
||||
id="TMT"></table></div><hr><button type="button" onclick="B()">Back</button>
|
||||
<button type="submit">Save</button></form></body></html>)=====";
|
||||
|
||||
|
||||
//security settings and about
|
||||
const char PAGE_settings_sec[] PROGMEM = R"=====(<!DOCTYPE html>
|
||||
<html><head><meta name="viewport" content="width=500"><meta charset="utf-8">
|
||||
<title>Misc Settings</title>
|
||||
<script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#security-settings");}function B(){window.open("/settings","_self");}function U(){window.open("/update","_self");}function GetV(){var d=document;
|
||||
%CSS%%SCSS%</head>
|
||||
<body onload="GetV()">
|
||||
<form id="form_s" name="Sf" method="post">
|
||||
<div class="helpB"><button type="button" onclick="H()">?</button></div>
|
||||
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button><hr>
|
||||
<h2>Security & Update setup</h2>
|
||||
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
|
||||
Passphrase: <input type="password" name="OP" maxlength="32"><br>
|
||||
To enable OTA, for security reasons you need to also enter the correct password!<br>
|
||||
The password should be changed when OTA is enabled.<br>
|
||||
<b>Disable OTA when not in use, otherwise an attacker can reflash device software!</b><br>
|
||||
<i>Settings on this page are only changable if OTA lock is disabled!</i><br>
|
||||
Deny access to WiFi settings if locked: <input type="checkbox" name="OW"><br><br>
|
||||
Factory reset: <input type="checkbox" name="RS"><br>
|
||||
// Autogenerated from wled00/data/settings_sec.htm, do not edit!!
|
||||
const char PAGE_settings_sec[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta name="viewport" content="width=500"><meta
|
||||
charset="utf-8"><title>Misc Settings</title><script>
|
||||
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#security-settings")}function B(){window.open("/settings","_self")}function U(){window.open("/update","_self")}function GetV() {var d=document;
|
||||
%CSS%%SCSS%</head><body onload="GetV()">
|
||||
<form id="form_s" name="Sf" method="post"><div class="helpB"><button
|
||||
type="button" onclick="H()">?</button></div><button type="button" onclick="B()">
|
||||
Back</button><button type="submit">Save & Reboot</button><hr><h2>
|
||||
Security & Update setup</h2>Lock wireless (OTA) software update: <input
|
||||
type="checkbox" name="NO"><br>Passphrase: <input type="password" name="OP"
|
||||
maxlength="32"><br>
|
||||
To enable OTA, for security reasons you need to also enter the correct password!
|
||||
<br>The password should be changed when OTA is enabled.<br><b>
|
||||
Disable OTA when not in use, otherwise an attacker can reflash device software!
|
||||
</b><br><i>Settings on this page are only changable if OTA lock is disabled!</i>
|
||||
<br>Deny access to WiFi settings if locked: <input type="checkbox" name="OW">
|
||||
<br><br>Factory reset: <input type="checkbox" name="RS"><br>
|
||||
All EEPROM content (settings) will be erased.<br><br>
|
||||
HTTP traffic is unencrypted. An attacker in the same network can intercept form data!
|
||||
<h3>Software Update</h3>
|
||||
<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/wiki/Contributors-&-About" target="_blank">Contributors, dependencies and special thanks</a><br>
|
||||
<h3>Software Update</h3><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.2<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-2020 Christian Schwinne <br>
|
||||
<i>Licensed under the MIT license</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>
|
||||
</body>
|
||||
</html>)=====";
|
||||
(c) 2016-2019 Christian Schwinne<br><i>Licensed under the MIT license</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></body></html>)=====";
|
||||
|
||||
|
3529
wled00/html_ui.h
148
wled00/ir.cpp
@ -15,6 +15,8 @@ decode_results results;
|
||||
|
||||
unsigned long irCheckedTime = 0;
|
||||
uint32_t lastValidCode = 0;
|
||||
byte lastRepeatableAction = ACTION_NONE;
|
||||
uint8_t lastRepeatableValue = 0;
|
||||
uint16_t irTimesRepeated = 0;
|
||||
uint8_t lastIR6ColourIdx = 0;
|
||||
|
||||
@ -36,7 +38,7 @@ bool decodeIRCustom(uint32_t code)
|
||||
}
|
||||
|
||||
|
||||
//relatively change brightness, minumum A=5
|
||||
|
||||
void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte higherBoundary)
|
||||
{
|
||||
int16_t new_val = (int16_t) *property + amount;
|
||||
@ -45,6 +47,16 @@ void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte high
|
||||
*property = (byte)constrain(new_val,0.1,255.1);
|
||||
}
|
||||
|
||||
void changeBrightness(int8_t amount)
|
||||
{
|
||||
int16_t new_val = bri + amount;
|
||||
if (new_val < 5) new_val = 5; //minimum brightness A=5
|
||||
bri = (byte)constrain(new_val,0.1,255.1);
|
||||
if(amount > 0) lastRepeatableAction = ACTION_BRIGHT_UP;
|
||||
if(amount < 0) lastRepeatableAction = ACTION_BRIGHT_DOWN;
|
||||
lastRepeatableValue = amount;
|
||||
}
|
||||
|
||||
void changeEffectSpeed(int8_t amount)
|
||||
{
|
||||
if (effectCurrent != 0) {
|
||||
@ -65,6 +77,10 @@ void changeEffectSpeed(int8_t amount)
|
||||
col[1] = fastled_col.green;
|
||||
col[2] = fastled_col.blue;
|
||||
}
|
||||
|
||||
if(amount > 0) lastRepeatableAction = ACTION_SPEED_UP;
|
||||
if(amount < 0) lastRepeatableAction = ACTION_SPEED_DOWN;
|
||||
lastRepeatableValue = amount;
|
||||
}
|
||||
|
||||
void changeEffectIntensity(int8_t amount)
|
||||
@ -85,6 +101,10 @@ void changeEffectIntensity(int8_t amount)
|
||||
col[1] = fastled_col.green;
|
||||
col[2] = fastled_col.blue;
|
||||
}
|
||||
|
||||
if(amount > 0) lastRepeatableAction = ACTION_INTENSITY_UP;
|
||||
if(amount < 0) lastRepeatableAction = ACTION_INTENSITY_DOWN;
|
||||
lastRepeatableValue = amount;
|
||||
}
|
||||
|
||||
void decodeIR(uint32_t code)
|
||||
@ -92,14 +112,61 @@ void decodeIR(uint32_t code)
|
||||
if (code == 0xFFFFFFFF) //repeated code, continue brightness up/down
|
||||
{
|
||||
irTimesRepeated++;
|
||||
if (lastValidCode == IR24_BRIGHTER || lastValidCode == IR40_BPLUS )
|
||||
applyRepeatActions();
|
||||
return;
|
||||
}
|
||||
lastValidCode = 0; irTimesRepeated = 0;
|
||||
if (decodeIRCustom(code)) return;
|
||||
if (code > 0xFFFFFF) return; //invalid code
|
||||
else if (code > 0xF70000 && code < 0xF80000) decodeIR24(code); //is in 24-key remote range
|
||||
else if (code > 0xFF0000) {
|
||||
switch (irEnabled) {
|
||||
case 1: decodeIR24OLD(code); break; // white 24-key remote (old) - it sends 0xFF0000 values
|
||||
case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys
|
||||
case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys
|
||||
case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys
|
||||
case 5: decodeIR21(code); break; // white 21-key remote
|
||||
case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness,
|
||||
// "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE"
|
||||
// sets bright plain white
|
||||
case 7: decodeIR9(code); break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
if (nightlightActive && bri == 0) nightlightActive = false;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); //for notifier, IR is considered a button input
|
||||
//code <= 0xF70000 also invalid
|
||||
}
|
||||
|
||||
void applyRepeatActions(){
|
||||
|
||||
if (lastRepeatableAction == ACTION_BRIGHT_UP)
|
||||
{
|
||||
relativeChange(&bri, 10); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
changeBrightness(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
else if (lastValidCode == IR24_DARKER || lastValidCode == IR40_BMINUS )
|
||||
else if (lastRepeatableAction == ACTION_BRIGHT_DOWN )
|
||||
{
|
||||
relativeChange(&bri, -10, 5); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
changeBrightness(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
|
||||
if (lastRepeatableAction == ACTION_SPEED_UP)
|
||||
{
|
||||
changeEffectSpeed(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
else if (lastRepeatableAction == ACTION_SPEED_DOWN )
|
||||
{
|
||||
changeEffectSpeed(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
|
||||
if (lastRepeatableAction == ACTION_INTENSITY_UP)
|
||||
{
|
||||
changeEffectIntensity(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
else if (lastRepeatableAction == ACTION_INTENSITY_DOWN )
|
||||
{
|
||||
changeEffectIntensity(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
|
||||
if (lastValidCode == IR40_WPLUS)
|
||||
{
|
||||
relativeChangeWhite(10); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
@ -114,37 +181,14 @@ void decodeIR(uint32_t code)
|
||||
nightlightStartTime = millis();
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
|
||||
}
|
||||
return;
|
||||
}
|
||||
lastValidCode = 0; irTimesRepeated = 0;
|
||||
|
||||
if (decodeIRCustom(code)) return;
|
||||
if (code > 0xFFFFFF) return; //invalid code
|
||||
else if (code > 0xF70000 && code < 0xF80000) decodeIR24(code); //is in 24-key remote range
|
||||
else if (code > 0xFF0000) {
|
||||
switch (irEnabled) {
|
||||
case 1: decodeIR24OLD(code); break; // white 24-key remote (old) - it sends 0xFF0000 values
|
||||
case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys
|
||||
case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys
|
||||
case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys
|
||||
case 5: decodeIR21(code); break; // white 21-key remote
|
||||
case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness,
|
||||
// "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE"
|
||||
// sets bright plain white
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
if (nightlightActive && bri == 0) nightlightActive = false;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_BUTTON); //for notifier, IR is considered a button input
|
||||
//code <= 0xF70000 also invalid
|
||||
}
|
||||
|
||||
|
||||
void decodeIR24(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR24_BRIGHTER : relativeChange(&bri, 10); break;
|
||||
case IR24_DARKER : relativeChange(&bri, -10, 5); break;
|
||||
case IR24_BRIGHTER : changeBrightness(10); break;
|
||||
case IR24_DARKER : changeBrightness(-10); break;
|
||||
case IR24_OFF : briLast = bri; bri = 0; break;
|
||||
case IR24_ON : bri = briLast; break;
|
||||
case IR24_RED : colorFromUint32(COLOR_RED); break;
|
||||
@ -175,8 +219,8 @@ void decodeIR24(uint32_t code)
|
||||
void decodeIR24OLD(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR24_OLD_BRIGHTER : relativeChange(&bri, 10); break;
|
||||
case IR24_OLD_DARKER : relativeChange(&bri, -10, 5); break;
|
||||
case IR24_OLD_BRIGHTER : changeBrightness(10); break;
|
||||
case IR24_OLD_DARKER : changeBrightness(-10); break;
|
||||
case IR24_OLD_OFF : briLast = bri; bri = 0; break;
|
||||
case IR24_OLD_ON : bri = briLast; break;
|
||||
case IR24_OLD_RED : colorFromUint32(COLOR_RED); break;
|
||||
@ -208,8 +252,8 @@ void decodeIR24OLD(uint32_t code)
|
||||
void decodeIR24CT(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR24_CT_BRIGHTER : relativeChange(&bri, 10); break;
|
||||
case IR24_CT_DARKER : relativeChange(&bri, -10, 5); break;
|
||||
case IR24_CT_BRIGHTER : changeBrightness(10); break;
|
||||
case IR24_CT_DARKER : changeBrightness(-10); break;
|
||||
case IR24_CT_OFF : briLast = bri; bri = 0; break;
|
||||
case IR24_CT_ON : bri = briLast; break;
|
||||
case IR24_CT_RED : colorFromUint32(COLOR_RED); break;
|
||||
@ -243,8 +287,8 @@ void decodeIR24CT(uint32_t code)
|
||||
void decodeIR40(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR40_BPLUS : relativeChange(&bri, 10); break;
|
||||
case IR40_BMINUS : relativeChange(&bri, -10, 5); break;
|
||||
case IR40_BPLUS : changeBrightness(10); break;
|
||||
case IR40_BMINUS : changeBrightness(-10); break;
|
||||
case IR40_OFF : briLast = bri; bri = 0; break;
|
||||
case IR40_ON : bri = briLast; break;
|
||||
case IR40_RED : colorFromUint24(COLOR_RED); break;
|
||||
@ -300,8 +344,8 @@ void decodeIR40(uint32_t code)
|
||||
void decodeIR44(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR44_BPLUS : relativeChange(&bri, 10); break;
|
||||
case IR44_BMINUS : relativeChange(&bri, -10, 5); break;
|
||||
case IR44_BPLUS : changeBrightness(10); break;
|
||||
case IR44_BMINUS : changeBrightness(-10); break;
|
||||
case IR44_OFF : briLast = bri; bri = 0; break;
|
||||
case IR44_ON : bri = briLast; break;
|
||||
case IR44_RED : colorFromUint24(COLOR_RED); break;
|
||||
@ -363,8 +407,8 @@ void decodeIR44(uint32_t code)
|
||||
void decodeIR21(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR21_BRIGHTER: relativeChange(&bri, 10); break;
|
||||
case IR21_DARKER: relativeChange(&bri, -10, 5); break;
|
||||
case IR21_BRIGHTER: changeBrightness(10); break;
|
||||
case IR21_DARKER: changeBrightness(-10); break;
|
||||
case IR21_OFF: briLast = bri; bri = 0; break;
|
||||
case IR21_ON: bri = briLast; break;
|
||||
case IR21_RED: colorFromUint32(COLOR_RED); break;
|
||||
@ -392,9 +436,9 @@ void decodeIR21(uint32_t code)
|
||||
void decodeIR6(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR6_POWER: toggleOnOff(); break;
|
||||
case IR6_CHANNEL_UP: relativeChange(&bri, 10); break;
|
||||
case IR6_CHANNEL_DOWN: relativeChange(&bri, -10, 5); break;
|
||||
case IR6_POWER: toggleOnOff(); break;
|
||||
case IR6_CHANNEL_UP: changeBrightness(10); break;
|
||||
case IR6_CHANNEL_DOWN: changeBrightness(-10); break;
|
||||
case IR6_VOLUME_UP: relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break; // next effect
|
||||
case IR6_VOLUME_DOWN: // next palette
|
||||
relativeChange(&effectPalette, 1, 0, strip.getPaletteCount() -1);
|
||||
@ -421,6 +465,24 @@ void decodeIR6(uint32_t code)
|
||||
lastValidCode = code;
|
||||
}
|
||||
|
||||
void decodeIR9(uint32_t code)
|
||||
{
|
||||
switch (code) {
|
||||
case IR9_POWER : toggleOnOff(); break;
|
||||
case IR9_A : if (!applyPreset(1)) effectCurrent = FX_MODE_COLORTWINKLE; break;
|
||||
case IR9_B : if (!applyPreset(2)) effectCurrent = FX_MODE_RAINBOW_CYCLE; break;
|
||||
case IR9_C : if (!applyPreset(3)) effectCurrent = FX_MODE_BREATH; break;
|
||||
case IR9_UP : changeBrightness(16); break;
|
||||
case IR9_DOWN : changeBrightness(-16); break;
|
||||
//case IR9_UP : changeEffectIntensity(16); break;
|
||||
//case IR9_DOWN : changeEffectIntensity(-16); break;
|
||||
case IR9_LEFT : changeEffectSpeed(-16); break;
|
||||
case IR9_RIGHT : changeEffectSpeed(16); break;
|
||||
case IR9_SELECT : relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break;
|
||||
default: return;
|
||||
}
|
||||
lastValidCode = code;
|
||||
}
|
||||
|
||||
void initIR()
|
||||
{
|
||||
|
@ -13,6 +13,15 @@
|
||||
#define IR6_VOLUME_DOWN 0xFF2FD0
|
||||
#define IR6_MUTE 0xFFAF50
|
||||
|
||||
#define IR9_POWER 0xFF629D
|
||||
#define IR9_A 0xFF22DD
|
||||
#define IR9_B 0xFF02FD
|
||||
#define IR9_C 0xFFC23D
|
||||
#define IR9_LEFT 0xFF30CF
|
||||
#define IR9_RIGHT 0xFF7A85
|
||||
#define IR9_UP 0xFF9867
|
||||
#define IR9_DOWN 0xFF38C7
|
||||
#define IR9_SELECT 0xFF18E7
|
||||
|
||||
//Infrared codes for 24-key remote from http://woodsgood.ca/projects/2015/02/13/rgb-led-strip-controllers-ir-codes/
|
||||
#define IR24_BRIGHTER 0xF700FF
|
||||
@ -229,3 +238,12 @@
|
||||
#define COLOR2_NEUTRALWHITE 0xFF000000
|
||||
#define COLOR2_COLDWHITE 0xFF7F7F7F
|
||||
#define COLOR2_COLDWHITE2 0xFFFFFFFF
|
||||
|
||||
#define ACTION_NONE 0
|
||||
#define ACTION_BRIGHT_UP 1
|
||||
#define ACTION_BRIGHT_DOWN 2
|
||||
#define ACTION_SPEED_UP 3
|
||||
#define ACTION_SPEED_DOWN 4
|
||||
#define ACTION_INTENSITY_UP 5
|
||||
#define ACTION_INTENSITY_DOWN 6
|
||||
#define ACTION_POWER 7
|
110
wled00/json.cpp
@ -59,6 +59,7 @@ void deserializeSegment(JsonObject elem, byte it)
|
||||
//if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
|
||||
seg.setOption(SEG_OPTION_SELECTED, elem["sel"] | seg.getOption(SEG_OPTION_SELECTED));
|
||||
seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
|
||||
seg.setOption(SEG_OPTION_MIRROR , elem["mi"] | seg.getOption(SEG_OPTION_MIRROR ));
|
||||
|
||||
//temporary, strip object gets updated via colorUpdated()
|
||||
if (id == strip.getMainSegmentId()) {
|
||||
@ -73,6 +74,53 @@ void deserializeSegment(JsonObject elem, byte it)
|
||||
seg.intensity = elem["ix"] | seg.intensity;
|
||||
seg.palette = elem["pal"] | seg.palette;
|
||||
}
|
||||
|
||||
JsonArray iarr = elem["i"]; //set individual LEDs
|
||||
if (!iarr.isNull()) {
|
||||
strip.setPixelSegment(id);
|
||||
|
||||
//freeze and init to black
|
||||
if (!seg.getOption(SEG_OPTION_FREEZE)) {
|
||||
seg.setOption(SEG_OPTION_FREEZE, true);
|
||||
strip.fill(0);
|
||||
}
|
||||
|
||||
uint16_t start = 0, stop = 0;
|
||||
byte set = 0; //0 nothing set, 1 start set, 2 range set
|
||||
|
||||
for (uint16_t i = 0; i < iarr.size(); i++) {
|
||||
if(iarr[i].is<JsonInteger>()) {
|
||||
if (!set) {
|
||||
start = iarr[i];
|
||||
set = 1;
|
||||
} else {
|
||||
stop = iarr[i];
|
||||
set = 2;
|
||||
}
|
||||
} else {
|
||||
JsonArray icol = iarr[i];
|
||||
if (icol.isNull()) break;
|
||||
|
||||
byte sz = icol.size();
|
||||
if (sz == 0 && sz > 4) break;
|
||||
|
||||
int rgbw[] = {0,0,0,0};
|
||||
byte cp = copyArray(icol, rgbw);
|
||||
|
||||
if (set < 2) stop = start + 1;
|
||||
for (uint16_t i = start; i < stop; i++) {
|
||||
strip.setPixelColor(i, rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
|
||||
}
|
||||
if (!set) start++;
|
||||
set = 0;
|
||||
}
|
||||
}
|
||||
strip.setPixelSegment(255);
|
||||
strip.trigger();
|
||||
} else { //return to regular effect
|
||||
seg.setOption(SEG_OPTION_FREEZE, false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,16 +158,13 @@ bool deserializeState(JsonObject root)
|
||||
presetCycleMin = ccnf["min"] | presetCycleMin;
|
||||
presetCycleMax = ccnf["max"] | presetCycleMax;
|
||||
tr = ccnf["time"] | -1;
|
||||
if (tr >= 2)
|
||||
{
|
||||
presetCycleTime = tr;
|
||||
presetCycleTime *= 100;
|
||||
}
|
||||
if (tr >= 2) presetCycleTime = tr;
|
||||
|
||||
JsonObject nl = root["nl"];
|
||||
nightlightActive = nl["on"] | nightlightActive;
|
||||
nightlightDelayMins = nl["dur"] | nightlightDelayMins;
|
||||
nightlightFade = nl["fade"] | nightlightFade;
|
||||
nightlightMode = nl["fade"] | nightlightMode; //deprecated
|
||||
nightlightMode = nl["mode"] | nightlightMode;
|
||||
nightlightTargetBri = nl["tbri"] | nightlightTargetBri;
|
||||
|
||||
JsonObject udpn = root["udpn"];
|
||||
@ -172,6 +217,8 @@ bool deserializeState(JsonObject root)
|
||||
}
|
||||
}
|
||||
|
||||
usermods.readFromJsonState(root);
|
||||
|
||||
colorUpdated(noNotification ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
||||
|
||||
//write presets to flash directly?
|
||||
@ -216,12 +263,13 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id)
|
||||
}
|
||||
}
|
||||
|
||||
root["fx"] = seg.mode;
|
||||
root["sx"] = seg.speed;
|
||||
root["ix"] = seg.intensity;
|
||||
root["fx"] = seg.mode;
|
||||
root["sx"] = seg.speed;
|
||||
root["ix"] = seg.intensity;
|
||||
root["pal"] = seg.palette;
|
||||
root["sel"] = seg.isSelected();
|
||||
root["rev"] = seg.getOption(SEG_OPTION_REVERSED);
|
||||
root["mi"] = seg.getOption(SEG_OPTION_MIRROR);
|
||||
}
|
||||
|
||||
|
||||
@ -237,16 +285,19 @@ void serializeState(JsonObject root)
|
||||
root["pss"] = savedPresets;
|
||||
root["pl"] = (presetCyclingEnabled) ? 0: -1;
|
||||
|
||||
//temporary for preser cycle
|
||||
usermods.addToJsonState(root);
|
||||
|
||||
//temporary for preset cycle
|
||||
JsonObject ccnf = root.createNestedObject("ccnf");
|
||||
ccnf["min"] = presetCycleMin;
|
||||
ccnf["max"] = presetCycleMax;
|
||||
ccnf["time"] = presetCycleTime/100;
|
||||
ccnf["time"] = presetCycleTime;
|
||||
|
||||
JsonObject nl = root.createNestedObject("nl");
|
||||
nl["on"] = nightlightActive;
|
||||
nl["dur"] = nightlightDelayMins;
|
||||
nl["fade"] = nightlightFade;
|
||||
nl["fade"] = (nightlightMode > NL_MODE_SET); //deprecated
|
||||
nl["mode"] = nightlightMode;
|
||||
nl["tbri"] = nightlightTargetBri;
|
||||
|
||||
JsonObject udpn = root.createNestedObject("udpn");
|
||||
@ -319,8 +370,9 @@ void serializeInfo(JsonObject root)
|
||||
case REALTIME_MODE_UDP: root["lm"] = "UDP"; break;
|
||||
case REALTIME_MODE_HYPERION: root["lm"] = "Hyperion"; break;
|
||||
case REALTIME_MODE_E131: root["lm"] = "E1.31"; break;
|
||||
case REALTIME_MODE_ADALIGHT: root["lm"] = F("USB Adalight");
|
||||
case REALTIME_MODE_ADALIGHT: root["lm"] = F("USB Adalight/TPM2"); break;
|
||||
case REALTIME_MODE_ARTNET: root["lm"] = "Art-Net"; break;
|
||||
case REALTIME_MODE_TPM2NET: root["lm"] = F("tpm2.net"); break;
|
||||
}
|
||||
|
||||
if (realtimeIP[0] == 0)
|
||||
@ -330,6 +382,12 @@ void serializeInfo(JsonObject root)
|
||||
root["lip"] = realtimeIP.toString();
|
||||
}
|
||||
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
root["ws"] = ws.count();
|
||||
#else
|
||||
root["ws"] = -1;
|
||||
#endif
|
||||
|
||||
root["fxcount"] = strip.getModeCount();
|
||||
root["palcount"] = strip.getPaletteCount();
|
||||
|
||||
@ -365,6 +423,8 @@ void serializeInfo(JsonObject root)
|
||||
|
||||
root["freeheap"] = ESP.getFreeHeap();
|
||||
root["uptime"] = millis()/1000 + rolloverMillis*4294967;
|
||||
|
||||
usermods.addToJsonInfo(root);
|
||||
|
||||
byte os = 0;
|
||||
#ifdef WLED_DEBUG
|
||||
@ -449,21 +509,37 @@ void serveJson(AsyncWebServerRequest* request)
|
||||
|
||||
#define MAX_LIVE_LEDS 180
|
||||
|
||||
void serveLiveLeds(AsyncWebServerRequest* request)
|
||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
|
||||
{
|
||||
AsyncWebSocketClient * wsc;
|
||||
if (!request) { //not HTTP, use Websockets
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
wsc = ws.client(wsClient);
|
||||
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t used = ledCount;
|
||||
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
|
||||
char buffer[2000] = "{\"leds\":[";
|
||||
olen = 9;
|
||||
obuf = buffer;
|
||||
olen = 9;
|
||||
|
||||
for (uint16_t i= 0; i < used; i += n)
|
||||
{
|
||||
olen += sprintf(buffer + olen, "\"%06X\",", strip.getPixelColor(i));
|
||||
olen += sprintf(obuf + olen, "\"%06X\",", strip.getPixelColor(i));
|
||||
}
|
||||
olen -= 1;
|
||||
oappend("],\"n\":");
|
||||
oappendi(n);
|
||||
oappend("}");
|
||||
request->send(200, "application/json", buffer);
|
||||
if (request) {
|
||||
request->send(200, "application/json", buffer);
|
||||
}
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
else {
|
||||
wsc->text(obuf, olen);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
/*
|
||||
* LED methods
|
||||
*/
|
||||
|
||||
void setValuesFromMainSeg()
|
||||
{
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
@ -114,7 +113,7 @@ void colorUpdated(int callMode)
|
||||
|
||||
if (!colChanged) return; //following code is for e.g. initiating transitions
|
||||
|
||||
if (callMode != NOTIFIER_CALL_MODE_NO_NOTIFY && nightlightActive && nightlightFade)
|
||||
if (callMode != NOTIFIER_CALL_MODE_NO_NOTIFY && nightlightActive && (nightlightMode == NL_MODE_FADE || nightlightMode == NL_MODE_COLORFADE))
|
||||
{
|
||||
briNlT = bri;
|
||||
nightlightDelayMs -= (millis() - nightlightStartTime);
|
||||
@ -133,6 +132,9 @@ void colorUpdated(int callMode)
|
||||
|
||||
briIT = bri;
|
||||
if (bri > 0) briLast = bri;
|
||||
|
||||
//deactivate nightlight if target brightness is reached
|
||||
if (bri == nightlightTargetBri && callMode != NOTIFIER_CALL_MODE_NO_NOTIFY) nightlightActive = false;
|
||||
|
||||
if (fadeTransition)
|
||||
{
|
||||
@ -164,6 +166,7 @@ void colorUpdated(int callMode)
|
||||
|
||||
void updateInterfaces(uint8_t callMode)
|
||||
{
|
||||
sendDataWs();
|
||||
#ifndef WLED_DISABLE_ALEXA
|
||||
if (espalexaDevice != nullptr && callMode != NOTIFIER_CALL_MODE_ALEXA) {
|
||||
espalexaDevice->setValue(bri);
|
||||
@ -223,40 +226,84 @@ void handleNightlight()
|
||||
nightlightActiveOld = true;
|
||||
briNlT = bri;
|
||||
for (byte i=0; i<4; i++) colNlT[i] = col[i]; // remember starting color
|
||||
if (nightlightMode == NL_MODE_SUN)
|
||||
{
|
||||
//save current
|
||||
colNlT[0] = effectCurrent;
|
||||
colNlT[1] = effectSpeed;
|
||||
colNlT[2] = effectPalette;
|
||||
|
||||
effectCurrent = FX_MODE_SUNRISE;
|
||||
effectSpeed = nightlightDelayMins;
|
||||
effectPalette = 0;
|
||||
if (effectSpeed > 60) effectSpeed = 60; //currently limited to 60 minutes
|
||||
if (bri) effectSpeed += 60; //sunset if currently on
|
||||
briNlT = !bri; //true == sunrise, false == sunset
|
||||
if (!bri) bri = briLast;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY);
|
||||
}
|
||||
}
|
||||
float nper = (millis() - nightlightStartTime)/((float)nightlightDelayMs);
|
||||
if (nightlightFade)
|
||||
if (nightlightMode == NL_MODE_FADE || nightlightMode == NL_MODE_COLORFADE)
|
||||
{
|
||||
bri = briNlT + ((nightlightTargetBri - briNlT)*nper);
|
||||
if (nightlightColorFade) // color fading only is enabled with "NF=2"
|
||||
if (nightlightMode == NL_MODE_COLORFADE) // color fading only is enabled with "NF=2"
|
||||
{
|
||||
for (byte i=0; i<4; i++) col[i] = colNlT[i]+ ((colSec[i] - colNlT[i])*nper); // fading from actual color to secondary color
|
||||
}
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY);
|
||||
}
|
||||
if (nper >= 1)
|
||||
if (nper >= 1) //nightlight duration over
|
||||
{
|
||||
nightlightActive = false;
|
||||
if (!nightlightFade)
|
||||
if (nightlightMode == NL_MODE_SET)
|
||||
{
|
||||
bri = nightlightTargetBri;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY);
|
||||
}
|
||||
updateBlynk();
|
||||
if (bri == 0) briLast = briNlT;
|
||||
if (nightlightMode == NL_MODE_SUN)
|
||||
{
|
||||
if (!briNlT) { //turn off if sunset
|
||||
effectCurrent = colNlT[0];
|
||||
effectSpeed = colNlT[1];
|
||||
effectPalette = colNlT[2];
|
||||
toggleOnOff();
|
||||
setLedsStandard();
|
||||
}
|
||||
}
|
||||
updateBlynk();
|
||||
if (macroNl > 0)
|
||||
applyMacro(macroNl);
|
||||
nightlightActiveOld = false;
|
||||
}
|
||||
} else if (nightlightActiveOld) //early de-init
|
||||
{
|
||||
if (nightlightMode == NL_MODE_SUN) { //restore previous effect
|
||||
effectCurrent = colNlT[0];
|
||||
effectSpeed = colNlT[1];
|
||||
effectPalette = colNlT[2];
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY);
|
||||
}
|
||||
nightlightActiveOld = false;
|
||||
}
|
||||
|
||||
//also handle preset cycle here
|
||||
if (presetCyclingEnabled && (millis() - presetCycledTime > presetCycleTime))
|
||||
if (presetCyclingEnabled && (millis() - presetCycledTime > (100*presetCycleTime)))
|
||||
{
|
||||
applyPreset(presetCycCurr,presetApplyBri);
|
||||
presetCycCurr++; if (presetCycCurr > presetCycleMax) presetCycCurr = presetCycleMin;
|
||||
if (presetCycCurr > 25) presetCycCurr = 1;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_PRESET_CYCLE);
|
||||
presetCycledTime = millis();
|
||||
if (bri == 0 || nightlightActive) return;
|
||||
|
||||
if (presetCycCurr < presetCycleMin || presetCycCurr > presetCycleMax) presetCycCurr = presetCycleMin;
|
||||
applyPreset(presetCycCurr,presetApplyBri);
|
||||
presetCycCurr++;
|
||||
if (presetCycCurr > 16) presetCycCurr = 1;
|
||||
colorUpdated(NOTIFIER_CALL_MODE_PRESET_CYCLE);
|
||||
}
|
||||
}
|
||||
|
||||
//utility for FastLED to use our custom timer
|
||||
uint32_t get_millisecond_timer()
|
||||
{
|
||||
return strip.now;
|
||||
}
|
||||
|
@ -56,6 +56,12 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties
|
||||
|
||||
DEBUG_PRINT("MQTT msg: ");
|
||||
DEBUG_PRINTLN(topic);
|
||||
|
||||
// paranoia check to avoid npe if no payload
|
||||
if (payload==nullptr) {
|
||||
DEBUG_PRINTLN("no payload -> leave");
|
||||
return;
|
||||
}
|
||||
DEBUG_PRINTLN(payload);
|
||||
|
||||
//no need to check the topic because we only get topics we are subscribed to
|
||||
@ -76,7 +82,7 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties
|
||||
void publishMqtt()
|
||||
{
|
||||
doPublishMqtt = false;
|
||||
if (mqtt == nullptr || !mqtt->connected()) return;
|
||||
if (!WLED_MQTT_CONNECTED) return;
|
||||
DEBUG_PRINTLN("Publish MQTT");
|
||||
|
||||
char s[10];
|
||||
|
@ -142,24 +142,24 @@ bool checkNTPResponse()
|
||||
void updateLocalTime()
|
||||
{
|
||||
unsigned long tmc = now()+ utcOffsetSecs;
|
||||
local = timezones[currentTimezone]->toLocal(tmc);
|
||||
localTime = timezones[currentTimezone]->toLocal(tmc);
|
||||
}
|
||||
|
||||
void getTimeString(char* out)
|
||||
{
|
||||
updateLocalTime();
|
||||
byte hr = hour(local);
|
||||
byte hr = hour(localTime);
|
||||
if (useAMPM)
|
||||
{
|
||||
if (hr > 11) hr -= 12;
|
||||
if (hr == 0) hr = 12;
|
||||
}
|
||||
sprintf(out,"%i-%i-%i, %i:%s%i:%s%i",year(local), month(local), day(local),
|
||||
hr,(minute(local)<10)?"0":"",minute(local),
|
||||
(second(local)<10)?"0":"",second(local));
|
||||
sprintf(out,"%i-%i-%i, %i:%s%i:%s%i",year(localTime), month(localTime), day(localTime),
|
||||
hr,(minute(localTime)<10)?"0":"",minute(localTime),
|
||||
(second(localTime)<10)?"0":"",second(localTime));
|
||||
if (useAMPM)
|
||||
{
|
||||
strcat(out,(hour(local) > 11)? " PM":" AM");
|
||||
strcat(out,(hour(localTime) > 11)? " PM":" AM");
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,9 +173,9 @@ void setCountdown()
|
||||
bool checkCountdown()
|
||||
{
|
||||
unsigned long n = now();
|
||||
if (countdownMode) local = countdownTime - n + utcOffsetSecs;
|
||||
if (countdownMode) localTime = countdownTime - n + utcOffsetSecs;
|
||||
if (n > countdownTime) {
|
||||
if (countdownMode) local = n - countdownTime + utcOffsetSecs;
|
||||
if (countdownMode) localTime = n - countdownTime + utcOffsetSecs;
|
||||
if (!countdownOverTriggered)
|
||||
{
|
||||
if (macroCountdown != 0) applyMacro(macroCountdown);
|
||||
@ -188,21 +188,21 @@ bool checkCountdown()
|
||||
|
||||
byte weekdayMondayFirst()
|
||||
{
|
||||
byte wd = weekday(local) -1;
|
||||
byte wd = weekday(localTime) -1;
|
||||
if (wd == 0) wd = 7;
|
||||
return wd;
|
||||
}
|
||||
|
||||
void checkTimers()
|
||||
{
|
||||
if (lastTimerMinute != minute(local)) //only check once a new minute begins
|
||||
if (lastTimerMinute != minute(localTime)) //only check once a new minute begins
|
||||
{
|
||||
lastTimerMinute = minute(local);
|
||||
lastTimerMinute = minute(localTime);
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (timerMacro[i] != 0
|
||||
&& (timerHours[i] == hour(local) || timerHours[i] == 24) //if hour is set to 24, activate every hour
|
||||
&& timerMinutes[i] == minute(local)
|
||||
&& (timerHours[i] == hour(localTime) || timerHours[i] == 24) //if hour is set to 24, activate every hour
|
||||
&& timerMinutes[i] == minute(localTime)
|
||||
&& (timerWeekday[i] & 0x01) //timer is enabled
|
||||
&& timerWeekday[i] >> weekdayMondayFirst() & 0x01) //timer should activate at current day of week
|
||||
{
|
||||
|
@ -40,10 +40,10 @@ void _overlayAnalogClock()
|
||||
{
|
||||
_overlayAnalogCountdown(); return;
|
||||
}
|
||||
double hourP = ((double)(hour(local)%12))/12;
|
||||
double minuteP = ((double)minute(local))/60;
|
||||
double hourP = ((double)(hour(localTime)%12))/12;
|
||||
double minuteP = ((double)minute(localTime))/60;
|
||||
hourP = hourP + minuteP/12;
|
||||
double secondP = ((double)second(local))/60;
|
||||
double secondP = ((double)second(localTime))/60;
|
||||
int hourPixel = floor(analogClock12pixel + overlaySize*hourP);
|
||||
if (hourPixel > overlayMax) hourPixel = overlayMin -1 + hourPixel - overlayMax;
|
||||
int minutePixel = floor(analogClock12pixel + overlaySize*minuteP);
|
||||
@ -279,13 +279,13 @@ void setCronixie()
|
||||
|
||||
void _overlayCronixie()
|
||||
{
|
||||
byte h = hour(local);
|
||||
byte h = hour(localTime);
|
||||
byte h0 = h;
|
||||
byte m = minute(local);
|
||||
byte s = second(local);
|
||||
byte d = day(local);
|
||||
byte mi = month(local);
|
||||
int y = year(local);
|
||||
byte m = minute(localTime);
|
||||
byte s = second(localTime);
|
||||
byte d = day(localTime);
|
||||
byte mi = month(localTime);
|
||||
int y = year(localTime);
|
||||
//this has to be changed in time for 22nd century
|
||||
y -= 2000; if (y<0) y += 30; //makes countdown work
|
||||
|
||||
@ -310,7 +310,7 @@ void _overlayCronixie()
|
||||
case 24: _digitOut[i] = m/10; break; //M
|
||||
case 30: _digitOut[i] = s/10; break; //S
|
||||
|
||||
case 43: _digitOut[i] = weekday(local); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //D
|
||||
case 43: _digitOut[i] = weekday(localTime); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //D
|
||||
case 44: _digitOut[i] = d/10; _digitOut[i+1] = d- _digitOut[i]*10; i++; break; //DD
|
||||
case 40: _digitOut[i] = mi/10; _digitOut[i+1] = mi- _digitOut[i]*10; i++; break; //II
|
||||
case 37: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //YY
|
||||
@ -331,7 +331,7 @@ void _overlayCronixie()
|
||||
//case 65: _digitOut[i+1] = (h0>17 || (h0>5 && h0<12))?1:10; i++; //bb
|
||||
case 64: _digitOut[i] = (h0>11)?1:10; break; //b
|
||||
|
||||
case 93: _digitOut[i] = weekday(local); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //d
|
||||
case 93: _digitOut[i] = weekday(localTime); _digitOut[i]--; if (_digitOut[i]<1) _digitOut[i]= 7; break; //d
|
||||
case 94: _digitOut[i] = d/10; _digitOut[i+1] = d- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //dd
|
||||
case 90: _digitOut[i] = mi/10; _digitOut[i+1] = mi- _digitOut[i]*10; if(_digitOut[i] == 0) _digitOut[i]=10; i++; break; //ii
|
||||
case 87: _digitOut[i] = y/10; _digitOut[i+1] = y- _digitOut[i]*10; i++; break; //yy
|
||||
|
@ -103,7 +103,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
t = request->arg("TL").toInt();
|
||||
if (t > 0) nightlightDelayMinsDefault = t;
|
||||
nightlightDelayMins = nightlightDelayMinsDefault;
|
||||
nightlightFade = request->hasArg("TW");
|
||||
nightlightMode = request->arg("TW").toInt();
|
||||
|
||||
t = request->arg("PB").toInt();
|
||||
if (t >= 0 && t < 4) strip.paletteBlend = t;
|
||||
@ -297,7 +297,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
||||
if (subPage == 7)
|
||||
{
|
||||
int t = request->arg("CN").toInt();
|
||||
int t = request->arg("PU").toInt();
|
||||
if (t >= 0 && t <= 63999) e131ProxyUniverse = t;
|
||||
|
||||
t = request->arg("CN").toInt();
|
||||
if (t>0 && t<16) {
|
||||
DMXChannels = t;
|
||||
}
|
||||
@ -420,7 +423,16 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
||||
|
||||
WS2812FX::Segment& mainseg = strip.getSegment(main);
|
||||
pos = req.indexOf("SV="); //segment selected
|
||||
if (pos > 0) mainseg.setOption(SEG_OPTION_SELECTED, (req.charAt(pos+3) != '0'));
|
||||
if (pos > 0) {
|
||||
byte t = getNumVal(&req, pos);
|
||||
if (t == 2) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++)
|
||||
{
|
||||
strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0);
|
||||
}
|
||||
}
|
||||
mainseg.setOption(SEG_OPTION_SELECTED, t);
|
||||
}
|
||||
|
||||
uint16_t startI = mainseg.start;
|
||||
uint16_t stopI = mainseg.stop;
|
||||
@ -465,7 +477,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
||||
pos = req.indexOf("PT="); //sets cycle time in ms
|
||||
if (pos > 0) {
|
||||
int v = getNumVal(&req, pos);
|
||||
if (v > 49) presetCycleTime = v;
|
||||
if (v > 100) presetCycleTime = v/100;
|
||||
}
|
||||
|
||||
pos = req.indexOf("PA="); //apply brightness from preset
|
||||
@ -600,10 +612,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
||||
pos = req.indexOf("NF=");
|
||||
if (pos > 0)
|
||||
{
|
||||
nightlightFade = (req.charAt(pos+3) != '0');
|
||||
nightlightColorFade = (req.charAt(pos+3) == '2'); //NighLightColorFade can only be enabled via API or Macro with "NF=2"
|
||||
nightlightMode = getNumVal(&req, pos);
|
||||
|
||||
nightlightActiveOld = false; //re-init
|
||||
}
|
||||
if (nightlightMode > NL_MODE_SUN) nightlightMode = NL_MODE_SUN;
|
||||
|
||||
#if AUXPIN >= 0
|
||||
//toggle general purpose output
|
||||
@ -624,8 +637,8 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
||||
nightlightActive = false; //always disable nightlight when toggling
|
||||
switch (getNumVal(&req, pos))
|
||||
{
|
||||
case 0: if (bri != 0){briLast = bri; bri = 0;} break; //off
|
||||
case 1: bri = briLast; break; //on
|
||||
case 0: if (bri != 0){briLast = bri; bri = 0;} break; //off, only if it was previously on
|
||||
case 1: if (bri == 0) bri = briLast; break; //on, only if it was previously off
|
||||
default: toggleOnOff(); //toggle
|
||||
}
|
||||
}
|
||||
@ -634,6 +647,10 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
||||
pos = req.indexOf("RV=");
|
||||
if (pos > 0) strip.getSegment(main).setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0');
|
||||
|
||||
//Segment reverse
|
||||
pos = req.indexOf("MI=");
|
||||
if (pos > 0) strip.getSegment(main).setOption(SEG_OPTION_MIRROR, req.charAt(pos+3) != '0');
|
||||
|
||||
//Segment brightness/opacity
|
||||
pos = req.indexOf("SB=");
|
||||
if (pos > 0) {
|
||||
@ -644,8 +661,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
||||
}
|
||||
}
|
||||
|
||||
//deactivate nightlight if target brightness is reached
|
||||
if (bri == nightlightTargetBri) nightlightActive = false;
|
||||
//set time (unix timestamp)
|
||||
pos = req.indexOf("ST=");
|
||||
if (pos > 0) {
|
||||
@ -659,6 +674,12 @@ bool handleSet(AsyncWebServerRequest *request, const String& req)
|
||||
if (countdownTime - now() > 0) countdownOverTriggered = false;
|
||||
}
|
||||
|
||||
pos = req.indexOf("LO=");
|
||||
if (pos > 0) {
|
||||
realtimeOverride = getNumVal(&req, pos);
|
||||
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
|
||||
}
|
||||
|
||||
pos = req.indexOf("RB");
|
||||
if (pos > 0) doReboot = true;
|
||||
|
||||
|
@ -1,318 +0,0 @@
|
||||
/*
|
||||
esp8266_waveform - General purpose waveform generation and control,
|
||||
supporting outputs on all pins in parallel.
|
||||
|
||||
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
The core idea is to have a programmable waveform generator with a unique
|
||||
high and low period (defined in microseconds). TIMER1 is set to 1-shot
|
||||
mode and is always loaded with the time until the next edge of any live
|
||||
waveforms.
|
||||
|
||||
Up to one waveform generator per pin supported.
|
||||
|
||||
Each waveform generator is synchronized to the ESP cycle counter, not the
|
||||
timer. This allows for removing interrupt jitter and delay as the counter
|
||||
always increments once per 80MHz clock. Changes to a waveform are
|
||||
contiguous and only take effect on the next waveform transition,
|
||||
allowing for smooth transitions.
|
||||
|
||||
This replaces older tone(), analogWrite(), and the Servo classes.
|
||||
|
||||
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
|
||||
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef ESP8266
|
||||
#include <Arduino.h>
|
||||
#include "ets_sys.h"
|
||||
#include "core_esp8266_waveform.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Maximum delay between IRQs
|
||||
#define MAXIRQUS (10000)
|
||||
|
||||
// Set/clear GPIO 0-15 by bitmask
|
||||
#define SetGPIO(a) do { GPOS = a; } while (0)
|
||||
#define ClearGPIO(a) do { GPOC = a; } while (0)
|
||||
|
||||
// Waveform generator can create tones, PWM, and servos
|
||||
typedef struct {
|
||||
uint32_t nextServiceCycle; // ESP cycle timer when a transition required
|
||||
uint32_t expiryCycle; // For time-limited waveform, the cycle when this waveform must stop
|
||||
uint32_t nextTimeHighCycles; // Copy over low->high to keep smooth waveform
|
||||
uint32_t nextTimeLowCycles; // Copy over high->low to keep smooth waveform
|
||||
} Waveform;
|
||||
|
||||
static Waveform waveform[17]; // State of all possible pins
|
||||
static volatile uint32_t waveformState = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code
|
||||
static volatile uint32_t waveformEnabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code
|
||||
|
||||
// Enable lock-free by only allowing updates to waveformState and waveformEnabled from IRQ service routine
|
||||
static volatile uint32_t waveformToEnable = 0; // Message to the NMI handler to start a waveform on a inactive pin
|
||||
static volatile uint32_t waveformToDisable = 0; // Message to the NMI handler to disable a pin from waveform generation
|
||||
|
||||
static uint32_t (*timer1CB)() = NULL;
|
||||
|
||||
|
||||
// Non-speed critical bits
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
static inline ICACHE_RAM_ATTR uint32_t GetCycleCount() {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("esync; rsr %0,ccount":"=a"(ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
// Interrupt on/off control
|
||||
static ICACHE_RAM_ATTR void timer1Interrupt();
|
||||
static bool timerRunning = false;
|
||||
|
||||
static void initTimer() {
|
||||
timer1_disable();
|
||||
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt);
|
||||
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
|
||||
timerRunning = true;
|
||||
}
|
||||
|
||||
static void ICACHE_RAM_ATTR deinitTimer() {
|
||||
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
|
||||
timer1_disable();
|
||||
timer1_isr_init();
|
||||
timerRunning = false;
|
||||
}
|
||||
|
||||
// Set a callback. Pass in NULL to stop it
|
||||
void setTimer1Callback(uint32_t (*fn)()) {
|
||||
timer1CB = fn;
|
||||
if (!timerRunning && fn) {
|
||||
initTimer();
|
||||
timer1_write(microsecondsToClockCycles(1)); // Cause an interrupt post-haste
|
||||
} else if (timerRunning && !fn && !waveformEnabled) {
|
||||
deinitTimer();
|
||||
}
|
||||
}
|
||||
|
||||
// Start up a waveform on a pin, or change the current one. Will change to the new
|
||||
// waveform smoothly on next low->high transition. For immediate change, stopWaveform()
|
||||
// first, then it will immediately begin.
|
||||
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) {
|
||||
if ((pin > 16) || isFlashInterfacePin(pin)) {
|
||||
return false;
|
||||
}
|
||||
Waveform *wave = &waveform[pin];
|
||||
// Adjust to shave off some of the IRQ time, approximately
|
||||
wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS);
|
||||
wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS);
|
||||
wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0;
|
||||
if (runTimeUS && !wave->expiryCycle) {
|
||||
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
|
||||
}
|
||||
|
||||
uint32_t mask = 1<<pin;
|
||||
if (!(waveformEnabled & mask)) {
|
||||
// Actually set the pin high or low in the IRQ service to guarantee times
|
||||
wave->nextServiceCycle = GetCycleCount() + microsecondsToClockCycles(1);
|
||||
waveformToEnable |= mask;
|
||||
if (!timerRunning) {
|
||||
initTimer();
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
} else {
|
||||
// Ensure timely service....
|
||||
if (T1L > microsecondsToClockCycles(10)) {
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
}
|
||||
}
|
||||
while (waveformToEnable) {
|
||||
delay(0); // Wait for waveform to update
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Speed critical bits
|
||||
#pragma GCC optimize ("O2")
|
||||
// Normally would not want two copies like this, but due to different
|
||||
// optimization levels the inline attribute gets lost if we try the
|
||||
// other version.
|
||||
|
||||
static inline ICACHE_RAM_ATTR uint32_t GetCycleCountIRQ() {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a"(ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
static inline ICACHE_RAM_ATTR uint32_t min_u32(uint32_t a, uint32_t b) {
|
||||
if (a < b) {
|
||||
return a;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// Stops a waveform on a pin
|
||||
int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
|
||||
// Can't possibly need to stop anything if there is no timer active
|
||||
if (!timerRunning) {
|
||||
return false;
|
||||
}
|
||||
// If user sends in a pin >16 but <32, this will always point to a 0 bit
|
||||
// If they send >=32, then the shift will result in 0 and it will also return false
|
||||
uint32_t mask = 1<<pin;
|
||||
if (!(waveformEnabled & mask)) {
|
||||
return false; // It's not running, nothing to do here
|
||||
}
|
||||
waveformToDisable |= mask;
|
||||
// Ensure timely service....
|
||||
if (T1L > microsecondsToClockCycles(10)) {
|
||||
timer1_write(microsecondsToClockCycles(10));
|
||||
}
|
||||
while (waveformToDisable) {
|
||||
/* no-op */ // Can't delay() since stopWaveform may be called from an IRQ
|
||||
}
|
||||
if (!waveformEnabled && !timer1CB) {
|
||||
deinitTimer();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// The SDK and hardware take some time to actually get to our NMI code, so
|
||||
// decrement the next IRQ's timer value by a bit so we can actually catch the
|
||||
// real CPU cycle counter we want for the waveforms.
|
||||
#if F_CPU == 80000000
|
||||
#define DELTAIRQ (microsecondsToClockCycles(3))
|
||||
#else
|
||||
#define DELTAIRQ (microsecondsToClockCycles(2))
|
||||
#endif
|
||||
|
||||
|
||||
static ICACHE_RAM_ATTR void timer1Interrupt() {
|
||||
// Optimize the NMI inner loop by keeping track of the min and max GPIO that we
|
||||
// are generating. In the common case (1 PWM) these may be the same pin and
|
||||
// we can avoid looking at the other pins.
|
||||
static int startPin = 0;
|
||||
static int endPin = 0;
|
||||
|
||||
uint32_t nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
|
||||
uint32_t timeoutCycle = GetCycleCountIRQ() + microsecondsToClockCycles(14);
|
||||
|
||||
if (waveformToEnable || waveformToDisable) {
|
||||
// Handle enable/disable requests from main app.
|
||||
waveformEnabled = (waveformEnabled & ~waveformToDisable) | waveformToEnable; // Set the requested waveforms on/off
|
||||
waveformState &= ~waveformToEnable; // And clear the state of any just started
|
||||
waveformToEnable = 0;
|
||||
waveformToDisable = 0;
|
||||
// Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t)
|
||||
startPin = __builtin_ffs(waveformEnabled) - 1;
|
||||
// Find the last bit by subtracting off GCC's count-leading-zeros (no offset in this one)
|
||||
endPin = 32 - __builtin_clz(waveformEnabled);
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
if (waveformEnabled) {
|
||||
do {
|
||||
nextEventCycles = microsecondsToClockCycles(MAXIRQUS);
|
||||
for (int i = startPin; i <= endPin; i++) {
|
||||
uint32_t mask = 1<<i;
|
||||
|
||||
// If it's not on, ignore!
|
||||
if (!(waveformEnabled & mask)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Waveform *wave = &waveform[i];
|
||||
uint32_t now = GetCycleCountIRQ();
|
||||
|
||||
// Disable any waveforms that are done
|
||||
if (wave->expiryCycle) {
|
||||
int32_t expiryToGo = wave->expiryCycle - now;
|
||||
if (expiryToGo < 0) {
|
||||
// Done, remove!
|
||||
waveformEnabled &= ~mask;
|
||||
if (i == 16) {
|
||||
GP16O &= ~1;
|
||||
} else {
|
||||
ClearGPIO(mask);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for toggles
|
||||
int32_t cyclesToGo = wave->nextServiceCycle - now;
|
||||
if (cyclesToGo < 0) {
|
||||
// See #7057
|
||||
// The following is a no-op unless we have overshot by an entire waveform cycle.
|
||||
// As modulus is an expensive operation, this code is removed for now:
|
||||
// cyclesToGo = -((-cyclesToGo) % (wave->nextTimeHighCycles + wave->nextTimeLowCycles));
|
||||
//
|
||||
// Alternative version with lower CPU impact:
|
||||
// while (-cyclesToGo > wave->nextTimeHighCycles + wave->nextTimeLowCycles) { cyclesToGo += wave->nextTimeHighCycles + wave->nextTimeLowCycles)};
|
||||
waveformState ^= mask;
|
||||
if (waveformState & mask) {
|
||||
if (i == 16) {
|
||||
GP16O |= 1; // GPIO16 write slow as it's RMW
|
||||
} else {
|
||||
SetGPIO(mask);
|
||||
}
|
||||
wave->nextServiceCycle = now + wave->nextTimeHighCycles + cyclesToGo;
|
||||
nextEventCycles = min_u32(nextEventCycles, min_u32(wave->nextTimeHighCycles + cyclesToGo, 1));
|
||||
} else {
|
||||
if (i == 16) {
|
||||
GP16O &= ~1; // GPIO16 write slow as it's RMW
|
||||
} else {
|
||||
ClearGPIO(mask);
|
||||
}
|
||||
wave->nextServiceCycle = now + wave->nextTimeLowCycles + cyclesToGo;
|
||||
nextEventCycles = min_u32(nextEventCycles, min_u32(wave->nextTimeLowCycles + cyclesToGo, 1));
|
||||
}
|
||||
} else {
|
||||
uint32_t deltaCycles = wave->nextServiceCycle - now;
|
||||
nextEventCycles = min_u32(nextEventCycles, deltaCycles);
|
||||
}
|
||||
}
|
||||
|
||||
// Exit the loop if we've hit the fixed runtime limit or the next event is known to be after that timeout would occur
|
||||
uint32_t now = GetCycleCountIRQ();
|
||||
int32_t cycleDeltaNextEvent = timeoutCycle - (now + nextEventCycles);
|
||||
int32_t cyclesLeftTimeout = timeoutCycle - now;
|
||||
done = (cycleDeltaNextEvent < 0) || (cyclesLeftTimeout < 0);
|
||||
} while (!done);
|
||||
} // if (waveformEnabled)
|
||||
|
||||
if (timer1CB) {
|
||||
nextEventCycles = min_u32(nextEventCycles, timer1CB());
|
||||
}
|
||||
|
||||
if (nextEventCycles < microsecondsToClockCycles(10)) {
|
||||
nextEventCycles = microsecondsToClockCycles(10);
|
||||
}
|
||||
nextEventCycles -= DELTAIRQ;
|
||||
|
||||
// Do it here instead of global function to save time and because we know it's edge-IRQ
|
||||
#if F_CPU == 160000000
|
||||
T1L = nextEventCycles >> 1; // Already know we're in range by MAXIRQUS
|
||||
#else
|
||||
T1L = nextEventCycles; // Already know we're in range by MAXIRQUS
|
||||
#endif
|
||||
TEIE |= TEIE1; // Edge int enable
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
esp8266_waveform - General purpose waveform generation and control,
|
||||
supporting outputs on all pins in parallel.
|
||||
|
||||
Copyright (c) 2018 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
The core idea is to have a programmable waveform generator with a unique
|
||||
high and low period (defined in microseconds). TIMER1 is set to 1-shot
|
||||
mode and is always loaded with the time until the next edge of any live
|
||||
waveforms.
|
||||
|
||||
Up to one waveform generator per pin supported.
|
||||
|
||||
Each waveform generator is synchronized to the ESP cycle counter, not the
|
||||
timer. This allows for removing interrupt jitter and delay as the counter
|
||||
always increments once per 80MHz clock. Changes to a waveform are
|
||||
contiguous and only take effect on the next waveform transition,
|
||||
allowing for smooth transitions.
|
||||
|
||||
This replaces older tone(), analogWrite(), and the Servo classes.
|
||||
|
||||
Everywhere in the code where "cycles" is used, it means ESP.getCycleTime()
|
||||
cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz).
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifndef __ESP8266_WAVEFORM_H
|
||||
#define __ESP8266_WAVEFORM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Start or change a waveform of the specified high and low times on specific pin.
|
||||
// If runtimeUS > 0 then automatically stop it after that many usecs.
|
||||
// Returns true or false on success or failure.
|
||||
int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS);
|
||||
// Stop a waveform, if any, on the specified pin.
|
||||
// Returns true or false on success or failure.
|
||||
int stopWaveform(uint8_t pin);
|
||||
|
||||
// Add a callback function to be called on *EVERY* timer1 trigger. The
|
||||
// callback returns the number of microseconds until the next desired call.
|
||||
// However, since it is called every timer1 interrupt, it may be called
|
||||
// again before this period. It should therefore use the ESP Cycle Counter
|
||||
// to determine whether or not to perform an operation.
|
||||
// Pass in NULL to disable the callback and, if no other waveforms being
|
||||
// generated, stop the timer as well.
|
||||
// Make sure the CB function has the ICACHE_RAM_ATTR decorator.
|
||||
void setTimer1Callback(uint32_t (*fn)());
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
/*
|
||||
* @title Espalexa library
|
||||
* @version 2.4.5
|
||||
* @version 2.4.6
|
||||
* @author Christian Schwinne
|
||||
* @license MIT
|
||||
* @contributors d-999
|
||||
@ -49,7 +49,7 @@
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
#ifdef ESPALEXA_DEBUG
|
||||
#pragma message "Espalexa 2.4.5 debug mode"
|
||||
#pragma message "Espalexa 2.4.6 debug mode"
|
||||
#define EA_DEBUG(x) Serial.print (x)
|
||||
#define EA_DEBUGLN(x) Serial.println (x)
|
||||
#else
|
||||
@ -81,35 +81,29 @@ private:
|
||||
WiFiUDP espalexaUdp;
|
||||
IPAddress ipMulti;
|
||||
bool udpConnected = false;
|
||||
char packetBuffer[255]; //buffer to hold incoming udp packet
|
||||
String escapedMac=""; //lowercase mac address
|
||||
|
||||
//private member functions
|
||||
String boolString(bool st)
|
||||
{
|
||||
return(st)?"true":"false";
|
||||
}
|
||||
|
||||
String modeString(EspalexaColorMode m)
|
||||
const char* modeString(EspalexaColorMode m)
|
||||
{
|
||||
if (m == EspalexaColorMode::xy) return "xy";
|
||||
if (m == EspalexaColorMode::hs) return "hs";
|
||||
return "ct";
|
||||
}
|
||||
|
||||
String typeString(EspalexaDeviceType t)
|
||||
const char* typeString(EspalexaDeviceType t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case EspalexaDeviceType::dimmable: return "Dimmable light";
|
||||
case EspalexaDeviceType::whitespectrum: return "Color temperature light";
|
||||
case EspalexaDeviceType::color: return "Color light";
|
||||
case EspalexaDeviceType::extendedcolor: return "Extended color light";
|
||||
case EspalexaDeviceType::dimmable: return PSTR("Dimmable light");
|
||||
case EspalexaDeviceType::whitespectrum: return PSTR("Color temperature light");
|
||||
case EspalexaDeviceType::color: return PSTR("Color light");
|
||||
case EspalexaDeviceType::extendedcolor: return PSTR("Extended color light");
|
||||
}
|
||||
return "Light";
|
||||
return "";
|
||||
}
|
||||
|
||||
String modelidString(EspalexaDeviceType t)
|
||||
const char* modelidString(EspalexaDeviceType t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
@ -118,7 +112,7 @@ private:
|
||||
case EspalexaDeviceType::color: return "LST001";
|
||||
case EspalexaDeviceType::extendedcolor: return "LCT015";
|
||||
}
|
||||
return "Plug";
|
||||
return "";
|
||||
}
|
||||
|
||||
//Workaround functions courtesy of Sonoff-Tasmota
|
||||
@ -135,38 +129,38 @@ private:
|
||||
}
|
||||
|
||||
//device JSON string: color+temperature device emulates LCT015, dimmable device LWB010, (TODO: on/off Plug 01, color temperature device LWT010, color device LST001)
|
||||
String deviceJsonString(uint8_t deviceId)
|
||||
void deviceJsonString(uint8_t deviceId, char* buf)
|
||||
{
|
||||
deviceId--;
|
||||
if (deviceId >= currentDeviceCount) return "{}"; //error
|
||||
if (deviceId >= currentDeviceCount) {strcpy(buf,"{}"); return;} //error
|
||||
EspalexaDevice* dev = devices[deviceId];
|
||||
|
||||
String json = "{\"state\":{\"on\":";
|
||||
json += boolString(dev->getValue());
|
||||
if (dev->getType() != EspalexaDeviceType::onoff) //bri support
|
||||
{
|
||||
json += ",\"bri\":" + String(dev->getLastValue()-1);
|
||||
if (static_cast<uint8_t>(dev->getType()) > 2) //color support
|
||||
{
|
||||
json += ",\"hue\":" + String(dev->getHue()) + ",\"sat\":" + String(dev->getSat());
|
||||
json += ",\"effect\":\"none\",\"xy\":[" + String(dev->getX()) + "," + String(dev->getY()) + "]";
|
||||
}
|
||||
if (static_cast<uint8_t>(dev->getType()) > 1 && dev->getType() != EspalexaDeviceType::color) //white spectrum support
|
||||
{
|
||||
json += ",\"ct\":" + String(dev->getCt());
|
||||
}
|
||||
}
|
||||
json += ",\"alert\":\"none";
|
||||
if (static_cast<uint8_t>(dev->getType()) > 1) json += "\",\"colormode\":\"" + modeString(dev->getColorMode());
|
||||
json += "\",\"mode\":\"homeautomation\",\"reachable\":true},";
|
||||
json += "\"type\":\"" + typeString(dev->getType());
|
||||
json += "\",\"name\":\"" + dev->getName();
|
||||
json += "\",\"modelid\":\"" + modelidString(dev->getType());
|
||||
json += "\",\"manufacturername\":\"Philips\",\"productname\":\"E" + String(static_cast<uint8_t>(dev->getType()));
|
||||
json += "\",\"uniqueid\":\"" + String(encodeLightId(deviceId+1));
|
||||
json += "\",\"swversion\":\"espalexa-2.4.5\"}";
|
||||
|
||||
return json;
|
||||
//char buf_bri[12] = "";
|
||||
//brightness support, add "bri" to JSON
|
||||
//if (dev->getType() != EspalexaDeviceType::onoff)
|
||||
// sprintf(buf_bri,",\"bri\":%u", dev->getLastValue()-1);
|
||||
|
||||
char buf_col[80] = "";
|
||||
//color support
|
||||
if (static_cast<uint8_t>(dev->getType()) > 2)
|
||||
sprintf_P(buf_col,PSTR(",\"hue\":%u,\"sat\":%u,\"effect\":\"none\",\"xy\":[%f,%f]")
|
||||
,dev->getHue(), dev->getSat(), dev->getX(), dev->getY());
|
||||
|
||||
char buf_ct[16] = "";
|
||||
//white spectrum support
|
||||
if (static_cast<uint8_t>(dev->getType()) > 1 && dev->getType() != EspalexaDeviceType::color)
|
||||
sprintf(buf_ct, ",\"ct\":%u", dev->getCt());
|
||||
|
||||
char buf_cm[20] = "";
|
||||
if (static_cast<uint8_t>(dev->getType()) > 1)
|
||||
sprintf(buf_cm,PSTR("\",\"colormode\":\"%s"), modeString(dev->getColorMode()));
|
||||
|
||||
sprintf_P(buf, PSTR("{\"state\":{\"on\":%s,\"bri\":%u%s%s,\"alert\":\"none%s\",\"mode\":\"homeautomation\",\"reachable\":true},"
|
||||
"\"type\":\"%s\",\"name\":\"%s\",\"modelid\":\"%s\",\"manufacturername\":\"Philips\",\"productname\":\"E%u"
|
||||
"\",\"uniqueid\":\"%u\",\"swversion\":\"espalexa-2.4.6\"}")
|
||||
|
||||
, (dev->getValue())?"true":"false", dev->getLastValue()-1, buf_col, buf_ct, buf_cm, typeString(dev->getType()),
|
||||
dev->getName().c_str(), modelidString(dev->getType()), static_cast<uint8_t>(dev->getType()), encodeLightId(deviceId+1));
|
||||
}
|
||||
|
||||
//Espalexa status page /espalexa
|
||||
@ -181,14 +175,14 @@ private:
|
||||
res += "Value of device " + String(i+1) + " (" + dev->getName() + "): " + String(dev->getValue()) + " (" + typeString(dev->getType());
|
||||
if (static_cast<uint8_t>(dev->getType()) > 1) //color support
|
||||
{
|
||||
res += ", colormode=" + modeString(dev->getColorMode()) + ", r=" + String(dev->getR()) + ", g=" + String(dev->getG()) + ", b=" + String(dev->getB());
|
||||
res += ", colormode=" + String(modeString(dev->getColorMode())) + ", r=" + String(dev->getR()) + ", g=" + String(dev->getG()) + ", b=" + String(dev->getB());
|
||||
res +=", ct=" + String(dev->getCt()) + ", hue=" + String(dev->getHue()) + ", sat=" + String(dev->getSat()) + ", x=" + String(dev->getX()) + ", y=" + String(dev->getY());
|
||||
}
|
||||
res += ")\r\n";
|
||||
}
|
||||
res += "\r\nFree Heap: " + (String)ESP.getFreeHeap();
|
||||
res += "\r\nUptime: " + (String)millis();
|
||||
res += "\r\n\r\nEspalexa library v2.4.5 by Christian Schwinne 2020";
|
||||
res += "\r\n\r\nEspalexa library v2.4.6 by Christian Schwinne 2020";
|
||||
server->send(200, "text/plain", res);
|
||||
}
|
||||
#endif
|
||||
@ -206,7 +200,7 @@ private:
|
||||
EA_DEBUGLN("Body: " + body);
|
||||
if(!handleAlexaApiCall(server))
|
||||
#endif
|
||||
server->send(404, "text/plain", "Not Found (espalexa-internal)");
|
||||
server->send(404, "text/plain", "Not Found (espalexa)");
|
||||
}
|
||||
|
||||
//send description.xml device property page
|
||||
@ -216,30 +210,31 @@ private:
|
||||
IPAddress localIP = WiFi.localIP();
|
||||
char s[16];
|
||||
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
|
||||
|
||||
String setup_xml = "<?xml version=\"1.0\" ?>"
|
||||
char buf[1024];
|
||||
|
||||
sprintf_P(buf,PSTR("<?xml version=\"1.0\" ?>"
|
||||
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
|
||||
"<specVersion><major>1</major><minor>0</minor></specVersion>"
|
||||
"<URLBase>http://"+ String(s) +":80/</URLBase>"
|
||||
"<URLBase>http://%s:80/</URLBase>"
|
||||
"<device>"
|
||||
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>"
|
||||
"<friendlyName>Espalexa ("+ String(s) +")</friendlyName>"
|
||||
"<friendlyName>Espalexa (%s)</friendlyName>"
|
||||
"<manufacturer>Royal Philips Electronics</manufacturer>"
|
||||
"<manufacturerURL>http://www.philips.com</manufacturerURL>"
|
||||
"<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>"
|
||||
"<modelName>Philips hue bridge 2012</modelName>"
|
||||
"<modelNumber>929000226503</modelNumber>"
|
||||
"<modelURL>http://www.meethue.com</modelURL>"
|
||||
"<serialNumber>"+ escapedMac +"</serialNumber>"
|
||||
"<UDN>uuid:2f402f80-da50-11e1-9b23-"+ escapedMac +"</UDN>"
|
||||
"<serialNumber>%s</serialNumber>"
|
||||
"<UDN>uuid:2f402f80-da50-11e1-9b23-%s</UDN>"
|
||||
"<presentationURL>index.html</presentationURL>"
|
||||
"</device>"
|
||||
"</root>";
|
||||
"</root>"),s,s,escapedMac.c_str(),escapedMac.c_str());
|
||||
|
||||
server->send(200, "text/xml", setup_xml.c_str());
|
||||
server->send(200, "text/xml", buf);
|
||||
|
||||
EA_DEBUG("Sending :");
|
||||
EA_DEBUGLN(setup_xml);
|
||||
EA_DEBUG("Send setup.xml");
|
||||
//EA_DEBUGLN(setup_xml);
|
||||
}
|
||||
|
||||
//init the server
|
||||
@ -290,22 +285,23 @@ private:
|
||||
char s[16];
|
||||
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
|
||||
|
||||
String response =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
char buf[1024];
|
||||
|
||||
sprintf_P(buf,PSTR("HTTP/1.1 200 OK\r\n"
|
||||
"EXT:\r\n"
|
||||
"CACHE-CONTROL: max-age=100\r\n" // SSDP_INTERVAL
|
||||
"LOCATION: http://"+ String(s) +":80/description.xml\r\n"
|
||||
"LOCATION: http://%s:80/description.xml\r\n"
|
||||
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.17.0\r\n" // _modelName, _modelNumber
|
||||
"hue-bridgeid: "+ escapedMac +"\r\n"
|
||||
"hue-bridgeid: %s\r\n"
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n" // _deviceType
|
||||
"USN: uuid:2f402f80-da50-11e1-9b23-"+ escapedMac +"::ssdp:all\r\n" // _uuid::_deviceType
|
||||
"\r\n";
|
||||
"USN: uuid:2f402f80-da50-11e1-9b23-%s::ssdp:all\r\n" // _uuid::_deviceType
|
||||
"\r\n"),s,escapedMac.c_str(),escapedMac.c_str());
|
||||
|
||||
espalexaUdp.beginPacket(espalexaUdp.remoteIP(), espalexaUdp.remotePort());
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
espalexaUdp.write((uint8_t*)response.c_str(), response.length());
|
||||
espalexaUdp.write((uint8_t*)buf, strlen(buf));
|
||||
#else
|
||||
espalexaUdp.write(response.c_str());
|
||||
espalexaUdp.write(buf);
|
||||
#endif
|
||||
espalexaUdp.endPacket();
|
||||
}
|
||||
@ -362,7 +358,8 @@ public:
|
||||
if (!packetSize) return; //no new udp packet
|
||||
|
||||
EA_DEBUGLN("Got UDP!");
|
||||
int len = espalexaUdp.read(packetBuffer, 254);
|
||||
char packetBuffer[255]; //buffer to hold incoming udp packet
|
||||
uint16_t len = espalexaUdp.read(packetBuffer, 254);
|
||||
if (len > 0) {
|
||||
packetBuffer[len] = 0;
|
||||
}
|
||||
@ -370,10 +367,9 @@ public:
|
||||
if (!discoverable) return; //do not reply to M-SEARCH if not discoverable
|
||||
|
||||
String request = packetBuffer;
|
||||
if(request.indexOf("M-SEA") >= 0) { //M-SEARCH
|
||||
if(request.indexOf("M-SEARCH") >= 0) {
|
||||
EA_DEBUGLN(request);
|
||||
//match upnp:rootdevice, device:basic:1, ssdp:all and ssdp:discover
|
||||
if(request.indexOf("np:rootd") > 0 || request.indexOf("asic:1") > 0 || request.indexOf("dp:all") > 0 || request.indexOf("dp:dis") > 0) {
|
||||
if(request.indexOf("upnp:rootdevice") > 0 || request.indexOf("asic:1") > 0 || request.indexOf("ssdp:all") > 0) {
|
||||
EA_DEBUGLN("Responding search req...");
|
||||
respondToSearch();
|
||||
}
|
||||
@ -448,13 +444,13 @@ public:
|
||||
{
|
||||
EA_DEBUGLN("devType");
|
||||
body = "";
|
||||
server->send(200, "application/json", "[{\"success\":{\"username\":\"2WLEDHardQrI3WHYTHoMcXHgEspsM8ZZRpSKtBQr\"}}]");
|
||||
server->send(200, "application/json", F("[{\"success\":{\"username\":\"2WLEDHardQrI3WHYTHoMcXHgEspsM8ZZRpSKtBQr\"}}]"));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (req.indexOf("state") > 0) //client wants to control light
|
||||
{
|
||||
server->send(200, "application/json", "[{\"success\":{\"/lights/1/state/\": true}}]");
|
||||
server->send(200, "application/json", F("[{\"success\":{\"/lights/1/state/\": true}}]"));
|
||||
|
||||
uint32_t devId = req.substring(req.indexOf("lights")+7).toInt();
|
||||
EA_DEBUG("ls"); EA_DEBUGLN(devId);
|
||||
@ -531,7 +527,9 @@ public:
|
||||
for (int i = 0; i<currentDeviceCount; i++)
|
||||
{
|
||||
jsonTemp += "\"" + String(encodeLightId(i+1)) + "\":";
|
||||
jsonTemp += deviceJsonString(i+1);
|
||||
char buf[512];
|
||||
deviceJsonString(i+1, buf);
|
||||
jsonTemp += buf;
|
||||
if (i < currentDeviceCount-1) jsonTemp += ",";
|
||||
}
|
||||
jsonTemp += "}";
|
||||
@ -544,7 +542,9 @@ public:
|
||||
{
|
||||
server->send(200, "application/json", "{}");
|
||||
} else {
|
||||
server->send(200, "application/json", deviceJsonString(devId));
|
||||
char buf[512];
|
||||
deviceJsonString(devId, buf);
|
||||
server->send(200, "application/json", buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ EspalexaDevice::EspalexaDevice(String deviceName, DeviceCallbackFunction gnCallb
|
||||
_callbackDev = gnCallback;
|
||||
_type = t;
|
||||
if (t == EspalexaDeviceType::onoff) _type = EspalexaDeviceType::dimmable; //on/off is broken, so make dimmable device instead
|
||||
if (t == EspalexaDeviceType::whitespectrum) _mode = EspalexaColorMode::ct;
|
||||
_val = initialValue;
|
||||
_val_last = _val;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#ifndef EspalexaDevice_h
|
||||
#define EspalexaDevice_h
|
||||
#include <functional>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <functional>
|
||||
|
||||
|
256
wled00/udp.cpp
@ -1,7 +1,7 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* UDP sync notifier
|
||||
* UDP sync notifier / Realtime / Hyperion / TPM2.NET
|
||||
*/
|
||||
|
||||
#define WLEDPACKETSIZE 29
|
||||
@ -89,6 +89,16 @@ void realtimeLock(uint32_t timeoutMs, byte md)
|
||||
}
|
||||
|
||||
|
||||
#define TMP2NET_OUT_PORT 65442
|
||||
|
||||
void sendTPM2Ack() {
|
||||
notifierUdp.beginPacket(notifierUdp.remoteIP(), TMP2NET_OUT_PORT);
|
||||
uint8_t response_ack = 0xac;
|
||||
notifierUdp.write(&response_ack, 1);
|
||||
notifierUdp.endPacket();
|
||||
}
|
||||
|
||||
|
||||
void handleNotifications()
|
||||
{
|
||||
//send second notification if enabled
|
||||
@ -139,122 +149,162 @@ void handleNotifications()
|
||||
}
|
||||
|
||||
//notifier and UDP realtime
|
||||
if (packetSize > UDP_IN_MAXSIZE) return;
|
||||
if(packetSize && notifierUdp.remoteIP() != WiFi.localIP()) //don't process broadcasts we send ourselves
|
||||
if (!packetSize || packetSize > UDP_IN_MAXSIZE) return;
|
||||
if (notifierUdp.remoteIP() == WiFi.localIP()) return; //don't process broadcasts we send ourselves
|
||||
|
||||
uint8_t udpIn[packetSize];
|
||||
notifierUdp.read(udpIn, packetSize);
|
||||
|
||||
//wled notifier, block if realtime packets active
|
||||
if (udpIn[0] == 0 && !realtimeMode && receiveNotifications)
|
||||
{
|
||||
uint8_t udpIn[packetSize];
|
||||
notifierUdp.read(udpIn, packetSize);
|
||||
|
||||
//wled notifier, block if realtime packets active
|
||||
if (udpIn[0] == 0 && !realtimeMode && receiveNotifications)
|
||||
//ignore notification if received within a second after sending a notification ourselves
|
||||
if (millis() - notificationSentTime < 1000) return;
|
||||
if (udpIn[1] > 199) return; //do not receive custom versions
|
||||
|
||||
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
||||
//apply colors from notification
|
||||
if (receiveNotificationColor || !someSel)
|
||||
{
|
||||
//ignore notification if received within a second after sending a notification ourselves
|
||||
if (millis() - notificationSentTime < 1000) return;
|
||||
if (udpIn[1] > 199) return; //do not receive custom versions
|
||||
|
||||
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
||||
//apply colors from notification
|
||||
if (receiveNotificationColor || !someSel)
|
||||
col[0] = udpIn[3];
|
||||
col[1] = udpIn[4];
|
||||
col[2] = udpIn[5];
|
||||
if (udpIn[11] > 0) //sending module's white val is intended
|
||||
{
|
||||
col[0] = udpIn[3];
|
||||
col[1] = udpIn[4];
|
||||
col[2] = udpIn[5];
|
||||
if (udpIn[11] > 0) //sending module's white val is intended
|
||||
col[3] = udpIn[10];
|
||||
if (udpIn[11] > 1)
|
||||
{
|
||||
col[3] = udpIn[10];
|
||||
if (udpIn[11] > 1)
|
||||
{
|
||||
colSec[0] = udpIn[12];
|
||||
colSec[1] = udpIn[13];
|
||||
colSec[2] = udpIn[14];
|
||||
colSec[3] = udpIn[15];
|
||||
}
|
||||
if (udpIn[11] > 5)
|
||||
{
|
||||
uint32_t t = (udpIn[25] << 24) | (udpIn[26] << 16) | (udpIn[27] << 8) | (udpIn[28]);
|
||||
t += 2;
|
||||
t -= millis();
|
||||
strip.timebase = t;
|
||||
}
|
||||
if (udpIn[11] > 6)
|
||||
{
|
||||
strip.setColor(2, udpIn[20], udpIn[21], udpIn[22], udpIn[23]); //tertiary color
|
||||
}
|
||||
colSec[0] = udpIn[12];
|
||||
colSec[1] = udpIn[13];
|
||||
colSec[2] = udpIn[14];
|
||||
colSec[3] = udpIn[15];
|
||||
}
|
||||
if (udpIn[11] > 5)
|
||||
{
|
||||
uint32_t t = (udpIn[25] << 24) | (udpIn[26] << 16) | (udpIn[27] << 8) | (udpIn[28]);
|
||||
t += 2;
|
||||
t -= millis();
|
||||
strip.timebase = t;
|
||||
}
|
||||
if (udpIn[11] > 6)
|
||||
{
|
||||
strip.setColor(2, udpIn[20], udpIn[21], udpIn[22], udpIn[23]); //tertiary color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//apply effects from notification
|
||||
if (udpIn[11] < 200 && (receiveNotificationEffects || !someSel))
|
||||
{
|
||||
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
|
||||
effectSpeed = udpIn[9];
|
||||
if (udpIn[11] > 2) effectIntensity = udpIn[16];
|
||||
if (udpIn[11] > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19];
|
||||
}
|
||||
|
||||
if (udpIn[11] > 3)
|
||||
{
|
||||
transitionDelayTemp = ((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00);
|
||||
}
|
||||
|
||||
nightlightActive = udpIn[6];
|
||||
if (nightlightActive) nightlightDelayMins = udpIn[7];
|
||||
|
||||
if (receiveNotificationBrightness || !someSel) bri = udpIn[2];
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
|
||||
|
||||
} else if (udpIn[0] > 0 && udpIn[0] < 5 && receiveDirect) //1 warls //2 drgb //3 drgbw
|
||||
//apply effects from notification
|
||||
if (udpIn[11] < 200 && (receiveNotificationEffects || !someSel))
|
||||
{
|
||||
realtimeIP = notifierUdp.remoteIP();
|
||||
DEBUG_PRINTLN(notifierUdp.remoteIP());
|
||||
if (packetSize < 2) return;
|
||||
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
|
||||
effectSpeed = udpIn[9];
|
||||
if (udpIn[11] > 2) effectIntensity = udpIn[16];
|
||||
if (udpIn[11] > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19];
|
||||
}
|
||||
|
||||
if (udpIn[11] > 3)
|
||||
{
|
||||
transitionDelayTemp = ((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00);
|
||||
}
|
||||
|
||||
if (udpIn[1] == 0)
|
||||
nightlightActive = udpIn[6];
|
||||
if (nightlightActive) nightlightDelayMins = udpIn[7];
|
||||
|
||||
if (receiveNotificationBrightness || !someSel) bri = udpIn[2];
|
||||
colorUpdated(NOTIFIER_CALL_MODE_NOTIFICATION);
|
||||
|
||||
}
|
||||
if (!receiveDirect) return;
|
||||
|
||||
//TPM2.NET
|
||||
if (udpIn[0] == 0x9c)
|
||||
{
|
||||
//WARNING: this code assumes that the final TMP2.NET payload is evenly distributed if using multiple packets (ie. frame size is constant)
|
||||
//if the number of LEDs in your installation doesn't allow that, please include padding bytes at the end of the last packet
|
||||
byte tpmType = udpIn[1];
|
||||
if (tpmType == 0xaa) { //TPM2.NET polling, expect answer
|
||||
sendTPM2Ack(); return;
|
||||
}
|
||||
if (tpmType != 0xda) return; //return if notTPM2.NET data
|
||||
|
||||
realtimeIP = notifierUdp.remoteIP();
|
||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_TPM2NET);
|
||||
if (realtimeOverride) return;
|
||||
|
||||
tpmPacketCount++; //increment the packet count
|
||||
if (tpmPacketCount == 1) tpmPayloadFrameSize = (udpIn[2] << 8) + udpIn[3]; //save frame size for the whole payload if this is the first packet
|
||||
byte packetNum = udpIn[4]; //starts with 1!
|
||||
byte numPackets = udpIn[5];
|
||||
|
||||
uint16_t id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
|
||||
for (uint16_t i = 6; i < tpmPayloadFrameSize + 4; i += 3)
|
||||
{
|
||||
if (id < ledCount)
|
||||
{
|
||||
realtimeTimeout = 0;
|
||||
return;
|
||||
} else {
|
||||
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
|
||||
}
|
||||
if (realtimeOverride) return;
|
||||
|
||||
if (udpIn[0] == 1) //warls
|
||||
{
|
||||
for (uint16_t i = 2; i < packetSize -3; i += 4)
|
||||
{
|
||||
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
|
||||
}
|
||||
} else if (udpIn[0] == 2) //drgb
|
||||
{
|
||||
uint16_t id = 0;
|
||||
for (uint16_t i = 2; i < packetSize -2; i += 3)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
|
||||
id++; if (id >= ledCount) break;
|
||||
}
|
||||
} else if (udpIn[0] == 3) //drgbw
|
||||
{
|
||||
uint16_t id = 0;
|
||||
for (uint16_t i = 2; i < packetSize -3; i += 4)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
|
||||
|
||||
id++; if (id >= ledCount) break;
|
||||
}
|
||||
} else if (udpIn[0] == 4) //dnrgb
|
||||
{
|
||||
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
|
||||
for (uint16_t i = 4; i < packetSize -2; i += 3)
|
||||
{
|
||||
if (id >= ledCount) break;
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
id++;
|
||||
}
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
id++;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (tpmPacketCount == numPackets) //reset packet count and show if all packets were received
|
||||
{
|
||||
tpmPacketCount = 0;
|
||||
strip.show();
|
||||
}
|
||||
}
|
||||
|
||||
//UDP realtime: 1 warls 2 drgb 3 drgbw
|
||||
if (udpIn[0] > 0 && udpIn[0] < 5)
|
||||
{
|
||||
realtimeIP = notifierUdp.remoteIP();
|
||||
DEBUG_PRINTLN(notifierUdp.remoteIP());
|
||||
if (packetSize < 2) return;
|
||||
|
||||
if (udpIn[1] == 0)
|
||||
{
|
||||
realtimeTimeout = 0;
|
||||
return;
|
||||
} else {
|
||||
realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP);
|
||||
}
|
||||
if (realtimeOverride) return;
|
||||
|
||||
if (udpIn[0] == 1) //warls
|
||||
{
|
||||
for (uint16_t i = 2; i < packetSize -3; i += 4)
|
||||
{
|
||||
setRealtimePixel(udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3], 0);
|
||||
}
|
||||
} else if (udpIn[0] == 2) //drgb
|
||||
{
|
||||
uint16_t id = 0;
|
||||
for (uint16_t i = 2; i < packetSize -2; i += 3)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
|
||||
id++; if (id >= ledCount) break;
|
||||
}
|
||||
} else if (udpIn[0] == 3) //drgbw
|
||||
{
|
||||
uint16_t id = 0;
|
||||
for (uint16_t i = 2; i < packetSize -3; i += 4)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
|
||||
|
||||
id++; if (id >= ledCount) break;
|
||||
}
|
||||
} else if (udpIn[0] == 4) //dnrgb
|
||||
{
|
||||
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
|
||||
for (uint16_t i = 4; i < packetSize -2; i += 3)
|
||||
{
|
||||
if (id >= ledCount) break;
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
id++;
|
||||
}
|
||||
}
|
||||
strip.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
23
wled00/um_manager.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "wled.h"
|
||||
/*
|
||||
* Registration and management utility for v2 usermods
|
||||
*/
|
||||
|
||||
//Usermod Manager internals
|
||||
void UsermodManager::loop() { for (byte i = 0; i < numMods; i++) ums[i]->loop(); }
|
||||
|
||||
void UsermodManager::setup() { for (byte i = 0; i < numMods; i++) ums[i]->setup(); }
|
||||
void UsermodManager::connected() { for (byte i = 0; i < numMods; i++) ums[i]->connected(); }
|
||||
|
||||
void UsermodManager::addToJsonState(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToJsonState(obj); }
|
||||
void UsermodManager::addToJsonInfo(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToJsonInfo(obj); }
|
||||
void UsermodManager::readFromJsonState(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->readFromJsonState(obj); }
|
||||
|
||||
bool UsermodManager::add(Usermod* um)
|
||||
{
|
||||
if (numMods >= WLED_MAX_USERMODS || um == nullptr) return false;
|
||||
ums[numMods] = um;
|
||||
numMods++;
|
||||
}
|
||||
|
||||
byte UsermodManager::getModCount() {return numMods;}
|
@ -1,9 +1,11 @@
|
||||
#include "wled.h"
|
||||
/*
|
||||
* This file allows you to add own functionality to WLED more easily
|
||||
* 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)
|
||||
* bytes 2400+ are currently ununsed, but might be used for future wled features
|
||||
* 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)
|
||||
|
18
wled00/usermod_v2_empty.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "wled.h"
|
||||
|
||||
//This is an empty v2 usermod template. Please see the file usermod_v2_example.h in the EXAMPLE_v2 usermod folder for documentation on the functions you can use!
|
||||
|
||||
class UsermodRenameMe : public Usermod {
|
||||
private:
|
||||
|
||||
public:
|
||||
void setup() {
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
}
|
||||
};
|
26
wled00/usermods_list.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#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"
|
||||
|
||||
void registerUsermods()
|
||||
{
|
||||
/*
|
||||
* Add your usermod class name here
|
||||
* || || ||
|
||||
* \/ \/ \/
|
||||
*/
|
||||
//usermods.add(new MyExampleUsermod());
|
||||
//usermods.add(new UsermodTemperature());
|
||||
//usermods.add(new UsermodRenameMe());
|
||||
}
|
@ -14,8 +14,11 @@ WLED::WLED()
|
||||
void WLED::reset()
|
||||
{
|
||||
briT = 0;
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
ws.closeAll(1012);
|
||||
#endif
|
||||
long dly = millis();
|
||||
while (millis() - dly < 250) {
|
||||
while (millis() - dly < 450) {
|
||||
yield(); // enough time to send response to client
|
||||
}
|
||||
setAllLeds();
|
||||
@ -51,6 +54,7 @@ void WLED::loop()
|
||||
handleDMX();
|
||||
#endif
|
||||
userLoop();
|
||||
usermods.loop();
|
||||
|
||||
yield();
|
||||
handleIO();
|
||||
@ -101,36 +105,31 @@ void WLED::loop()
|
||||
if (lastMqttReconnectAttempt > millis()) rolloverMillis++; //millis() rolls over every 50 days
|
||||
initMqtt();
|
||||
}
|
||||
yield();
|
||||
handleWs();
|
||||
|
||||
// DEBUG serial logging
|
||||
#ifdef WLED_DEBUG
|
||||
if (millis() - debugTime > 9999) {
|
||||
DEBUG_PRINTLN("---DEBUG INFO---");
|
||||
DEBUG_PRINT("Runtime: ");
|
||||
DEBUG_PRINTLN(millis());
|
||||
DEBUG_PRINT("Unix time: ");
|
||||
DEBUG_PRINTLN(now());
|
||||
DEBUG_PRINT("Free heap: ");
|
||||
DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
DEBUG_PRINT("Wifi state: ");
|
||||
DEBUG_PRINTLN(WiFi.status());
|
||||
DEBUG_PRINT("Runtime: "); DEBUG_PRINTLN(millis());
|
||||
DEBUG_PRINT("Unix time: "); DEBUG_PRINTLN(now());
|
||||
DEBUG_PRINT("Free heap: "); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
DEBUG_PRINT("Wifi state: "); DEBUG_PRINTLN(WiFi.status());
|
||||
|
||||
if (WiFi.status() != lastWifiState) {
|
||||
wifiStateChangedTime = millis();
|
||||
}
|
||||
lastWifiState = WiFi.status();
|
||||
DEBUG_PRINT("State time: ");
|
||||
DEBUG_PRINTLN(wifiStateChangedTime);
|
||||
DEBUG_PRINT("NTP last sync: ");
|
||||
DEBUG_PRINTLN(ntpLastSyncTime);
|
||||
DEBUG_PRINT("Client IP: ");
|
||||
DEBUG_PRINTLN(WiFi.localIP());
|
||||
DEBUG_PRINT("Loops/sec: ");
|
||||
DEBUG_PRINTLN(loops / 10);
|
||||
DEBUG_PRINT("State time: "); DEBUG_PRINTLN(wifiStateChangedTime);
|
||||
DEBUG_PRINT("NTP last sync: "); DEBUG_PRINTLN(ntpLastSyncTime);
|
||||
DEBUG_PRINT("Client IP: "); DEBUG_PRINTLN(WiFi.localIP());
|
||||
DEBUG_PRINT("Loops/sec: "); DEBUG_PRINTLN(loops / 10);
|
||||
loops = 0;
|
||||
debugTime = millis();
|
||||
}
|
||||
loops++;
|
||||
#endif // WLED_DEBU
|
||||
#endif // WLED_DEBUG
|
||||
}
|
||||
|
||||
void WLED::setup()
|
||||
@ -164,6 +163,7 @@ void WLED::setup()
|
||||
int heapPreAlloc = ESP.getFreeHeap();
|
||||
DEBUG_PRINT("heap ");
|
||||
DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
registerUsermods();
|
||||
|
||||
strip.init(EEPROM.read(372), ledCount, EEPROM.read(2204)); // init LEDs quickly
|
||||
strip.setBrightness(0);
|
||||
@ -182,6 +182,7 @@ void WLED::setup()
|
||||
loadSettingsFromEEPROM(true);
|
||||
beginStrip();
|
||||
userSetup();
|
||||
usermods.setup();
|
||||
if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0)
|
||||
showWelcomePage = true;
|
||||
WiFi.persistent(false);
|
||||
@ -294,6 +295,10 @@ void WLED::initAP(bool resetAP)
|
||||
|
||||
void WLED::initConnection()
|
||||
{
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
ws.onEvent(wsEvent);
|
||||
#endif
|
||||
|
||||
WiFi.disconnect(true); // close old connections
|
||||
#ifdef ESP8266
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||
@ -327,15 +332,41 @@ void WLED::initConnection()
|
||||
DEBUG_PRINT(clientSSID);
|
||||
DEBUG_PRINTLN("...");
|
||||
|
||||
// convert the "serverDescription" into a valid DNS hostname (alphanumeric)
|
||||
char hostname[25] = "wled-";
|
||||
const char *pC = serverDescription;
|
||||
uint8_t pos = 5;
|
||||
|
||||
while (*pC && pos < 24) { // while !null and not over length
|
||||
if (isalnum(*pC)) { // if the current char is alpha-numeric append it to the hostname
|
||||
hostname[pos] = *pC;
|
||||
pos++;
|
||||
} else if (*pC == ' ' || *pC == '_' || *pC == '-' || *pC == '+' || *pC == '!' || *pC == '?' || *pC == '*') {
|
||||
hostname[pos] = '-';
|
||||
pos++;
|
||||
}
|
||||
// else do nothing - no leading hyphens and do not include hyphens for all other characters.
|
||||
pC++;
|
||||
}
|
||||
// if the hostname is left blank, use the mac address/default mdns name
|
||||
if (pos < 6) {
|
||||
sprintf(hostname + 5, "%*s", 6, escapedMac.c_str() + 6);
|
||||
} else { //last character must not be hyphen
|
||||
while (pos > 0 && hostname[pos -1] == '-') {
|
||||
hostname[pos -1] = 0;
|
||||
pos--;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ESP8266
|
||||
WiFi.hostname(serverDescription);
|
||||
WiFi.hostname(hostname);
|
||||
#endif
|
||||
|
||||
WiFi.begin(clientSSID, clientPass);
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
WiFi.setSleep(!noWifiSleep);
|
||||
WiFi.setHostname(serverDescription);
|
||||
WiFi.setHostname(hostname);
|
||||
#else
|
||||
wifi_set_sleep_type((noWifiSleep) ? NONE_SLEEP_T : MODEM_SLEEP_T);
|
||||
#endif
|
||||
@ -363,8 +394,12 @@ void WLED::initInterfaces()
|
||||
strip.service();
|
||||
// Set up mDNS responder:
|
||||
if (strlen(cmDNS) > 0) {
|
||||
if (!aOtaEnabled)
|
||||
#ifndef WLED_DISABLE_OTA
|
||||
if (!aOtaEnabled) //ArduinoOTA begins mDNS for us if enabled
|
||||
MDNS.begin(cmDNS);
|
||||
#else
|
||||
MDNS.begin(cmDNS);
|
||||
#endif
|
||||
|
||||
DEBUG_PRINTLN("mDNS started");
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
@ -457,6 +492,7 @@ void WLED::handleConnection()
|
||||
DEBUG_PRINTLN(WiFi.localIP());
|
||||
initInterfaces();
|
||||
userConnected();
|
||||
usermods.connected();
|
||||
|
||||
// shut down AP
|
||||
if (apBehavior != AP_BEHAVIOR_ALWAYS && apActive) {
|
||||
|
@ -3,12 +3,12 @@
|
||||
/*
|
||||
Main sketch, global variable declarations
|
||||
@title WLED project sketch
|
||||
@version 0.10.0
|
||||
@version 0.10.2
|
||||
@author Christian Schwinne
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2005030
|
||||
#define VERSION 2009030
|
||||
|
||||
// ESP8266-01 (blue) got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.4.2 and the setting 512K(No SPIFFS).
|
||||
|
||||
@ -25,9 +25,14 @@
|
||||
//#define WLED_DISABLE_CRONIXIE // saves 3kb
|
||||
//#define WLED_DISABLE_HUESYNC // saves 4kb
|
||||
//#define WLED_DISABLE_INFRARED // there is no pin left for this on ESP8266-01, saves 12kb
|
||||
#define WLED_ENABLE_MQTT // saves 12kb
|
||||
#ifndef WLED_DISABLE_MQTT
|
||||
#define WLED_ENABLE_MQTT // saves 12kb
|
||||
#endif
|
||||
#define WLED_ENABLE_ADALIGHT // saves 500b only
|
||||
//#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2)
|
||||
#ifndef WLED_DISABLE_WEBSOCKETS
|
||||
#define WLED_ENABLE_WEBSOCKETS
|
||||
#endif
|
||||
|
||||
//#define WLED_DISABLE_FILESYSTEM // SPIFFS is not used by any WLED feature yet
|
||||
#define WLED_ENABLE_FS_SERVING // Enable sending html file from SPIFFS before serving progmem version
|
||||
@ -76,6 +81,10 @@
|
||||
#include "src/dependencies/blynk/BlynkSimpleEsp.h"
|
||||
#endif
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
#include "src/dependencies/dmx/ESPDMX.h"
|
||||
#endif
|
||||
|
||||
#include "src/dependencies/e131/ESPAsyncE131.h"
|
||||
#include "src/dependencies/async-mqtt-client/AsyncMqttClient.h"
|
||||
#include "src/dependencies/json/AsyncJson-v6.h"
|
||||
@ -109,10 +118,10 @@
|
||||
#include <IRutils.h>
|
||||
#endif
|
||||
|
||||
// remove flicker because PWM signal of RGB channels can become out of phase
|
||||
#if defined(WLED_USE_ANALOG_LEDS) && defined(ESP8266)
|
||||
#include "src/dependencies/arduino/core_esp8266_waveform.h"
|
||||
#endif
|
||||
// remove flicker because PWM signal of RGB channels can become out of phase (part of core as of Arduino core v2.7.0)
|
||||
//#if defined(WLED_USE_ANALOG_LEDS) && defined(ESP8266)
|
||||
// #include "src/dependencies/arduino/core_esp8266_waveform.h"
|
||||
//#endif
|
||||
|
||||
// enable additional debug output
|
||||
#ifdef WLED_DEBUG
|
||||
@ -148,8 +157,8 @@
|
||||
#endif
|
||||
|
||||
// Global Variable definitions
|
||||
WLED_GLOBAL char versionString[] _INIT("0.10.0");
|
||||
#define WLED_CODENAME "Namigai"
|
||||
WLED_GLOBAL char versionString[] _INIT("0.10.2");
|
||||
#define WLED_CODENAME "Fumikiri"
|
||||
|
||||
// AP and OTA default passwords (for maximum security change them!)
|
||||
WLED_GLOBAL char apPass[65] _INIT(DEFAULT_AP_PASS);
|
||||
@ -189,8 +198,7 @@ WLED_GLOBAL byte briS _INIT(128); // default brightness
|
||||
|
||||
WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlight is over
|
||||
WLED_GLOBAL byte nightlightDelayMins _INIT(60);
|
||||
WLED_GLOBAL bool nightlightFade _INIT(true); // if enabled, light will gradually dim towards the target bri. Otherwise, it will instantly set after delay over
|
||||
WLED_GLOBAL bool nightlightColorFade _INIT(false); // if enabled, light will gradually fade color from primary to secondary color.
|
||||
WLED_GLOBAL byte nightlightMode _INIT(NL_MODE_FADE); // See const.h for available modes. Was nightlightFade
|
||||
WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading color transition
|
||||
WLED_GLOBAL uint16_t transitionDelay _INIT(750); // default crossfade duration in ms
|
||||
|
||||
@ -218,7 +226,7 @@ WLED_GLOBAL bool notifyMacro _INIT(false); // send notifi
|
||||
WLED_GLOBAL bool notifyHue _INIT(true); // send notification if Hue light changes
|
||||
WLED_GLOBAL bool notifyTwice _INIT(false); // notifications use UDP: enable if devices don't sync reliably
|
||||
|
||||
WLED_GLOBAL bool alexaEnabled _INIT(true); // enable device discovery by Amazon Echo
|
||||
WLED_GLOBAL bool alexaEnabled _INIT(false); // enable device discovery by Amazon Echo
|
||||
WLED_GLOBAL char alexaInvocationName[33] _INIT("Light"); // speech control name of device. Choose something voice-to-text can understand
|
||||
|
||||
WLED_GLOBAL char blynkApiKey[36] _INIT(""); // Auth token for Blynk server. If empty, no connection will be made
|
||||
@ -229,6 +237,10 @@ WLED_GLOBAL bool receiveDirect _INIT(true); // receive UDP
|
||||
WLED_GLOBAL bool arlsDisableGammaCorrection _INIT(true); // activate if gamma correction is handled by the source
|
||||
WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to force max brightness if source has very dark colors that would be black
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
WLED_GLOBAL DMXESPSerial dmx;
|
||||
WLED_GLOBAL uint16_t e131ProxyUniverse _INIT(0); // output this E1.31 (sACN) / ArtNet universe via MAX485 (0 = disabled)
|
||||
#endif
|
||||
WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings for E1.31 (sACN) protocol (only DMX_MODE_MULTIPLE_* can span over consequtive universes)
|
||||
WLED_GLOBAL uint16_t e131Port _INIT(5568); // DMX in port. E1.31 default is 5568, Art-Net is 6454
|
||||
WLED_GLOBAL byte DMXMode _INIT(DMX_MODE_MULTIPLE_RGB); // DMX mode (s.a.)
|
||||
@ -409,7 +421,7 @@ WLED_GLOBAL bool blynkEnabled _INIT(false);
|
||||
// preset cycling
|
||||
WLED_GLOBAL bool presetCyclingEnabled _INIT(false);
|
||||
WLED_GLOBAL byte presetCycleMin _INIT(1), presetCycleMax _INIT(5);
|
||||
WLED_GLOBAL uint16_t presetCycleTime _INIT(1250);
|
||||
WLED_GLOBAL uint16_t presetCycleTime _INIT(12);
|
||||
WLED_GLOBAL unsigned long presetCycledTime _INIT(0);
|
||||
WLED_GLOBAL byte presetCycCurr _INIT(presetCycleMin);
|
||||
WLED_GLOBAL bool presetApplyBri _INIT(true);
|
||||
@ -420,6 +432,8 @@ WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE);
|
||||
WLED_GLOBAL byte realtimeOverride _INIT(REALTIME_OVERRIDE_NONE);
|
||||
WLED_GLOBAL IPAddress realtimeIP _INIT((0, 0, 0, 0));
|
||||
WLED_GLOBAL unsigned long realtimeTimeout _INIT(0);
|
||||
WLED_GLOBAL uint8_t tpmPacketCount _INIT(0);
|
||||
WLED_GLOBAL uint16_t tpmPayloadFrameSize _INIT(0);
|
||||
|
||||
// mqtt
|
||||
WLED_GLOBAL long lastMqttReconnectAttempt _INIT(0);
|
||||
@ -446,7 +460,7 @@ WLED_GLOBAL DNSServer dnsServer;
|
||||
|
||||
// network time
|
||||
WLED_GLOBAL bool ntpConnected _INIT(false);
|
||||
WLED_GLOBAL time_t local _INIT(0);
|
||||
WLED_GLOBAL time_t localTime _INIT(0);
|
||||
WLED_GLOBAL unsigned long ntpLastSyncTime _INIT(999000000L);
|
||||
WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(999000000L);
|
||||
WLED_GLOBAL IPAddress ntpServerIP;
|
||||
@ -472,6 +486,9 @@ WLED_GLOBAL bool doPublishMqtt _INIT(false);
|
||||
|
||||
// server library objects
|
||||
WLED_GLOBAL AsyncWebServer server _INIT_N(((80)));
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
WLED_GLOBAL AsyncWebSocket ws _INIT_N((("/ws")));
|
||||
#endif
|
||||
WLED_GLOBAL AsyncClient* hueClient _INIT(NULL);
|
||||
WLED_GLOBAL AsyncMqttClient* mqtt _INIT(NULL);
|
||||
|
||||
@ -484,6 +501,9 @@ WLED_GLOBAL bool e131NewData _INIT(false);
|
||||
// led fx library object
|
||||
WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
|
||||
|
||||
// Usermod manager
|
||||
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
|
||||
|
||||
// debug macro variable definitions
|
||||
#ifdef WLED_DEBUG
|
||||
WLED_GLOBAL unsigned long debugTime _INIT(0);
|
||||
@ -495,6 +515,7 @@ WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
|
||||
|
||||
#define WLED_CONNECTED (WiFi.status() == WL_CONNECTED)
|
||||
#define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID, DEFAULT_CLIENT_SSID) != 0)
|
||||
#define WLED_MQTT_CONNECTED (mqtt != nullptr && mqtt->connected())
|
||||
|
||||
// append new c string to temp buffer efficiently
|
||||
bool oappend(const char* txt);
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
//eeprom Version code, enables default settings instead of 0 init on update
|
||||
#define EEPVER 19
|
||||
#define EEPVER 21
|
||||
//0 -> old version, default
|
||||
//1 -> 0.4p 1711272 and up
|
||||
//2 -> 0.4p 1711302 and up
|
||||
@ -28,6 +28,8 @@
|
||||
//17-> 0.9.1-dmx
|
||||
//18-> 0.9.1-e131
|
||||
//19-> 0.9.1n
|
||||
//20-> 0.9.1p
|
||||
//21-> 0.10.1p
|
||||
|
||||
void commit()
|
||||
{
|
||||
@ -85,7 +87,7 @@ void saveSettingsToEEPROM()
|
||||
writeStringToEEPROM(160, apPass, 64);
|
||||
|
||||
EEPROM.write(224, nightlightDelayMinsDefault);
|
||||
EEPROM.write(225, nightlightFade);
|
||||
EEPROM.write(225, nightlightMode);
|
||||
EEPROM.write(226, notifyDirectDefault);
|
||||
EEPROM.write(227, apChannel);
|
||||
EEPROM.write(228, apHide);
|
||||
@ -211,6 +213,11 @@ void saveSettingsToEEPROM()
|
||||
EEPROM.write(2181, macroNl);
|
||||
EEPROM.write(2182, macroDoublePress);
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
EEPROM.write(2185, e131ProxyUniverse & 0xFF);
|
||||
EEPROM.write(2186, (e131ProxyUniverse >> 8) & 0xFF);
|
||||
#endif
|
||||
|
||||
EEPROM.write(2187, e131Port & 0xFF);
|
||||
EEPROM.write(2188, (e131Port >> 8) & 0xFF);
|
||||
|
||||
@ -304,7 +311,7 @@ void loadSettingsFromEEPROM(bool first)
|
||||
|
||||
nightlightDelayMinsDefault = EEPROM.read(224);
|
||||
nightlightDelayMins = nightlightDelayMinsDefault;
|
||||
nightlightFade = EEPROM.read(225);
|
||||
nightlightMode = EEPROM.read(225);
|
||||
notifyDirectDefault = EEPROM.read(226);
|
||||
notifyDirect = notifyDirectDefault;
|
||||
|
||||
@ -524,6 +531,13 @@ void loadSettingsFromEEPROM(bool first)
|
||||
e131Port = EEPROM.read(2187) + ((EEPROM.read(2188) << 8) & 0xFF00);
|
||||
}
|
||||
|
||||
#ifdef WLED_ENABLE_DMX
|
||||
if (lastEEPROMversion > 19)
|
||||
{
|
||||
e131ProxyUniverse = EEPROM.read(2185) + ((EEPROM.read(2186) << 8) & 0xFF00);
|
||||
}
|
||||
#endif
|
||||
|
||||
receiveDirect = !EEPROM.read(2200);
|
||||
notifyMacro = EEPROM.read(2201);
|
||||
|
||||
@ -534,6 +548,7 @@ void loadSettingsFromEEPROM(bool first)
|
||||
{
|
||||
presetCyclingEnabled = EEPROM.read(2205);
|
||||
presetCycleTime = EEPROM.read(2206) + ((EEPROM.read(2207) << 8) & 0xFF00);
|
||||
if (lastEEPROMversion < 21) presetCycleTime /= 100; //was stored in ms, now is in tenths of a second
|
||||
presetCycleMin = EEPROM.read(2208);
|
||||
presetCycleMax = EEPROM.read(2209);
|
||||
presetApplyBri = EEPROM.read(2210);
|
||||
@ -568,8 +583,10 @@ void loadSettingsFromEEPROM(bool first)
|
||||
EEPROM.write(2550, DMXStartLED);
|
||||
#endif
|
||||
|
||||
//user MOD memory
|
||||
//2944 - 3071 reserved
|
||||
//Usermod memory
|
||||
//2551 - 2559 reserved for Usermods, usable by default
|
||||
//2560 - 2943 usable, NOT reserved (need to increase EEPSIZE accordingly, new WLED core features may override this section)
|
||||
//2944 - 3071 reserved for Usermods (need to increase EEPSIZE to 3072 in const.h)
|
||||
|
||||
overlayCurrent = overlayDefault;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* Adalight handler
|
||||
* Adalight and TPM2 handler
|
||||
*/
|
||||
|
||||
enum class AdaState {
|
||||
@ -13,7 +13,10 @@ enum class AdaState {
|
||||
Header_CountCheck,
|
||||
Data_Red,
|
||||
Data_Green,
|
||||
Data_Blue
|
||||
Data_Blue,
|
||||
TPM2_Header_Type,
|
||||
TPM2_Header_CountHi,
|
||||
TPM2_Header_CountLo
|
||||
};
|
||||
|
||||
void handleSerial()
|
||||
@ -33,6 +36,9 @@ void handleSerial()
|
||||
switch (state) {
|
||||
case AdaState::Header_A:
|
||||
if (next == 'A') state = AdaState::Header_d;
|
||||
else if (next == 0xC9) { //TPM2 start byte
|
||||
state = AdaState::TPM2_Header_Type;
|
||||
}
|
||||
break;
|
||||
case AdaState::Header_d:
|
||||
if (next == 'd') state = AdaState::Header_a;
|
||||
@ -57,6 +63,20 @@ void handleSerial()
|
||||
if (check == next) state = AdaState::Data_Red;
|
||||
else state = AdaState::Header_A;
|
||||
break;
|
||||
case AdaState::TPM2_Header_Type:
|
||||
state = AdaState::Header_A; //(unsupported) TPM2 command or invalid type
|
||||
if (next == 0xDA) state = AdaState::TPM2_Header_CountHi; //TPM2 data
|
||||
else if (next == 0xAA) Serial.write(0xAC); //TPM2 ping
|
||||
break;
|
||||
case AdaState::TPM2_Header_CountHi:
|
||||
pixel = 0;
|
||||
count = (next * 0x100) /3;
|
||||
state = AdaState::TPM2_Header_CountLo;
|
||||
break;
|
||||
case AdaState::TPM2_Header_CountLo:
|
||||
count += next /3;
|
||||
state = AdaState::Data_Red;
|
||||
break;
|
||||
case AdaState::Data_Red:
|
||||
red = next;
|
||||
state = AdaState::Data_Green;
|
||||
|
@ -205,10 +205,10 @@ void initServer()
|
||||
} else
|
||||
{
|
||||
server.on("/edit", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveMessage(request, 500, "Access Denied", "Please unlock OTA in security settings!", 254);
|
||||
serveMessage(request, 500, "Access Denied", F("Please unlock OTA in security settings!"), 254);
|
||||
});
|
||||
server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
serveMessage(request, 500, "Access Denied", "Please unlock OTA in security settings!", 254);
|
||||
serveMessage(request, 500, "Access Denied", F("Please unlock OTA in security settings!"), 254);
|
||||
});
|
||||
}
|
||||
|
||||
@ -226,6 +226,10 @@ void initServer()
|
||||
if (captivePortal(request)) return;
|
||||
serveIndexOrWelcome(request);
|
||||
});
|
||||
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
server.addHandler(&ws);
|
||||
#endif
|
||||
|
||||
//called when the url is not defined here, ajax-in; get-settings
|
||||
server.onNotFound([](AsyncWebServerRequest *request){
|
||||
@ -374,7 +378,7 @@ void serveSettings(AsyncWebServerRequest* request)
|
||||
|
||||
if (subPage == 1 && wifiLock && otaLock)
|
||||
{
|
||||
serveMessage(request, 500, "Access Denied", "Please unlock OTA in security settings!", 254); return;
|
||||
serveMessage(request, 500, "Access Denied", F("Please unlock OTA in security settings!"), 254); return;
|
||||
}
|
||||
|
||||
#ifdef WLED_DISABLE_MOBILE_UI //disable welcome page if not enough storage
|
||||
|
114
wled00/ws.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
#include "wled.h"
|
||||
|
||||
/*
|
||||
* WebSockets server for bidirectional communication
|
||||
*/
|
||||
#ifdef WLED_ENABLE_WEBSOCKETS
|
||||
|
||||
uint16_t wsLiveClientId = 0;
|
||||
unsigned long wsLastLiveTime = 0;
|
||||
//uint8_t* wsFrameBuffer = nullptr;
|
||||
|
||||
#define WS_LIVE_INTERVAL 40
|
||||
|
||||
void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)
|
||||
{
|
||||
if(type == WS_EVT_CONNECT){
|
||||
//client connected
|
||||
sendDataWs(client);
|
||||
//client->ping();
|
||||
} else if(type == WS_EVT_DISCONNECT){
|
||||
//client disconnected
|
||||
if (client->id() == wsLiveClientId) wsLiveClientId = 0;
|
||||
} else if(type == WS_EVT_DATA){
|
||||
//data packet
|
||||
AwsFrameInfo * info = (AwsFrameInfo*)arg;
|
||||
if(info->final && info->index == 0 && info->len == len){
|
||||
//the whole message is in a single frame and we got all of it's data (max. 1450byte)
|
||||
if(info->opcode == WS_TEXT)
|
||||
{
|
||||
bool verboseResponse = false;
|
||||
{ //scope JsonDocument so it releases its buffer
|
||||
DynamicJsonDocument jsonBuffer(8192);
|
||||
DeserializationError error = deserializeJson(jsonBuffer, data, len);
|
||||
JsonObject root = jsonBuffer.as<JsonObject>();
|
||||
if (error || root.isNull()) return;
|
||||
|
||||
if (root.containsKey("lv"))
|
||||
{
|
||||
wsLiveClientId = root["lv"] ? client->id() : 0;
|
||||
}
|
||||
|
||||
verboseResponse = deserializeState(root);
|
||||
}
|
||||
if (verboseResponse || millis() - lastInterfaceUpdate < 1900) sendDataWs(client); //update if it takes longer than 100ms until next "broadcast"
|
||||
}
|
||||
} else {
|
||||
//message is comprised of multiple frames or the frame is split into multiple packets
|
||||
//if(info->index == 0){
|
||||
//if (!wsFrameBuffer && len < 4096) wsFrameBuffer = new uint8_t[4096];
|
||||
//}
|
||||
|
||||
//if (wsFrameBuffer && len < 4096 && info->index + info->)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
if((info->index + len) == info->len){
|
||||
if(info->final){
|
||||
if(info->message_opcode == WS_TEXT) {
|
||||
client->text("{\"error\":10}"); //we do not handle split packets right now
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(type == WS_EVT_ERROR){
|
||||
//error was received from the other end
|
||||
|
||||
} else if(type == WS_EVT_PONG){
|
||||
//pong message was received (in response to a ping request maybe)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void sendDataWs(AsyncWebSocketClient * client)
|
||||
{
|
||||
if (!ws.count()) return;
|
||||
AsyncWebSocketMessageBuffer * buffer;
|
||||
|
||||
{ //scope JsonDocument so it releases its buffer
|
||||
DynamicJsonDocument doc(8192);
|
||||
JsonObject state = doc.createNestedObject("state");
|
||||
serializeState(state);
|
||||
JsonObject info = doc.createNestedObject("info");
|
||||
serializeInfo(info);
|
||||
size_t len = measureJson(doc);
|
||||
buffer = ws.makeBuffer(len);
|
||||
if (!buffer) return; //out of memory
|
||||
|
||||
serializeJson(doc, (char *)buffer->get(), len +1);
|
||||
}
|
||||
if (client) {
|
||||
client->text(buffer);
|
||||
} else {
|
||||
ws.textAll(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void handleWs()
|
||||
{
|
||||
if (millis() - wsLastLiveTime > WS_LIVE_INTERVAL)
|
||||
{
|
||||
ws.cleanupClients();
|
||||
bool success = true;
|
||||
if (wsLiveClientId)
|
||||
success = serveLiveLeds(nullptr, wsLiveClientId);
|
||||
wsLastLiveTime = millis();
|
||||
if (!success) wsLastLiveTime -= 20; //try again in 20ms if failed due to non-empty WS queue
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
void handleWs() {}
|
||||
void sendDataWs(AsyncWebSocketClient * client) {}
|
||||
#endif
|
@ -5,14 +5,14 @@
|
||||
*/
|
||||
|
||||
//build XML response to HTTP /win API request
|
||||
char* XML_response(AsyncWebServerRequest *request, char* dest)
|
||||
void XML_response(AsyncWebServerRequest *request, char* dest)
|
||||
{
|
||||
char sbuf[(dest == nullptr)?1024:1]; //allocate local buffer if none passed
|
||||
obuf = (dest == nullptr)? sbuf:dest;
|
||||
|
||||
olen = 0;
|
||||
oappend((const char*)F("<?xml version=\"1.0\" ?><vs><ac>"));
|
||||
oappendi((nightlightActive && nightlightFade) ? briT : bri);
|
||||
oappendi((nightlightActive && nightlightMode > NL_MODE_SET) ? briT : bri);
|
||||
oappend("</ac>");
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
@ -34,7 +34,7 @@ char* XML_response(AsyncWebServerRequest *request, char* dest)
|
||||
oappend("</nr><nl>");
|
||||
oappendi(nightlightActive);
|
||||
oappend("</nl><nf>");
|
||||
oappendi(nightlightFade);
|
||||
oappendi(nightlightMode > NL_MODE_SET);
|
||||
oappend("</nf><nd>");
|
||||
oappendi(nightlightDelayMins);
|
||||
oappend("</nd><nt>");
|
||||
@ -60,39 +60,10 @@ char* XML_response(AsyncWebServerRequest *request, char* dest)
|
||||
oappend("</ps><cy>");
|
||||
oappendi(presetCyclingEnabled);
|
||||
oappend("</cy><ds>");
|
||||
oappend(serverDescription);
|
||||
if (realtimeMode)
|
||||
{
|
||||
String mesg = "Live ";
|
||||
if (realtimeMode == REALTIME_MODE_E131 || realtimeMode == REALTIME_MODE_ARTNET)
|
||||
{
|
||||
mesg += (realtimeMode == REALTIME_MODE_E131) ? "E1.31" : "Art-Net";
|
||||
mesg += " mode ";
|
||||
mesg += DMXMode;
|
||||
mesg += F(" at DMX Address ");
|
||||
mesg += DMXAddress;
|
||||
mesg += " from ";
|
||||
mesg += realtimeIP[0];
|
||||
for (int i = 1; i < 4; i++)
|
||||
{
|
||||
mesg += ".";
|
||||
mesg += realtimeIP[i];
|
||||
}
|
||||
} else if (realtimeMode == REALTIME_MODE_UDP || realtimeMode == REALTIME_MODE_HYPERION) {
|
||||
mesg += "UDP from ";
|
||||
mesg += realtimeIP[0];
|
||||
for (int i = 1; i < 4; i++)
|
||||
{
|
||||
mesg += ".";
|
||||
mesg += realtimeIP[i];
|
||||
}
|
||||
} else if (realtimeMode == REALTIME_MODE_ADALIGHT) {
|
||||
mesg += F("USB Adalight");
|
||||
} else { //generic
|
||||
mesg += "data";
|
||||
}
|
||||
oappend((char*)mesg.c_str());
|
||||
} else {
|
||||
oappend(serverDescription);
|
||||
oappend(" (live)");
|
||||
}
|
||||
oappend("</ds><ss>");
|
||||
oappendi(strip.getMainSegmentId());
|
||||
@ -100,9 +71,9 @@ char* XML_response(AsyncWebServerRequest *request, char* dest)
|
||||
if (request != nullptr) request->send(200, "text/xml", obuf);
|
||||
}
|
||||
|
||||
char* URL_response(AsyncWebServerRequest *request)
|
||||
void URL_response(AsyncWebServerRequest *request)
|
||||
{
|
||||
char sbuf[256]; //allocate local buffer if none passed
|
||||
char sbuf[256];
|
||||
char s2buf[100];
|
||||
obuf = s2buf;
|
||||
olen = 0;
|
||||
@ -301,7 +272,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',"BF",briMultiplier);
|
||||
sappend('v',"TB",nightlightTargetBri);
|
||||
sappend('v',"TL",nightlightDelayMinsDefault);
|
||||
sappend('c',"TW",nightlightFade);
|
||||
sappend('v',"TW",nightlightMode);
|
||||
sappend('i',"PB",strip.paletteBlend);
|
||||
sappend('c',"RV",strip.reverseMode);
|
||||
sappend('c',"SL",skipFirstLed);
|
||||
@ -456,6 +427,8 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
|
||||
if (subPage == 7)
|
||||
{
|
||||
sappend('v',"PU",e131ProxyUniverse);
|
||||
|
||||
sappend('v',"CN",DMXChannels);
|
||||
sappend('v',"CG",DMXGap);
|
||||
sappend('v',"CS",DMXStart);
|
||||
|