Project setup
This commit is contained in:
@@ -188,3 +188,5 @@ cython_debug/
|
|||||||
# Built Visual Studio Code Extensions
|
# Built Visual Studio Code Extensions
|
||||||
*.vsix
|
*.vsix
|
||||||
|
|
||||||
|
# Custom to this repo
|
||||||
|
buttonplus.yaml
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[[source]]
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
pyyaml = ">=6.0"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.12"
|
||||||
Generated
+101
@@ -0,0 +1,101 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "fe14101cf3766f9bbb7942a51a278b5dab6d277c4ac67ed1e09c2774ea4655a2"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.12"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"pyyaml": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c",
|
||||||
|
"sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a",
|
||||||
|
"sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3",
|
||||||
|
"sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956",
|
||||||
|
"sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6",
|
||||||
|
"sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c",
|
||||||
|
"sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65",
|
||||||
|
"sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a",
|
||||||
|
"sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0",
|
||||||
|
"sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b",
|
||||||
|
"sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1",
|
||||||
|
"sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6",
|
||||||
|
"sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7",
|
||||||
|
"sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e",
|
||||||
|
"sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007",
|
||||||
|
"sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310",
|
||||||
|
"sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4",
|
||||||
|
"sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9",
|
||||||
|
"sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295",
|
||||||
|
"sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea",
|
||||||
|
"sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0",
|
||||||
|
"sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e",
|
||||||
|
"sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac",
|
||||||
|
"sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9",
|
||||||
|
"sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7",
|
||||||
|
"sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35",
|
||||||
|
"sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb",
|
||||||
|
"sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b",
|
||||||
|
"sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69",
|
||||||
|
"sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5",
|
||||||
|
"sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b",
|
||||||
|
"sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c",
|
||||||
|
"sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369",
|
||||||
|
"sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd",
|
||||||
|
"sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824",
|
||||||
|
"sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198",
|
||||||
|
"sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065",
|
||||||
|
"sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c",
|
||||||
|
"sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c",
|
||||||
|
"sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764",
|
||||||
|
"sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196",
|
||||||
|
"sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b",
|
||||||
|
"sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00",
|
||||||
|
"sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac",
|
||||||
|
"sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8",
|
||||||
|
"sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e",
|
||||||
|
"sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28",
|
||||||
|
"sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3",
|
||||||
|
"sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5",
|
||||||
|
"sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4",
|
||||||
|
"sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b",
|
||||||
|
"sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf",
|
||||||
|
"sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5",
|
||||||
|
"sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702",
|
||||||
|
"sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8",
|
||||||
|
"sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788",
|
||||||
|
"sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da",
|
||||||
|
"sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d",
|
||||||
|
"sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc",
|
||||||
|
"sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c",
|
||||||
|
"sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba",
|
||||||
|
"sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f",
|
||||||
|
"sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917",
|
||||||
|
"sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5",
|
||||||
|
"sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26",
|
||||||
|
"sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f",
|
||||||
|
"sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b",
|
||||||
|
"sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be",
|
||||||
|
"sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c",
|
||||||
|
"sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3",
|
||||||
|
"sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6",
|
||||||
|
"sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926",
|
||||||
|
"sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"markers": "python_version >= '3.8'",
|
||||||
|
"version": "==6.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {}
|
||||||
|
}
|
||||||
@@ -1,3 +1,11 @@
|
|||||||
# buttonplus-esphome-generator
|
# buttonplus-esphome-generator
|
||||||
|
|
||||||
A python script that generates a full ESPHome config for the Button+ V2
|
A python script that generates a full ESPHome config for the Button+ V2
|
||||||
|
|
||||||
|
## Project uses pipenv
|
||||||
|
run `pipenv install` to setup the project the first time.
|
||||||
|
run `pipenv shell` after that to open the virtual environment.
|
||||||
|
You can then use `python
|
||||||
|
|
||||||
|
## Config example
|
||||||
|
The configuration (handmade) on which this generator is based, can be found in the `esphome` folder.
|
||||||
@@ -0,0 +1,304 @@
|
|||||||
|
packages:
|
||||||
|
base: !include ../common.yaml
|
||||||
|
scripts: !include scripts.yaml
|
||||||
|
events: !include events.yaml
|
||||||
|
|
||||||
|
esphome:
|
||||||
|
on_boot:
|
||||||
|
priority: -100
|
||||||
|
then:
|
||||||
|
- script.execute: setup_bar_displays
|
||||||
|
- script.execute: update_bar1_left
|
||||||
|
- script.execute: update_bar1_right
|
||||||
|
- script.execute: update_bar2_left
|
||||||
|
- script.execute: update_bar2_right
|
||||||
|
- script.execute: update_bar3_left
|
||||||
|
- script.execute: update_bar3_right
|
||||||
|
|
||||||
|
mcp23008:
|
||||||
|
- id: 'base_J0'
|
||||||
|
i2c_id: buttons
|
||||||
|
address: 0x20
|
||||||
|
- id: 'base_J1'
|
||||||
|
i2c_id: buttons
|
||||||
|
address: 0x21
|
||||||
|
- id: 'base_J2'
|
||||||
|
i2c_id: buttons
|
||||||
|
address: 0x22
|
||||||
|
- id: 'base_J3'
|
||||||
|
i2c_id: buttons
|
||||||
|
address: 0x23
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
############################
|
||||||
|
### Buttons Main Display ###
|
||||||
|
############################
|
||||||
|
- platform: gpio
|
||||||
|
id: 'main_display_btn_left'
|
||||||
|
name: "Main Display button Left"
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J0
|
||||||
|
number: 6
|
||||||
|
mode: INPUT_PULLUP
|
||||||
|
inverted: true
|
||||||
|
- platform: gpio
|
||||||
|
id: 'main_display_btn_right'
|
||||||
|
name: "Main Display button Right"
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J0
|
||||||
|
number: 2
|
||||||
|
mode: INPUT_PULLUP
|
||||||
|
inverted: true
|
||||||
|
|
||||||
|
############################
|
||||||
|
### Buttons BAR module 1 ###
|
||||||
|
############################
|
||||||
|
- platform: gpio
|
||||||
|
id: 'bar1_btn_left'
|
||||||
|
name: "BAR 1 button Left"
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J1
|
||||||
|
number: 6
|
||||||
|
mode: INPUT_PULLUP
|
||||||
|
inverted: true
|
||||||
|
- platform: gpio
|
||||||
|
id: 'bar1_btn_right'
|
||||||
|
name: "BAR 1 button Right"
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J1
|
||||||
|
number: 2
|
||||||
|
mode: INPUT_PULLUP
|
||||||
|
inverted: true
|
||||||
|
|
||||||
|
############################
|
||||||
|
### Buttons BAR module 2 ###
|
||||||
|
############################
|
||||||
|
- platform: gpio
|
||||||
|
id: 'bar2_btn_left'
|
||||||
|
name: "BAR 2 button Left"
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J2
|
||||||
|
number: 6
|
||||||
|
mode: INPUT_PULLUP
|
||||||
|
inverted: true
|
||||||
|
- platform: gpio
|
||||||
|
id: 'bar2_btn_right'
|
||||||
|
name: "BAR 2 button Right"
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J2
|
||||||
|
number: 2
|
||||||
|
mode: INPUT_PULLUP
|
||||||
|
inverted: true
|
||||||
|
|
||||||
|
############################
|
||||||
|
### Buttons BAR module 3 ###
|
||||||
|
############################
|
||||||
|
- platform: gpio
|
||||||
|
id: 'bar3_btn_left'
|
||||||
|
name: "BAR 3 button Left"
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J3
|
||||||
|
number: 6
|
||||||
|
mode: INPUT_PULLUP
|
||||||
|
inverted: true
|
||||||
|
- platform: gpio
|
||||||
|
id: 'bar3_btn_right'
|
||||||
|
name: "BAR 3 button Right"
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J3
|
||||||
|
number: 2
|
||||||
|
mode: INPUT_PULLUP
|
||||||
|
inverted: true
|
||||||
|
|
||||||
|
light:
|
||||||
|
- id: !extend neopixels
|
||||||
|
num_leds: 13
|
||||||
|
##############################
|
||||||
|
### RGB LED's BAR module 1 ###
|
||||||
|
##############################
|
||||||
|
- platform: partition
|
||||||
|
name: "BAR 1 Left RGB Front"
|
||||||
|
id: bar1_left_rgb_front
|
||||||
|
segments:
|
||||||
|
- id: neopixels
|
||||||
|
from: 0
|
||||||
|
to: 0
|
||||||
|
- platform: partition
|
||||||
|
name: "BAR 1 Left RGB Back"
|
||||||
|
id: bar1_left_rgb_back
|
||||||
|
segments:
|
||||||
|
- id: neopixels
|
||||||
|
from: 1
|
||||||
|
to: 1
|
||||||
|
- platform: partition
|
||||||
|
name: "BAR 1 Right RGB Front"
|
||||||
|
id: bar1_right_rgb_front
|
||||||
|
segments:
|
||||||
|
- id: neopixels
|
||||||
|
from: 2
|
||||||
|
to: 2
|
||||||
|
- platform: partition
|
||||||
|
name: "BAR 1 Right RGB Back"
|
||||||
|
id: bar1_right_rgb_back
|
||||||
|
segments:
|
||||||
|
- id: neopixels
|
||||||
|
from: 3
|
||||||
|
to: 3
|
||||||
|
##############################
|
||||||
|
### RGB LED's BAR module 2 ###
|
||||||
|
##############################
|
||||||
|
- platform: partition
|
||||||
|
name: "BAR 2 Left RGB Front"
|
||||||
|
id: bar2_left_rgb_front
|
||||||
|
segments:
|
||||||
|
- id: neopixels
|
||||||
|
from: 4
|
||||||
|
to: 4
|
||||||
|
- platform: partition
|
||||||
|
name: "BAR 2 Left RGB Back"
|
||||||
|
id: bar2_left_rgb_back
|
||||||
|
segments:
|
||||||
|
- id: neopixels
|
||||||
|
from: 5
|
||||||
|
to: 5
|
||||||
|
- platform: partition
|
||||||
|
name: "BAR 2 Right RGB Front"
|
||||||
|
id: bar2_right_rgb_front
|
||||||
|
segments:
|
||||||
|
- id: neopixels
|
||||||
|
from: 6
|
||||||
|
to: 6
|
||||||
|
- platform: partition
|
||||||
|
name: "BAR 2 Right RGB Back"
|
||||||
|
id: bar2_right_rgb_back
|
||||||
|
segments:
|
||||||
|
- id: neopixels
|
||||||
|
from: 7
|
||||||
|
to: 7
|
||||||
|
##############################
|
||||||
|
### RGB LED's BAR module 3 ###
|
||||||
|
##############################
|
||||||
|
- platform: partition
|
||||||
|
name: "BAR 3 Left RGB Front"
|
||||||
|
id: bar3_left_rgb_front
|
||||||
|
segments:
|
||||||
|
- id: neopixels
|
||||||
|
from: 8
|
||||||
|
to: 8
|
||||||
|
- platform: partition
|
||||||
|
name: "BAR 3 Left RGB Back"
|
||||||
|
id: bar3_left_rgb_back
|
||||||
|
segments:
|
||||||
|
- id: neopixels
|
||||||
|
from: 9
|
||||||
|
to: 9
|
||||||
|
- platform: partition
|
||||||
|
name: "BAR 3 Right RGB Front"
|
||||||
|
id: bar3_right_rgb_front
|
||||||
|
segments:
|
||||||
|
- id: neopixels
|
||||||
|
from: 10
|
||||||
|
to: 10
|
||||||
|
- platform: partition
|
||||||
|
name: "BAR 3 Right RGB Back"
|
||||||
|
id: bar3_right_rgb_back
|
||||||
|
segments:
|
||||||
|
- id: neopixels
|
||||||
|
from: 11
|
||||||
|
to: 11
|
||||||
|
|
||||||
|
output:
|
||||||
|
#######################################
|
||||||
|
### CS pins to control BAR Displays ###
|
||||||
|
#######################################
|
||||||
|
- id: cs_pin_bar1_left
|
||||||
|
platform: gpio
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J1
|
||||||
|
number: 5
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
|
inverted: true
|
||||||
|
- id: cs_pin_bar1_right
|
||||||
|
platform: gpio
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J1
|
||||||
|
number: 1
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
|
inverted: true
|
||||||
|
- id: cs_pin_bar2_left
|
||||||
|
platform: gpio
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J2
|
||||||
|
number: 5
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
|
inverted: true
|
||||||
|
- id: cs_pin_bar2_right
|
||||||
|
platform: gpio
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J2
|
||||||
|
number: 1
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
|
inverted: true
|
||||||
|
- id: cs_pin_bar3_left
|
||||||
|
platform: gpio
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J3
|
||||||
|
number: 5
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
|
inverted: true
|
||||||
|
- id: cs_pin_bar3_right
|
||||||
|
platform: gpio
|
||||||
|
pin:
|
||||||
|
mcp23xxx: base_J3
|
||||||
|
number: 1
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
|
inverted: true
|
||||||
|
|
||||||
|
display:
|
||||||
|
####################
|
||||||
|
### Main Display ###
|
||||||
|
####################
|
||||||
|
- id: main_display
|
||||||
|
platform: ili9xxx
|
||||||
|
model: ili9341
|
||||||
|
invert_colors: false
|
||||||
|
color_order: rgb
|
||||||
|
update_interval: 30s
|
||||||
|
dc_pin:
|
||||||
|
number: GPIO7
|
||||||
|
allow_other_uses: true
|
||||||
|
cs_pin:
|
||||||
|
mcp23xxx: base_J0
|
||||||
|
number: 5
|
||||||
|
mode:
|
||||||
|
output: true
|
||||||
|
inverted: false
|
||||||
|
show_test_card: false
|
||||||
|
dimensions:
|
||||||
|
height: 240
|
||||||
|
width: 320
|
||||||
|
rotation: 180
|
||||||
|
###################
|
||||||
|
### BAR modules ###
|
||||||
|
###################
|
||||||
|
- id: bar_display
|
||||||
|
platform: ili9xxx
|
||||||
|
model: ST7735
|
||||||
|
color_order: bgr
|
||||||
|
update_interval: never
|
||||||
|
dc_pin:
|
||||||
|
number: GPIO7
|
||||||
|
allow_other_uses: true
|
||||||
|
invert_colors: false
|
||||||
|
show_test_card: false
|
||||||
|
auto_clear_enabled: false
|
||||||
|
dimensions:
|
||||||
|
height: 160
|
||||||
|
width: 80
|
||||||
|
offset_width: 24
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
esphome:
|
||||||
|
name: buttonplus
|
||||||
|
friendly_name: ButtonPlus
|
||||||
|
|
||||||
|
esp32:
|
||||||
|
variant: ESP32S3
|
||||||
|
board: esp32-s3-devkitc1-n16r8
|
||||||
|
flash_size: 16MB
|
||||||
|
framework:
|
||||||
|
type: esp-idf
|
||||||
|
|
||||||
|
# Enable logging
|
||||||
|
logger:
|
||||||
|
level: DEBUG
|
||||||
|
|
||||||
|
# Enable Home Assistant API
|
||||||
|
api:
|
||||||
|
encryption:
|
||||||
|
key: ""
|
||||||
|
|
||||||
|
ota:
|
||||||
|
- platform: esphome
|
||||||
|
password: ""
|
||||||
|
|
||||||
|
wifi:
|
||||||
|
ssid: !secret wifi_ssid
|
||||||
|
password: !secret wifi_password
|
||||||
|
|
||||||
|
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
||||||
|
ap:
|
||||||
|
ssid: "Buttonplus"
|
||||||
|
password: ""
|
||||||
|
|
||||||
|
packages:
|
||||||
|
remote_package_files:
|
||||||
|
files:
|
||||||
|
- path: 'base.yaml'
|
||||||
|
vars:
|
||||||
|
nr_of_pages: '3'
|
||||||
|
page_names: '{"Start", "Music", "Page 3"}'
|
||||||
|
- path: '../cards/music.yaml'
|
||||||
|
vars:
|
||||||
|
music_card_entity_id: 'media_player.spotifyplus_kennyboy44'
|
||||||
|
music_card_text_color: FFFFFF
|
||||||
|
music_card_icon_main_color: FF7F00
|
||||||
|
music_card_icon_bar_color: FF7F00
|
||||||
|
|
||||||
|
font:
|
||||||
|
- file: "https://github.com/web-fonts/ttf/raw/refs/heads/master/bpg-ingiri-arial-webfont.ttf"
|
||||||
|
id: font_arial20
|
||||||
|
size: 20
|
||||||
|
bpp: 4
|
||||||
|
- file: "https://torinak.com/font/7segment.ttf"
|
||||||
|
id: font_clock
|
||||||
|
size: 64
|
||||||
|
bpp: 4
|
||||||
|
- file: "https://torinak.com/font/7segment.ttf"
|
||||||
|
id: font_date
|
||||||
|
size: 24
|
||||||
|
bpp: 4
|
||||||
|
|
||||||
|
image:
|
||||||
|
- file: mdi:lightbulb
|
||||||
|
id: lightbulb
|
||||||
|
resize: 80x80
|
||||||
|
type: GRAYSCALE
|
||||||
|
- file: mdi:alert
|
||||||
|
id: alert
|
||||||
|
resize: 80x80
|
||||||
|
type: GRAYSCALE
|
||||||
|
- file: mdi:chevron-right
|
||||||
|
id: icon_next_page
|
||||||
|
resize: 30x30
|
||||||
|
type: GRAYSCALE
|
||||||
|
- file: mdi:chevron-left
|
||||||
|
id: icon_prev_page
|
||||||
|
resize: 30x30
|
||||||
|
type: GRAYSCALE
|
||||||
|
- file: mdi:home-thermometer-outline
|
||||||
|
id: icon_temp_inside
|
||||||
|
resize: 40x40
|
||||||
|
type: GRAYSCALE
|
||||||
|
- file: mdi:brightness-percent
|
||||||
|
id: icon_ambient_inside
|
||||||
|
resize: 40x40
|
||||||
|
type: GRAYSCALE
|
||||||
|
|
||||||
|
color:
|
||||||
|
- id: red
|
||||||
|
hex: FF0000
|
||||||
|
- id: blue
|
||||||
|
hex: 0000FF
|
||||||
|
- id: yellow
|
||||||
|
hex: FFFF00
|
||||||
|
- id: green
|
||||||
|
hex: 00FF00
|
||||||
|
- id: orange
|
||||||
|
hex: FF7F00
|
||||||
|
- id: white
|
||||||
|
hex: FFFFFF
|
||||||
|
- id: grey
|
||||||
|
hex: A6A6A6
|
||||||
|
|
||||||
|
display:
|
||||||
|
#########
|
||||||
|
# MAIN ##
|
||||||
|
#########
|
||||||
|
- id: !extend main_display
|
||||||
|
# data_rate: 40MHz
|
||||||
|
lambda: |-
|
||||||
|
id(all_pages_main).execute();
|
||||||
|
|
||||||
|
switch (id(actual_page)){
|
||||||
|
case 0:
|
||||||
|
it.print(100, 150, id(font_arial20), "Hooray, it works!");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
id(music_card).execute(20, 125);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
it.print(100, 150, id(font_arial20), "Last Page");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
script:
|
||||||
|
- id: all_pages_main
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
//>>> prev/next icons next to butotns
|
||||||
|
id(main_display).image(0, 208, id(icon_prev_page), ImageAlign::TOP_LEFT, id(red));
|
||||||
|
id(main_display).image(320, 208, id(icon_next_page), ImageAlign::TOP_RIGHT, id(red));
|
||||||
|
//
|
||||||
|
//>>> Page name
|
||||||
|
id(main_display).print(100, 208, id(font_arial20), id(active_page_name).c_str());
|
||||||
|
//
|
||||||
|
//>>> temperature inside:
|
||||||
|
id(main_display).image(36, 15, id(icon_temp_inside), ImageAlign::TOP_CENTER, id(red));
|
||||||
|
id(main_display).printf(36, 80, id(font_arial20), id(white), TextAlign::TOP_CENTER , "%.1f°", id(buttonplus_temperature).state);
|
||||||
|
//
|
||||||
|
//>>> ambient light:
|
||||||
|
id(main_display).image(285, 15, id(icon_ambient_inside), ImageAlign::TOP_CENTER, id(red));
|
||||||
|
id(main_display).printf(285, 80, id(font_arial20), id(white), TextAlign::TOP_CENTER , "%.1flux", id(buttonplus_ambientlight).state);
|
||||||
|
//
|
||||||
|
//>>> print time and date
|
||||||
|
id(main_display).strftime(160, 5, id(font_clock), TextAlign::TOP_CENTER, "%H:%M", id(datetime).now());
|
||||||
|
id(main_display).strftime(160, 80, id(font_date), TextAlign::TOP_CENTER, "%d-%m-%Y", id(datetime).now());
|
||||||
|
- id: !extend bar1_left_draw
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
switch (id(actual_page)){
|
||||||
|
case 0:
|
||||||
|
id(bar_display).image(80, 0, id(lightbulb), ImageAlign::TOP_CENTER, id(red));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
id(music_card_bar).execute("volume_down");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- id: !extend bar1_right_draw
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
switch (id(actual_page)){
|
||||||
|
case 0:
|
||||||
|
id(bar_display).image(80, 0, id(lightbulb), ImageAlign::TOP_CENTER, id(red));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
id(music_card_bar).execute("volume_up");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- id: !extend bar2_left_draw
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
switch (id(actual_page)){
|
||||||
|
case 0:
|
||||||
|
id(bar_display).image(80, 0, id(lightbulb), ImageAlign::TOP_CENTER, id(red));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
id(music_card_bar).execute("prev");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- id: !extend bar2_right_draw
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
switch (id(actual_page)){
|
||||||
|
case 0:
|
||||||
|
id(bar_display).image(80, 0, id(lightbulb), ImageAlign::TOP_CENTER, id(red));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
id(music_card_bar).execute("next");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- id: !extend bar3_left_draw
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
switch (id(actual_page)){
|
||||||
|
case 0:
|
||||||
|
id(bar_display).image(80, 0, id(lightbulb), ImageAlign::TOP_CENTER, id(red));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
id(music_card_bar).execute("power");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- id: !extend bar3_right_draw
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
switch (id(actual_page)){
|
||||||
|
case 0:
|
||||||
|
id(bar_display).image(80, 0, id(lightbulb), ImageAlign::TOP_CENTER, id(red));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
id(music_card_bar).execute("playpause");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
event:
|
||||||
|
- id: !extend bar1_btn_left_event
|
||||||
|
on_event:
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGD("main", "BAR1LEFT event %s triggered.", event_type.c_str());
|
||||||
|
- lambda: |-
|
||||||
|
if (event_type == "click page 1"){
|
||||||
|
id(music_card_vol_down).execute();
|
||||||
|
ESP_LOGD("main", "VOL DOWN");
|
||||||
|
}
|
||||||
|
- id: !extend bar1_btn_right_event
|
||||||
|
on_event:
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGD("main", "BAR1RIGHT event %s triggered.", event_type.c_str());
|
||||||
|
- lambda: |-
|
||||||
|
if (event_type == "click page 1"){
|
||||||
|
id(music_card_vol_up).execute();
|
||||||
|
ESP_LOGD("main", "VOL UP");
|
||||||
|
}
|
||||||
|
- id: !extend bar2_btn_left_event
|
||||||
|
on_event:
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGD("main", "BAR2LEFT event %s triggered.", event_type.c_str());
|
||||||
|
- lambda: |-
|
||||||
|
if (event_type == "click page 1"){
|
||||||
|
id(music_card_prev).execute();
|
||||||
|
ESP_LOGD("main", "PREV");
|
||||||
|
}
|
||||||
|
- id: !extend bar2_btn_right_event
|
||||||
|
on_event:
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGD("main", "BAR2RIGHT event %s triggered.", event_type.c_str());
|
||||||
|
- lambda: |-
|
||||||
|
if (event_type == "click page 1"){
|
||||||
|
id(music_card_next).execute();
|
||||||
|
ESP_LOGD("main", "NEXT");
|
||||||
|
}
|
||||||
|
- id: !extend bar3_btn_left_event
|
||||||
|
on_event:
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGD("main", "BAR3LEFT event %s triggered.", event_type.c_str());
|
||||||
|
- lambda: |-
|
||||||
|
if (event_type == "click page 1"){
|
||||||
|
id(music_card_power).execute();
|
||||||
|
ESP_LOGD("main", "POWER");
|
||||||
|
}
|
||||||
|
- id: !extend bar3_btn_right_event
|
||||||
|
on_event:
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
ESP_LOGD("main", "BAR3RIGHT event %s triggered.", event_type.c_str());
|
||||||
|
- lambda: |-
|
||||||
|
if (event_type == "click page 1"){
|
||||||
|
id(music_card_playpause).execute();
|
||||||
|
ESP_LOGD("main", "PLAY PAUSE");
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,549 @@
|
|||||||
|
## Events for 3 pages
|
||||||
|
|
||||||
|
substitutions:
|
||||||
|
nr_of_pages: '3'
|
||||||
|
display_events:
|
||||||
|
- double_click page 0
|
||||||
|
- triple_click page 0
|
||||||
|
- hold page 0
|
||||||
|
- double_click page 1
|
||||||
|
- triple_click page 1
|
||||||
|
- hold page 1
|
||||||
|
- double_click page 2
|
||||||
|
- triple_click page 2
|
||||||
|
- hold page 2
|
||||||
|
button_events:
|
||||||
|
- click page 0
|
||||||
|
- double_click page 0
|
||||||
|
- triple_click page 0
|
||||||
|
- hold page 0
|
||||||
|
- click page 1
|
||||||
|
- double_click page 1
|
||||||
|
- triple_click page 1
|
||||||
|
- hold page 1
|
||||||
|
- click page 2
|
||||||
|
- double_click page 2
|
||||||
|
- triple_click page 2
|
||||||
|
- hold page 2
|
||||||
|
script:
|
||||||
|
- id: trigger_with_feedback
|
||||||
|
parameters:
|
||||||
|
event_id: esphome::template_::TemplateEvent*
|
||||||
|
event_msg: std::string
|
||||||
|
led_id: light::LightState*
|
||||||
|
r: float
|
||||||
|
g: float
|
||||||
|
b: float
|
||||||
|
then:
|
||||||
|
- lambda: event_id->trigger(event_msg);
|
||||||
|
- if:
|
||||||
|
condition:
|
||||||
|
lambda: return led_id != nullptr;
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
auto call = led_id->make_call();
|
||||||
|
call.set_state(true);
|
||||||
|
call.set_rgb(r, g, b);
|
||||||
|
call.set_brightness(1.0);
|
||||||
|
call.set_flash_length(200); // Returns to previous state automatically
|
||||||
|
call.perform();
|
||||||
|
event:
|
||||||
|
- platform: template
|
||||||
|
name: DISPLAY Button Left
|
||||||
|
id: display_btn_left_event
|
||||||
|
device_class: button
|
||||||
|
event_types: ${display_events}
|
||||||
|
- platform: template
|
||||||
|
name: DISPLAY Button Right
|
||||||
|
id: display_btn_right_event
|
||||||
|
device_class: button
|
||||||
|
event_types: ${display_events}
|
||||||
|
- platform: template
|
||||||
|
name: BAR1 Button Left
|
||||||
|
id: bar1_btn_left_event
|
||||||
|
device_class: button
|
||||||
|
event_types: ${button_events}
|
||||||
|
- platform: template
|
||||||
|
name: BAR1 Button Right
|
||||||
|
id: bar1_btn_right_event
|
||||||
|
device_class: button
|
||||||
|
event_types: ${button_events}
|
||||||
|
- platform: template
|
||||||
|
name: BAR2 Button Left
|
||||||
|
id: bar2_btn_left_event
|
||||||
|
device_class: button
|
||||||
|
event_types: ${button_events}
|
||||||
|
- platform: template
|
||||||
|
name: BAR2 Button Right
|
||||||
|
id: bar2_btn_right_event
|
||||||
|
device_class: button
|
||||||
|
event_types: ${button_events}
|
||||||
|
- platform: template
|
||||||
|
name: BAR3 Button Left
|
||||||
|
id: bar3_btn_left_event
|
||||||
|
device_class: button
|
||||||
|
event_types: ${button_events}
|
||||||
|
- platform: template
|
||||||
|
name: BAR3 Button Right
|
||||||
|
id: bar3_btn_right_event
|
||||||
|
device_class: button
|
||||||
|
event_types: ${button_events}
|
||||||
|
binary_sensor:
|
||||||
|
- id: !extend 'main_display_btn_left'
|
||||||
|
filters:
|
||||||
|
- delayed_off: 10ms
|
||||||
|
internal: true
|
||||||
|
on_multi_click:
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute: prev_page
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: display_btn_left_event
|
||||||
|
event_msg: !lambda "return \"double_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: !lambda "return nullptr;"
|
||||||
|
r: 0.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: display_btn_left_event
|
||||||
|
event_msg: !lambda "return \"triple_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: !lambda "return nullptr;"
|
||||||
|
r: 1.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at least 1s
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: display_btn_left_event
|
||||||
|
event_msg: !lambda "return \"hold page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: !lambda "return nullptr;"
|
||||||
|
r: 1.0
|
||||||
|
g: 0.5
|
||||||
|
b: 0.0
|
||||||
|
- id: !extend 'main_display_btn_right'
|
||||||
|
filters:
|
||||||
|
- delayed_off: 10ms
|
||||||
|
internal: true
|
||||||
|
on_multi_click:
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute: next_page
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: display_btn_right_event
|
||||||
|
event_msg: !lambda "return \"double_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: !lambda "return nullptr;"
|
||||||
|
r: 0.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: display_btn_right_event
|
||||||
|
event_msg: !lambda "return \"triple_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: !lambda "return nullptr;"
|
||||||
|
r: 1.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at least 1s
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: display_btn_right_event
|
||||||
|
event_msg: !lambda "return \"hold page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: !lambda "return nullptr;"
|
||||||
|
r: 1.0
|
||||||
|
g: 0.5
|
||||||
|
b: 0.0
|
||||||
|
- id: !extend 'bar1_btn_left'
|
||||||
|
filters:
|
||||||
|
- delayed_off: 10ms
|
||||||
|
internal: true
|
||||||
|
on_multi_click:
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar1_btn_left_event
|
||||||
|
event_msg: !lambda "return \"click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar1_left_rgb_front
|
||||||
|
r: 0.0
|
||||||
|
g: 1.0
|
||||||
|
b: 0.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar1_btn_left_event
|
||||||
|
event_msg: !lambda "return \"double_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar1_left_rgb_front
|
||||||
|
r: 0.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar1_btn_left_event
|
||||||
|
event_msg: !lambda "return \"triple_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar1_left_rgb_front
|
||||||
|
r: 1.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at least 1s
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar1_btn_left_event
|
||||||
|
event_msg: !lambda "return \"hold page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar1_left_rgb_front
|
||||||
|
r: 1.0
|
||||||
|
g: 0.5
|
||||||
|
b: 0.0
|
||||||
|
- id: !extend 'bar1_btn_right'
|
||||||
|
filters:
|
||||||
|
- delayed_off: 10ms
|
||||||
|
internal: true
|
||||||
|
on_multi_click:
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar1_btn_right_event
|
||||||
|
event_msg: !lambda "return \"click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar1_right_rgb_front
|
||||||
|
r: 0.0
|
||||||
|
g: 1.0
|
||||||
|
b: 0.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar1_btn_right_event
|
||||||
|
event_msg: !lambda "return \"double_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar1_right_rgb_front
|
||||||
|
r: 0.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar1_btn_right_event
|
||||||
|
event_msg: !lambda "return \"triple_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar1_right_rgb_front
|
||||||
|
r: 1.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at least 1s
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar1_btn_right_event
|
||||||
|
event_msg: !lambda "return \"hold page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar1_right_rgb_front
|
||||||
|
r: 1.0
|
||||||
|
g: 0.5
|
||||||
|
b: 0.0
|
||||||
|
- id: !extend 'bar2_btn_left'
|
||||||
|
filters:
|
||||||
|
- delayed_off: 10ms
|
||||||
|
internal: true
|
||||||
|
on_multi_click:
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar2_btn_left_event
|
||||||
|
event_msg: !lambda "return \"click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar2_left_rgb_front
|
||||||
|
r: 0.0
|
||||||
|
g: 1.0
|
||||||
|
b: 0.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar2_btn_left_event
|
||||||
|
event_msg: !lambda "return \"double_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar2_left_rgb_front
|
||||||
|
r: 0.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar2_btn_left_event
|
||||||
|
event_msg: !lambda "return \"triple_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar2_left_rgb_front
|
||||||
|
r: 1.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at least 1s
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar2_btn_left_event
|
||||||
|
event_msg: !lambda "return \"hold page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar2_left_rgb_front
|
||||||
|
r: 1.0
|
||||||
|
g: 0.5
|
||||||
|
b: 0.0
|
||||||
|
- id: !extend 'bar2_btn_right'
|
||||||
|
filters:
|
||||||
|
- delayed_off: 10ms
|
||||||
|
internal: true
|
||||||
|
on_multi_click:
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar2_btn_right_event
|
||||||
|
event_msg: !lambda "return \"click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar2_right_rgb_front
|
||||||
|
r: 0.0
|
||||||
|
g: 1.0
|
||||||
|
b: 0.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar2_btn_right_event
|
||||||
|
event_msg: !lambda "return \"double_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar2_right_rgb_front
|
||||||
|
r: 0.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar2_btn_right_event
|
||||||
|
event_msg: !lambda "return \"triple_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar2_right_rgb_front
|
||||||
|
r: 1.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at least 1s
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar2_btn_right_event
|
||||||
|
event_msg: !lambda "return \"hold page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar2_right_rgb_front
|
||||||
|
r: 1.0
|
||||||
|
g: 0.5
|
||||||
|
b: 0.0
|
||||||
|
- id: !extend 'bar3_btn_left'
|
||||||
|
filters:
|
||||||
|
- delayed_off: 10ms
|
||||||
|
internal: true
|
||||||
|
on_multi_click:
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar3_btn_left_event
|
||||||
|
event_msg: !lambda "return \"click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar3_left_rgb_front
|
||||||
|
r: 0.0
|
||||||
|
g: 1.0
|
||||||
|
b: 0.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar3_btn_left_event
|
||||||
|
event_msg: !lambda "return \"double_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar3_left_rgb_front
|
||||||
|
r: 0.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar3_btn_left_event
|
||||||
|
event_msg: !lambda "return \"triple_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar3_left_rgb_front
|
||||||
|
r: 1.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at least 1s
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar3_btn_left_event
|
||||||
|
event_msg: !lambda "return \"hold page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar3_left_rgb_front
|
||||||
|
r: 1.0
|
||||||
|
g: 0.5
|
||||||
|
b: 0.0
|
||||||
|
- id: !extend 'bar3_btn_right'
|
||||||
|
filters:
|
||||||
|
- delayed_off: 10ms
|
||||||
|
internal: true
|
||||||
|
on_multi_click:
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar3_btn_right_event
|
||||||
|
event_msg: !lambda "return \"click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar3_right_rgb_front
|
||||||
|
r: 0.0
|
||||||
|
g: 1.0
|
||||||
|
b: 0.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar3_btn_right_event
|
||||||
|
event_msg: !lambda "return \"double_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar3_right_rgb_front
|
||||||
|
r: 0.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at most 0.2s
|
||||||
|
- ON for at most 300ms
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar3_btn_right_event
|
||||||
|
event_msg: !lambda "return \"triple_click page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar3_right_rgb_front
|
||||||
|
r: 1.0
|
||||||
|
g: 0.0
|
||||||
|
b: 1.0
|
||||||
|
- timing:
|
||||||
|
- ON for at least 1s
|
||||||
|
- OFF for at least 0.2s
|
||||||
|
then:
|
||||||
|
- script.execute:
|
||||||
|
id: trigger_with_feedback
|
||||||
|
event_id: bar3_btn_right_event
|
||||||
|
event_msg: !lambda "return \"hold page \" + std::to_string(id(actual_page));"
|
||||||
|
led_id: bar3_right_rgb_front
|
||||||
|
r: 1.0
|
||||||
|
g: 0.5
|
||||||
|
b: 0.0
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
|
||||||
|
script:
|
||||||
|
######################
|
||||||
|
### update scripts ###
|
||||||
|
######################
|
||||||
|
- id: update_bar1_left
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(cs_pin_bar1_left).turn_on(); // <<
|
||||||
|
id(cs_pin_bar1_right).turn_off();
|
||||||
|
id(cs_pin_bar2_left).turn_off();
|
||||||
|
id(cs_pin_bar2_right).turn_off();
|
||||||
|
id(cs_pin_bar3_left).turn_off();
|
||||||
|
id(cs_pin_bar3_right).turn_off();
|
||||||
|
id(bar_display).clear();
|
||||||
|
id(bar_display).set_rotation(display::DisplayRotation::DISPLAY_ROTATION_270_DEGREES);
|
||||||
|
id(bar1_left_draw).execute();
|
||||||
|
id(bar_display).update();
|
||||||
|
delay(1);
|
||||||
|
id(cs_pin_bar1_left).turn_off();
|
||||||
|
- id: update_bar1_right
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(cs_pin_bar1_left).turn_off();
|
||||||
|
id(cs_pin_bar1_right).turn_on(); // <<
|
||||||
|
id(cs_pin_bar2_left).turn_off();
|
||||||
|
id(cs_pin_bar2_right).turn_off();
|
||||||
|
id(cs_pin_bar3_left).turn_off();
|
||||||
|
id(cs_pin_bar3_right).turn_off();
|
||||||
|
id(bar_display).clear();
|
||||||
|
id(bar_display).set_rotation(display::DisplayRotation::DISPLAY_ROTATION_90_DEGREES);
|
||||||
|
id(bar1_right_draw).execute();
|
||||||
|
id(bar_display).update();
|
||||||
|
delay(1);
|
||||||
|
id(cs_pin_bar1_right).turn_off();
|
||||||
|
- id: update_bar2_left
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(cs_pin_bar1_left).turn_off();
|
||||||
|
id(cs_pin_bar1_right).turn_off();
|
||||||
|
id(cs_pin_bar2_left).turn_on(); // <<
|
||||||
|
id(cs_pin_bar2_right).turn_off();
|
||||||
|
id(cs_pin_bar3_left).turn_off();
|
||||||
|
id(cs_pin_bar3_right).turn_off();
|
||||||
|
id(bar_display).clear();
|
||||||
|
id(bar_display).set_rotation(display::DisplayRotation::DISPLAY_ROTATION_270_DEGREES);
|
||||||
|
id(bar2_left_draw).execute();
|
||||||
|
id(bar_display).update();
|
||||||
|
delay(1);
|
||||||
|
id(cs_pin_bar2_left).turn_off();
|
||||||
|
- id: update_bar2_right
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(cs_pin_bar1_left).turn_off();
|
||||||
|
id(cs_pin_bar1_right).turn_off();
|
||||||
|
id(cs_pin_bar2_left).turn_off();
|
||||||
|
id(cs_pin_bar2_right).turn_on(); // <<
|
||||||
|
id(cs_pin_bar3_left).turn_off();
|
||||||
|
id(cs_pin_bar3_right).turn_off();
|
||||||
|
id(bar_display).clear();
|
||||||
|
id(bar_display).set_rotation(display::DisplayRotation::DISPLAY_ROTATION_90_DEGREES);
|
||||||
|
id(bar2_right_draw).execute();
|
||||||
|
id(bar_display).update();
|
||||||
|
delay(1);
|
||||||
|
id(cs_pin_bar2_right).turn_off();
|
||||||
|
- id: update_bar3_left
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(cs_pin_bar1_left).turn_off();
|
||||||
|
id(cs_pin_bar1_right).turn_off();
|
||||||
|
id(cs_pin_bar2_left).turn_off();
|
||||||
|
id(cs_pin_bar2_right).turn_off();
|
||||||
|
id(cs_pin_bar3_left).turn_on(); // <<
|
||||||
|
id(cs_pin_bar3_right).turn_off();
|
||||||
|
id(bar_display).clear();
|
||||||
|
id(bar_display).set_rotation(display::DisplayRotation::DISPLAY_ROTATION_270_DEGREES);
|
||||||
|
id(bar3_left_draw).execute();
|
||||||
|
id(bar_display).update();
|
||||||
|
delay(1);
|
||||||
|
id(cs_pin_bar3_left).turn_off();
|
||||||
|
- id: update_bar3_right
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(cs_pin_bar1_left).turn_off();
|
||||||
|
id(cs_pin_bar1_right).turn_off();
|
||||||
|
id(cs_pin_bar2_left).turn_off();
|
||||||
|
id(cs_pin_bar2_right).turn_off();
|
||||||
|
id(cs_pin_bar3_left).turn_off();
|
||||||
|
id(cs_pin_bar3_right).turn_on(); // <<
|
||||||
|
id(bar_display).clear();
|
||||||
|
id(bar_display).set_rotation(display::DisplayRotation::DISPLAY_ROTATION_90_DEGREES);
|
||||||
|
id(bar3_right_draw).execute();
|
||||||
|
id(bar_display).update();
|
||||||
|
delay(1);
|
||||||
|
id(cs_pin_bar3_right).turn_off();
|
||||||
|
####################################
|
||||||
|
### setup mini display's scripts ###
|
||||||
|
####################################
|
||||||
|
- id: setup_bar_displays
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(cs_pin_bar1_left).turn_on();
|
||||||
|
id(bar_display).setup();
|
||||||
|
delay(5);
|
||||||
|
id(cs_pin_bar1_left).turn_off();
|
||||||
|
id(cs_pin_bar1_right).turn_on();
|
||||||
|
id(bar_display).setup();
|
||||||
|
delay(5);
|
||||||
|
id(cs_pin_bar1_right).turn_off();
|
||||||
|
id(cs_pin_bar2_left).turn_on();
|
||||||
|
id(bar_display).setup();
|
||||||
|
delay(5);
|
||||||
|
id(cs_pin_bar2_left).turn_off();
|
||||||
|
id(cs_pin_bar2_right).turn_on();
|
||||||
|
id(bar_display).setup();
|
||||||
|
delay(5);
|
||||||
|
id(cs_pin_bar2_right).turn_off();
|
||||||
|
id(cs_pin_bar3_left).turn_on();
|
||||||
|
id(bar_display).setup();
|
||||||
|
delay(5);
|
||||||
|
id(cs_pin_bar3_left).turn_off();
|
||||||
|
id(cs_pin_bar3_right).turn_on();
|
||||||
|
id(bar_display).setup();
|
||||||
|
delay(5);
|
||||||
|
id(cs_pin_bar3_right).turn_off();
|
||||||
|
###############################
|
||||||
|
### pre-define draw scripts ###
|
||||||
|
###############################
|
||||||
|
- id: bar1_left_draw
|
||||||
|
then:
|
||||||
|
- id: bar1_right_draw
|
||||||
|
then:
|
||||||
|
- id: bar2_left_draw
|
||||||
|
then:
|
||||||
|
- id: bar2_right_draw
|
||||||
|
then:
|
||||||
|
- id: bar3_left_draw
|
||||||
|
then:
|
||||||
|
- id: bar3_right_draw
|
||||||
|
then:
|
||||||
|
######################
|
||||||
|
### update scripts ###
|
||||||
|
######################
|
||||||
|
- id: update_main
|
||||||
|
then:
|
||||||
|
- component.update: main_display
|
||||||
|
- id: update_all
|
||||||
|
then:
|
||||||
|
- component.update: main_display
|
||||||
|
- delay: 0.1s
|
||||||
|
- script.execute: update_bar1_left
|
||||||
|
- delay: 0.1s
|
||||||
|
- script.execute: update_bar1_right
|
||||||
|
- delay: 0.1s
|
||||||
|
- script.execute: update_bar2_left
|
||||||
|
- delay: 0.1s
|
||||||
|
- script.execute: update_bar2_right
|
||||||
|
- delay: 0.1s
|
||||||
|
- script.execute: update_bar3_left
|
||||||
|
- delay: 0.1s
|
||||||
|
- script.execute: update_bar3_right
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
This folder contains the example working configuration on which this generator is based.
|
||||||
|
|
||||||
|
`common.yaml`: for all button+ configurations (max 3 bars, 1 display)
|
||||||
|
`config.yaml`: the base for ESPHome with board configuration
|
||||||
|
`base.yaml`: the base for the specific configuration with the GPIO definitions
|
||||||
|
`events.yaml`: all events for all buttons based on a provided number of pages
|
||||||
|
`scripts.yaml`: scripts to update the displays for the specific configuration
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# ESPHome Button+ - Music card
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
* Add the music card to the main display `lambda` and give it the position you want
|
||||||
|
```
|
||||||
|
id(music_card).execute(20, 125);
|
||||||
|
```
|
||||||
|
|
||||||
|
* Add the icons buttons to the BAR's
|
||||||
|
|
||||||
|
Select one of the folowing types:
|
||||||
|
* `volume_up`
|
||||||
|
* `volume_down`
|
||||||
|
* `next`
|
||||||
|
* `prev`
|
||||||
|
* `playpause`
|
||||||
|
* `power`
|
||||||
|
|
||||||
|
```
|
||||||
|
id(music_card_bar).execute("volume_up");
|
||||||
|
```
|
||||||
|
|
||||||
|
* add actions to the buttons
|
||||||
|
Select the a matching action for the button:
|
||||||
|
* `music_card_vol_up`
|
||||||
|
* `music_card_vol_down`
|
||||||
|
* `music_card_next`
|
||||||
|
* `music_card_prev`
|
||||||
|
* `music_card_playpause`
|
||||||
|
* `music_card_power`
|
||||||
|
|
||||||
|
```
|
||||||
|
id(music_card_vol_up).execute();
|
||||||
|
```
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
image:
|
||||||
|
- file: mdi:music-box-outline
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_album
|
||||||
|
resize: 20x20
|
||||||
|
- file: mdi:account-music
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_artist
|
||||||
|
resize: 20x20
|
||||||
|
- file: mdi:music-note
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_songtitle
|
||||||
|
resize: 20x20
|
||||||
|
- file: mdi:power-off
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_off
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:power-on
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_on
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:power
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_power
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:timer-sand-empty
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_idle
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:play-pause
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_playpause
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:play-box-outline
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_play_box
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:pause-box-outline
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_pause_box
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:power
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_standby
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:download-box-outline
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_buffering
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:volume-plus
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_vol_up
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:volume-minus
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_vol_down
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:skip-forward
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_next
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:skip-backward
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_prev
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:play
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_play
|
||||||
|
resize: 75x75
|
||||||
|
- file: mdi:pause
|
||||||
|
type: GRAYSCALE
|
||||||
|
id: icon_music_pause
|
||||||
|
resize: 75x75
|
||||||
|
|
||||||
|
color:
|
||||||
|
- id: music_card_text_color
|
||||||
|
hex: ${music_card_text_color}
|
||||||
|
- id: music_card_icon_main_color
|
||||||
|
hex: ${music_card_icon_main_color}
|
||||||
|
- id: music_card_icon_bar_color
|
||||||
|
hex: ${music_card_icon_bar_color}
|
||||||
|
|
||||||
|
text_sensor:
|
||||||
|
- platform: homeassistant
|
||||||
|
id: music_album
|
||||||
|
entity_id: ${music_card_entity_id}
|
||||||
|
attribute: media_album_name
|
||||||
|
on_value:
|
||||||
|
- delay: 500ms
|
||||||
|
- script.execute: update_main
|
||||||
|
- platform: homeassistant
|
||||||
|
id: music_artist
|
||||||
|
entity_id: ${music_card_entity_id}
|
||||||
|
attribute: media_artist
|
||||||
|
- platform: homeassistant
|
||||||
|
id: music_title
|
||||||
|
entity_id: ${music_card_entity_id}
|
||||||
|
attribute: media_title
|
||||||
|
on_value:
|
||||||
|
- delay: 500ms
|
||||||
|
- script.execute: update_main
|
||||||
|
- platform: homeassistant
|
||||||
|
id: music_playerstate
|
||||||
|
entity_id: ${music_card_entity_id}
|
||||||
|
on_value:
|
||||||
|
- script.execute: update_all
|
||||||
|
|
||||||
|
script:
|
||||||
|
- id: music_card
|
||||||
|
parameters:
|
||||||
|
x: int
|
||||||
|
y: int
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
// player state
|
||||||
|
if (strcmp(id(music_playerstate).state.c_str(), "off") == 0) {
|
||||||
|
id(main_display).image(x, 1+y, id(icon_music_off), ImageAlign::TOP_LEFT, id(music_card_icon_main_color));
|
||||||
|
} else if (strcmp(id(music_playerstate).state.c_str(), "on") == 0) {
|
||||||
|
id(main_display).image(x, 1+y, id(icon_music_on), ImageAlign::TOP_LEFT, id(music_card_icon_main_color));
|
||||||
|
} else if (strcmp(id(music_playerstate).state.c_str(), "idle") == 0) {
|
||||||
|
id(main_display).image(x, 1+y, id(icon_music_idle), ImageAlign::TOP_LEFT, id(music_card_icon_main_color));
|
||||||
|
} else if (strcmp(id(music_playerstate).state.c_str(), "playing") == 0) {
|
||||||
|
id(main_display).image(x, 1+y, id(icon_music_play_box), ImageAlign::TOP_LEFT, id(music_card_icon_main_color));
|
||||||
|
} else if (strcmp(id(music_playerstate).state.c_str(), "paused") == 0) {
|
||||||
|
id(main_display).image(x, 1+y, id(icon_music_pause_box), ImageAlign::TOP_LEFT, id(music_card_icon_main_color));
|
||||||
|
} else if (strcmp(id(music_playerstate).state.c_str(), "standby") == 0) {
|
||||||
|
id(main_display).image(x, 1+y, id(icon_music_standby), ImageAlign::TOP_LEFT, id(music_card_icon_main_color));
|
||||||
|
} else if (strcmp(id(music_playerstate).state.c_str(), "buffering") == 0) {
|
||||||
|
id(main_display).image(x, 1+y, id(icon_music_buffering), ImageAlign::TOP_LEFT, id(music_card_icon_main_color));
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// album
|
||||||
|
id(main_display).image(75+3+x, 4+y, id(icon_music_album), ImageAlign::TOP_LEFT, id(music_card_icon_main_color));
|
||||||
|
id(main_display).print(75+25+x, 0+y, id(font_arial20), id(music_card_text_color), TextAlign::TOP_LEFT , id(music_album).state.c_str());
|
||||||
|
//
|
||||||
|
// artist
|
||||||
|
id(main_display).image(75+3+x, 30+y, id(icon_music_artist), ImageAlign::TOP_LEFT, id(music_card_icon_main_color));
|
||||||
|
id(main_display).print(75+25+x, 26+y, id(font_arial20), id(music_card_text_color), TextAlign::TOP_LEFT , id(music_artist).state.c_str());
|
||||||
|
//
|
||||||
|
// song title
|
||||||
|
id(main_display).image(75+3+x, 56+y, id(icon_music_songtitle), ImageAlign::TOP_LEFT, id(music_card_icon_main_color));
|
||||||
|
id(main_display).print(75+25+x, 52+y, id(font_arial20), id(music_card_text_color), TextAlign::TOP_LEFT , id(music_title).state.c_str());
|
||||||
|
- id: music_card_bar
|
||||||
|
parameters:
|
||||||
|
type: string
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
if (strcmp(type.c_str(), "volume_up") == 0) { // button "volume_up"
|
||||||
|
id(bar_display).image(80, 2, id(icon_music_vol_up), ImageAlign::TOP_CENTER, id(music_card_icon_bar_color));
|
||||||
|
} else if (strcmp(type.c_str(), "volume_down") == 0) { // button "volume_down"
|
||||||
|
id(bar_display).image(80, 2, id(icon_music_vol_down), ImageAlign::TOP_CENTER, id(music_card_icon_bar_color));
|
||||||
|
} else if (strcmp(type.c_str(), "next") == 0) { // button "next"
|
||||||
|
id(bar_display).image(80, 2, id(icon_music_next), ImageAlign::TOP_CENTER, id(music_card_icon_bar_color));
|
||||||
|
} else if (strcmp(type.c_str(), "prev") == 0) { // button "prev"
|
||||||
|
id(bar_display).image(80, 2, id(icon_music_prev), ImageAlign::TOP_CENTER, id(music_card_icon_bar_color));
|
||||||
|
} else if (strcmp(type.c_str(), "playpause") == 0) { // button "playpause"
|
||||||
|
if (strcmp(id(music_playerstate).state.c_str(), "playing") == 0) {
|
||||||
|
id(bar_display).image(80, 2, id(icon_music_pause), ImageAlign::TOP_CENTER, id(music_card_icon_bar_color));
|
||||||
|
} else {
|
||||||
|
id(bar_display).image(80, 2, id(icon_music_play), ImageAlign::TOP_CENTER, id(music_card_icon_bar_color));
|
||||||
|
}
|
||||||
|
} else if (strcmp(type.c_str(), "power") == 0) { // button "power"
|
||||||
|
id(bar_display).image(80, 2, id(icon_music_power), ImageAlign::TOP_CENTER, id(music_card_icon_bar_color));
|
||||||
|
}
|
||||||
|
- id: music_card_vol_up
|
||||||
|
then:
|
||||||
|
- homeassistant.action:
|
||||||
|
action: media_player.volume_up
|
||||||
|
data:
|
||||||
|
entity_id: ${music_card_entity_id}
|
||||||
|
- id: music_card_vol_down
|
||||||
|
then:
|
||||||
|
- homeassistant.action:
|
||||||
|
action: media_player.volume_down
|
||||||
|
data:
|
||||||
|
entity_id: ${music_card_entity_id}
|
||||||
|
- id: music_card_next
|
||||||
|
then:
|
||||||
|
- homeassistant.action:
|
||||||
|
action: media_player.media_next_track
|
||||||
|
data:
|
||||||
|
entity_id: ${music_card_entity_id}
|
||||||
|
- id: music_card_prev
|
||||||
|
then:
|
||||||
|
- homeassistant.action:
|
||||||
|
action: media_player.media_previous_track
|
||||||
|
data:
|
||||||
|
entity_id: ${music_card_entity_id}
|
||||||
|
- id: music_card_playpause
|
||||||
|
then:
|
||||||
|
- homeassistant.action:
|
||||||
|
action: media_player.media_play_pause
|
||||||
|
data:
|
||||||
|
entity_id: ${music_card_entity_id}
|
||||||
|
- id: music_card_power
|
||||||
|
then:
|
||||||
|
- homeassistant.action:
|
||||||
|
action: media_player.toggle
|
||||||
|
data:
|
||||||
|
entity_id: ${music_card_entity_id}
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
esp32:
|
||||||
|
flash_size: 16MB
|
||||||
|
|
||||||
|
psram:
|
||||||
|
mode: octal
|
||||||
|
speed: 80MHz
|
||||||
|
|
||||||
|
interval:
|
||||||
|
- interval: 1min
|
||||||
|
then:
|
||||||
|
- logger.log: "ESPHome for Button+ V2 v0.1.0"
|
||||||
|
|
||||||
|
i2c:
|
||||||
|
# Devices at 0x20, 0x21, 0x22, 0x23
|
||||||
|
- id: buttons
|
||||||
|
sda: GPIO1
|
||||||
|
scl: GPIO2
|
||||||
|
frequency: 50khz
|
||||||
|
|
||||||
|
# Devices at 0x29 (ambient), 0x4A (temp)
|
||||||
|
- id: sensors
|
||||||
|
sda: GPIO47
|
||||||
|
scl: GPIO48
|
||||||
|
frequency: 50khz
|
||||||
|
|
||||||
|
spi:
|
||||||
|
clk_pin: GPIO6
|
||||||
|
mosi_pin: GPIO5
|
||||||
|
|
||||||
|
substitutions:
|
||||||
|
nr_of_pages: '"2"'
|
||||||
|
page_names: '{"Page 1", "Page 2"}'
|
||||||
|
|
||||||
|
globals:
|
||||||
|
- id: nr_of_pages
|
||||||
|
type: int
|
||||||
|
initial_value: ${nr_of_pages}
|
||||||
|
- id: actual_page
|
||||||
|
type: int
|
||||||
|
initial_value: '0'
|
||||||
|
- id: page_names
|
||||||
|
type: std::vector<std::string>
|
||||||
|
initial_value: ${page_names}
|
||||||
|
- id: active_page_name
|
||||||
|
type: std::string
|
||||||
|
initial_value: ""
|
||||||
|
|
||||||
|
output:
|
||||||
|
- platform: ledc
|
||||||
|
pin: GPIO3
|
||||||
|
id: display_main_backlight_pwm
|
||||||
|
inverted: True
|
||||||
|
max_power: 1.0
|
||||||
|
frequency: 500Hz
|
||||||
|
- platform: ledc
|
||||||
|
pin: GPIO46
|
||||||
|
id: displays_mini_backlight_pwm
|
||||||
|
inverted: True
|
||||||
|
max_power: 0.6
|
||||||
|
frequency: 500Hz
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: sts3x
|
||||||
|
address: 0x4A
|
||||||
|
id: buttonplus_temperature
|
||||||
|
i2c_id: sensors
|
||||||
|
name: "Temperature"
|
||||||
|
update_interval: 10s
|
||||||
|
unit_of_measurement: "°C"
|
||||||
|
icon: "mdi:thermometer"
|
||||||
|
device_class: "temperature"
|
||||||
|
state_class: "measurement"
|
||||||
|
accuracy_decimals: 1
|
||||||
|
- platform: ltr_als_ps
|
||||||
|
address: 0x29
|
||||||
|
i2c_id: sensors
|
||||||
|
update_interval: 10s
|
||||||
|
type: ALS
|
||||||
|
auto_mode: false
|
||||||
|
gain: 48x
|
||||||
|
ambient_light:
|
||||||
|
name: "Ambient Light"
|
||||||
|
id: buttonplus_ambientlight
|
||||||
|
unit_of_measurement: "lx"
|
||||||
|
icon: "mdi:brightness-6"
|
||||||
|
device_class: "illuminance"
|
||||||
|
state_class: "measurement"
|
||||||
|
accuracy_decimals: 1
|
||||||
|
infrared_counts:
|
||||||
|
name: "Infrared Counts"
|
||||||
|
id: buttonplus_infraredcounts
|
||||||
|
unit_of_measurement: "#"
|
||||||
|
icon: "mdi:brightness-5"
|
||||||
|
accuracy_decimals: 0
|
||||||
|
full_spectrum_counts :
|
||||||
|
name: "Full Spectrum Counts"
|
||||||
|
id: buttonplus_fullspectrumcounts
|
||||||
|
unit_of_measurement: "#"
|
||||||
|
icon: "mdi:brightness-7"
|
||||||
|
accuracy_decimals: 0
|
||||||
|
actual_gain:
|
||||||
|
name: "Actual Gain"
|
||||||
|
id: buttonplus_actualgain
|
||||||
|
icon: "mdi:multiplication"
|
||||||
|
accuracy_decimals: 0
|
||||||
|
- platform: template
|
||||||
|
name: "Active Page ID"
|
||||||
|
icon: "mdi:order-numeric-ascending"
|
||||||
|
id: active_page_id_ha
|
||||||
|
update_interval: never
|
||||||
|
accuracy_decimals: 0
|
||||||
|
|
||||||
|
text_sensor:
|
||||||
|
- platform: template
|
||||||
|
name: "Active Page Name"
|
||||||
|
icon: "mdi:order-alphabetical-ascending"
|
||||||
|
id: active_page_name_ha
|
||||||
|
update_interval: never
|
||||||
|
|
||||||
|
light:
|
||||||
|
- platform: esp32_rmt_led_strip
|
||||||
|
id: neopixels
|
||||||
|
rgb_order: RGB
|
||||||
|
chipset: ws2812
|
||||||
|
pin: GPIO4
|
||||||
|
num_leds: 17
|
||||||
|
- platform: monochromatic
|
||||||
|
output: display_main_backlight_pwm
|
||||||
|
gamma_correct : 2.2
|
||||||
|
name: "Main Display Backlight"
|
||||||
|
id: display_main_backlight
|
||||||
|
restore_mode: ALWAYS_ON
|
||||||
|
- platform: monochromatic
|
||||||
|
output: displays_mini_backlight_pwm
|
||||||
|
gamma_correct : 2.2
|
||||||
|
name: "Bars Display Backlight"
|
||||||
|
id: displays_mini_backlight
|
||||||
|
restore_mode: ALWAYS_ON
|
||||||
|
|
||||||
|
time:
|
||||||
|
- platform: homeassistant
|
||||||
|
id: datetime
|
||||||
|
|
||||||
|
number:
|
||||||
|
## Creates a number entity in Home Assistant
|
||||||
|
# It sets the menu of the Button Plus
|
||||||
|
- platform: template
|
||||||
|
name: "Menu Selector"
|
||||||
|
id: menuselector
|
||||||
|
optimistic: true
|
||||||
|
min_value: 0
|
||||||
|
max_value: ${nr_of_pages | int - 1}
|
||||||
|
step: 1
|
||||||
|
on_value:
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
if(id(menuselector).state >= id(nr_of_pages)) {
|
||||||
|
id(actual_page) = id(nr_of_pages)-1;
|
||||||
|
} else {
|
||||||
|
id(actual_page) = id(menuselector).state;
|
||||||
|
}
|
||||||
|
- logger.log: "Changing page"
|
||||||
|
- script.execute: set_page
|
||||||
|
|
||||||
|
script:
|
||||||
|
######################
|
||||||
|
### paging scripts ###
|
||||||
|
######################
|
||||||
|
- id: next_page
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(actual_page) = id(actual_page) + 1;
|
||||||
|
if(id(actual_page) >= id(nr_of_pages)) {
|
||||||
|
id(actual_page) = 0;
|
||||||
|
}
|
||||||
|
- script.execute: update_page
|
||||||
|
- id: prev_page
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(actual_page) = id(actual_page) - 1;
|
||||||
|
if(id(actual_page) < 0) {
|
||||||
|
id(actual_page) = id(nr_of_pages) - 1;
|
||||||
|
}
|
||||||
|
- script.execute: update_page
|
||||||
|
- id: set_page
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(active_page_name) = id(page_names)[id(actual_page)];
|
||||||
|
- sensor.template.publish:
|
||||||
|
id: active_page_id_ha
|
||||||
|
state: !lambda 'return id(actual_page);'
|
||||||
|
- text_sensor.template.publish:
|
||||||
|
id: active_page_name_ha
|
||||||
|
state: !lambda 'return id(active_page_name);'
|
||||||
|
- script.execute: update_all
|
||||||
|
- id: update_page
|
||||||
|
then:
|
||||||
|
- number.set:
|
||||||
|
id: menuselector
|
||||||
|
value: !lambda 'return id(actual_page);'
|
||||||
|
- script.execute: set_page
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[project]
|
||||||
|
name = "buttonplus-esphome-generator"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Generate ESPHome YAML for Button+ V2 (ESP32-S3)"
|
||||||
|
requires-python = ">=3.12"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
"""Button+ ESPHome generator package."""
|
||||||
|
__all__ = ["generator", "snippets"]
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
"""CLI tool to compose ESPHome YAML from snippets.
|
||||||
|
|
||||||
|
Usage: python main.py --pages 3 --notifications --led --output buttonplus.yaml
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from buttonplus_generator import snippets
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def deep_merge(a: Dict[str, Any], b: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""Recursively merge b into a and return a new dict.
|
||||||
|
|
||||||
|
Lists are concatenated; scalar values in b override a.
|
||||||
|
"""
|
||||||
|
result = dict(a)
|
||||||
|
for k, v in b.items():
|
||||||
|
if k in result:
|
||||||
|
if isinstance(result[k], dict) and isinstance(v, dict):
|
||||||
|
result[k] = deep_merge(result[k], v)
|
||||||
|
elif isinstance(result[k], list) and isinstance(v, list):
|
||||||
|
result[k] = result[k] + v
|
||||||
|
else:
|
||||||
|
result[k] = v
|
||||||
|
else:
|
||||||
|
result[k] = v
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def compose_config(device_name: str, pages: int, notifications: bool, led: bool) -> Dict[str, Any]:
|
||||||
|
config = snippets.base_config(device_name)
|
||||||
|
config = deep_merge(config, snippets.pages(pages))
|
||||||
|
config = deep_merge(config, snippets.notifications(notifications))
|
||||||
|
config = deep_merge(config, snippets.led_control(led))
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def compose_from_profile(profile: str, device_name: str | None = None) -> str:
|
||||||
|
"""Load an existing esphome profile folder and return its raw YAML text.
|
||||||
|
|
||||||
|
We intentionally return raw text because ESPHome config files use tags
|
||||||
|
like `!include` and `!secret` that PyYAML does not understand by
|
||||||
|
default. If `device_name` is provided we do a simple textual replace of
|
||||||
|
the `esphome.name` value.
|
||||||
|
"""
|
||||||
|
base = Path(__file__).resolve().parents[2]
|
||||||
|
profile_path = base / "esphome" / profile / "config.yaml"
|
||||||
|
if not profile_path.exists():
|
||||||
|
raise FileNotFoundError(f"Profile config not found: {profile_path}")
|
||||||
|
text = profile_path.read_text(encoding="utf-8")
|
||||||
|
if device_name:
|
||||||
|
# Replace the first occurrence of `esphome:` block name line.
|
||||||
|
# This is a conservative textual substitution and avoids full YAML parsing.
|
||||||
|
import re
|
||||||
|
|
||||||
|
def _repl(match: re.Match) -> str:
|
||||||
|
indent = match.group(1)
|
||||||
|
return f"{indent}name: {device_name}"
|
||||||
|
|
||||||
|
# Look for a line like: (some spaces)name: <value> that follows an `esphome:` line
|
||||||
|
text = re.sub(r"(^\s*)name:\s*.*$", _repl, text, count=1, flags=re.M)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv=None) -> int:
|
||||||
|
parser = argparse.ArgumentParser(description="Generate ESPHome YAML for Button+")
|
||||||
|
parser.add_argument("--device-name", default="buttonplus", help="ESPHome device name")
|
||||||
|
parser.add_argument("--pages", type=int, default=1, help="Number of pages")
|
||||||
|
parser.add_argument("--notifications", action="store_true", help="Enable notification features")
|
||||||
|
parser.add_argument("--led", action="store_true", help="Enable LED control")
|
||||||
|
parser.add_argument("--output", default="buttonplus.yaml", help="Output file path")
|
||||||
|
parser.add_argument("--profile", help="Use an existing esphome profile folder (e.g. 3bar_1display)")
|
||||||
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
|
if args.profile:
|
||||||
|
text = compose_from_profile(args.profile, device_name=args.device_name)
|
||||||
|
with open(args.output, "w", encoding="utf-8") as fh:
|
||||||
|
fh.write(text)
|
||||||
|
else:
|
||||||
|
config = compose_config(args.device_name, args.pages, args.notifications, args.led)
|
||||||
|
with open(args.output, "w", encoding="utf-8") as fh:
|
||||||
|
yaml.safe_dump(config, fh, sort_keys=False)
|
||||||
|
|
||||||
|
print(f"Wrote {args.output}")
|
||||||
|
return 0
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
"""Example snippet definitions for composing ESPHome YAML parts.
|
||||||
|
|
||||||
|
Each function returns a Python dict representing part of the final YAML.
|
||||||
|
Keep snippets small and composable — the generator deep-merges them.
|
||||||
|
"""
|
||||||
|
from typing import Dict, Any
|
||||||
|
from utils import slugify
|
||||||
|
|
||||||
|
def base_config(device_name: str = "buttonplus") -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"esphome": {
|
||||||
|
"name": slugify(device_name),
|
||||||
|
"friendly_name": device_name
|
||||||
|
},
|
||||||
|
"esp32":{
|
||||||
|
"variant": "ESP32S3",
|
||||||
|
"board": "esp32-s3-devkitc1-n16r8",
|
||||||
|
"flash_size": "16MB",
|
||||||
|
"framework": {
|
||||||
|
"type": "esp-idf"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wifi": {
|
||||||
|
"ssid": "!secret wifi_ssid",
|
||||||
|
"password": "!secret wifi_password",
|
||||||
|
},
|
||||||
|
"logger": {
|
||||||
|
"level": "DEBUG"
|
||||||
|
},
|
||||||
|
"api": {
|
||||||
|
"encryption": {
|
||||||
|
"key": "!secret encryption_key"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ota": [{
|
||||||
|
"platform": "esphome",
|
||||||
|
"password": "!secret ota_password"
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def notifications(enabled: bool) -> Dict[str, Any]:
|
||||||
|
if not enabled:
|
||||||
|
return {}
|
||||||
|
return {
|
||||||
|
"text_sensor": [
|
||||||
|
{
|
||||||
|
"platform": "template",
|
||||||
|
"name": "notification_text",
|
||||||
|
"id": "notification_text",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"binary_sensor": [
|
||||||
|
{
|
||||||
|
"platform": "gpio",
|
||||||
|
"pin": "GPIO0",
|
||||||
|
"name": "notification_button",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
def slugify(input : str) -> str:
|
||||||
|
s = input.lower()
|
||||||
|
s = re.sub(r'\s+', '_', s)
|
||||||
|
s = re.sub(r'[^a-z0-9_]+', '', s)
|
||||||
|
s = re.sub(r'_+', '_', s)
|
||||||
|
s = s.strip('_')
|
||||||
|
if not s:
|
||||||
|
s = 'buttonplus'
|
||||||
|
while len(s) > 1 and s[0].isdigit():
|
||||||
|
s = s[1:]
|
||||||
|
return s
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
from buttonplus_generator import generator
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generator.main()
|
||||||
Reference in New Issue
Block a user