Enhance configuration generation and merging
This commit is contained in:
@@ -2,28 +2,34 @@
|
||||
|
||||
A python script that generates a full ESPHome config for the Button+ V2
|
||||
|
||||
## Project uses pipenv
|
||||
## Features
|
||||
- Notification Service
|
||||
- And toasts!
|
||||
- Generate pages and all buttons and events belonging to each page
|
||||
|
||||
## Setup
|
||||
### 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
|
||||
|
||||
You can then use `python src/main.py --help` to run the generator
|
||||
|
||||
## Config example
|
||||
The configuration (handmade) on which this generator is based, can be found in the `esphome` folder.
|
||||
|
||||
# Todo
|
||||
## Todo
|
||||
|
||||
## Ideas
|
||||
- Notification service: until dismissed, or with timeout
|
||||
- Toast service, see above
|
||||
### Ideas
|
||||
- SHow image service
|
||||
- LED effects: flash, breathe
|
||||
- Top level config only for drawing, everything else hidden
|
||||
- back to using packages or includes probably
|
||||
- Allow adding of font and icons easily
|
||||
- LED set per page!
|
||||
|
||||
## Missing config
|
||||
### Missing config
|
||||
- Event lambda's (see config.yaml)
|
||||
- Implement --no-click-confirm
|
||||
- Add notification LED partition, in order to update multiple at the same time
|
||||
- Fix LED effects: Blink and Breathe
|
||||
- Dismiss notification button by changing page?
|
||||
- And make effects optional (--no-effects)
|
||||
@@ -28,6 +28,7 @@ def compose_config(
|
||||
click_types: List[ClickType],
|
||||
click_confirm: bool,
|
||||
services: bool,
|
||||
effects: bool
|
||||
) -> Dict[str, Any]:
|
||||
|
||||
# Base config
|
||||
@@ -38,7 +39,7 @@ def compose_config(
|
||||
# Display, if present
|
||||
if num_bars < 4:
|
||||
config = deep_merge(
|
||||
config, config_display(version=version, num_bars=num_bars, page_names=pages)
|
||||
config, config_display(version=version, num_bars=num_bars, page_names=pages, add_effects=effects)
|
||||
)
|
||||
|
||||
# Services, only available with display
|
||||
@@ -47,7 +48,7 @@ def compose_config(
|
||||
|
||||
# Bars
|
||||
config = deep_merge(
|
||||
config, config_bars(version=version, num_bars=num_bars, page_names=pages)
|
||||
config, config_bars(version=version, num_bars=num_bars, page_names=pages, add_effects=effects)
|
||||
)
|
||||
|
||||
# Events
|
||||
@@ -160,6 +161,12 @@ def main(argv=None) -> int:
|
||||
action="store_true",
|
||||
help="Don't add any of the toast, notification or image services.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-effects",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Don't add any effects to the LEDs.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output", "-o", default="buttonplus.yaml", help="Output file path"
|
||||
)
|
||||
@@ -171,11 +178,12 @@ def main(argv=None) -> int:
|
||||
pages: List[str] = args.pages
|
||||
click_types: List[ClickType] = list_to_click_type(args.click_types)
|
||||
click_confirm: bool = not args.no_click_confirm
|
||||
effects: bool = not args.no_effects
|
||||
services: bool = not args.no_services
|
||||
output: str = args.output
|
||||
|
||||
config = compose_config(
|
||||
device_name, version, num_bars, pages, click_types, click_confirm, services
|
||||
device_name, version, num_bars, pages, click_types, click_confirm, services, effects
|
||||
)
|
||||
with open(output, "w", encoding="utf-8") as fh:
|
||||
fh.writelines(
|
||||
|
||||
@@ -28,7 +28,7 @@ def list_merge(a: List[Any], b: List[Any]) -> List[Any]:
|
||||
|
||||
Steps:
|
||||
1. Check if both lists contain Dicts with an `id` key in them
|
||||
1a. Otherwise just return a + b (extend)
|
||||
1a. Otherwise do a pre-append list merge (extend)
|
||||
2. For every entry in a:
|
||||
3. Store id in a list for later
|
||||
4. Find the same id in b, if not found add to result without merge
|
||||
@@ -47,44 +47,92 @@ def list_merge(a: List[Any], b: List[Any]) -> List[Any]:
|
||||
|
||||
# If there are no id-based dicts in either list, just extend
|
||||
if not (a_has_id and b_has_id):
|
||||
return list(a) + list(b)
|
||||
return pre_append_list_merge(a, b)
|
||||
|
||||
result: List[Any] = []
|
||||
seen_ids = set()
|
||||
|
||||
# Merge entries from `a`, matching by `id` in `b` when present
|
||||
for item in a:
|
||||
# There is an `id`` field
|
||||
if isinstance(item, dict) and "id" in item:
|
||||
id_val = item.get("id")
|
||||
|
||||
# find matching entry in b
|
||||
match = None
|
||||
for bi in b:
|
||||
# check if b also had `id` field with the same value
|
||||
if isinstance(bi, dict) and bi.get("id") == id_val:
|
||||
match = bi
|
||||
break
|
||||
|
||||
# Both a and b have a matching `id` entry, so deep merge the dict
|
||||
if match is not None:
|
||||
# deep_merge returns a new dict
|
||||
merged = deep_merge(item, match)
|
||||
result.append(merged)
|
||||
# No match, just copy entry from `a`
|
||||
else:
|
||||
result.append(item)
|
||||
|
||||
# Store all the id's that we have seen
|
||||
if id_val is not None:
|
||||
seen_ids.add(id_val)
|
||||
|
||||
# No `id` field, just add to the list
|
||||
else:
|
||||
# Not an id'd dict, keep as-is
|
||||
result.append(item)
|
||||
|
||||
# Add remaining entries from b that were not merged or that don't have ids
|
||||
for item in b:
|
||||
# There is an `id`` field (we only copy missing id's)
|
||||
if isinstance(item, dict) and "id" in item:
|
||||
id_val = item.get("id")
|
||||
|
||||
# Empty id, just add it
|
||||
if id_val is None:
|
||||
result.append(item)
|
||||
|
||||
# Add the entry if is an unknown id (not already merged with an `a` entry)
|
||||
elif id_val not in seen_ids:
|
||||
result.append(item)
|
||||
# No id field, just add it
|
||||
else:
|
||||
result.append(item)
|
||||
|
||||
# Return the merged list
|
||||
return result
|
||||
|
||||
def pre_append_list_merge(a: List[Any], b: List[Any]) -> List[Any]:
|
||||
|
||||
# Detect whether both lists contain dicts with an 'prepend' key
|
||||
a_has_prepend = any(isinstance(x, dict) and "prepend" in x for x in a)
|
||||
b_has_prepend = any(isinstance(x, dict) and "prepend" in x for x in b)
|
||||
|
||||
# If there are no `prepend` keys in either list, just extend
|
||||
if not a_has_prepend and not b_has_prepend:
|
||||
return list(a) + list(b)
|
||||
|
||||
prepend_list = []
|
||||
append_list = []
|
||||
|
||||
def do_pre_or_append(entry: Dict[str, Any]) -> None:
|
||||
# There is a `prepend` field
|
||||
if isinstance(entry, dict) and "prepend" in entry:
|
||||
prepend = entry.pop("prepend")
|
||||
|
||||
if(prepend):
|
||||
# Append, so that the prepend order stays the same as how they are inserted
|
||||
prepend_list.append(entry)
|
||||
else:
|
||||
append_list.append(entry)
|
||||
else:
|
||||
append_list.append(entry)
|
||||
|
||||
for item in a:
|
||||
do_pre_or_append(item)
|
||||
|
||||
for item in b:
|
||||
do_pre_or_append(item)
|
||||
|
||||
return list(prepend_list) + list(append_list)
|
||||
@@ -4,14 +4,14 @@ from buttonplus_generator.merger import deep_merge
|
||||
from buttonplus_generator.utils import get_light_effects
|
||||
|
||||
|
||||
def config_bars(version: int, num_bars: int, page_names: List[str]) -> Dict[str, Any]:
|
||||
def config_bars(version: int, num_bars: int, page_names: List[str], add_effects: bool) -> Dict[str, Any]:
|
||||
config = bars_backlight()
|
||||
config = deep_merge(config, bars_setup(num_bars=num_bars))
|
||||
config = deep_merge(config, bars_buttons(num_bars=num_bars))
|
||||
config = deep_merge(
|
||||
config,
|
||||
bars_lights(
|
||||
num_bars=num_bars, display_has_leds=(version == 2 and num_bars < 4)
|
||||
num_bars=num_bars, display_has_leds=(version == 2 and num_bars < 4), add_effects=add_effects
|
||||
),
|
||||
)
|
||||
config = deep_merge(config, bars_display_output(num_bars=num_bars))
|
||||
@@ -171,7 +171,7 @@ def _bar_button_entry(bar_nr: int, base_id: str) -> List[Dict[str, Any]]:
|
||||
]
|
||||
|
||||
|
||||
def bars_lights(num_bars: int, display_has_leds: bool = True) -> Dict[str, Any]:
|
||||
def bars_lights(num_bars: int, display_has_leds: bool, add_effects: bool) -> Dict[str, Any]:
|
||||
bar_dict = {"light": []}
|
||||
|
||||
if num_bars < 1:
|
||||
@@ -180,49 +180,52 @@ def bars_lights(num_bars: int, display_has_leds: bool = True) -> Dict[str, Any]:
|
||||
display_offset = 4 if display_has_leds else 0
|
||||
|
||||
if num_bars > 0:
|
||||
bar_dict["light"].extend(_bar_lights_entry(1, 0 + display_offset))
|
||||
bar_dict["light"].extend(_bar_lights_entry(1, 0 + display_offset, add_effects))
|
||||
|
||||
if num_bars > 1:
|
||||
bar_dict["light"].extend(_bar_lights_entry(2, 4 + display_offset))
|
||||
bar_dict["light"].extend(_bar_lights_entry(2, 4 + display_offset, add_effects))
|
||||
|
||||
if num_bars > 2:
|
||||
bar_dict["light"].extend(_bar_lights_entry(3, 8 + display_offset))
|
||||
bar_dict["light"].extend(_bar_lights_entry(3, 8 + display_offset, add_effects))
|
||||
|
||||
if num_bars > 3:
|
||||
bar_dict["light"].extend(_bar_lights_entry(4, 12)) # no display
|
||||
bar_dict["light"].extend(_bar_lights_entry(4, 12, add_effects)) # no display
|
||||
|
||||
return bar_dict
|
||||
|
||||
|
||||
def _bar_lights_entry(bar_nr: int, offset: int) -> List[Dict[str, Any]]:
|
||||
def _bar_lights_entry(bar_nr: int, offset: int, add_effects: bool) -> List[Dict[str, Any]]:
|
||||
|
||||
light_effects = get_light_effects(add_effects)
|
||||
|
||||
return [
|
||||
{
|
||||
"platform": "partition",
|
||||
"name": f"BAR {bar_nr} Left RGB Front",
|
||||
"id": f"bar{bar_nr}_left_rgb_front",
|
||||
"segments": [{"id": "neopixels", "from": offset + 0, "to": offset + 0}],
|
||||
"effects": get_light_effects()
|
||||
"effects": light_effects
|
||||
},
|
||||
{
|
||||
"platform": "partition",
|
||||
"name": f"BAR {bar_nr} Left RGB Back",
|
||||
"id": f"bar{bar_nr}_left_rgb_back",
|
||||
"segments": [{"id": "neopixels", "from": offset + 1, "to": offset + 1}],
|
||||
"effects": get_light_effects()
|
||||
"effects": light_effects
|
||||
},
|
||||
{
|
||||
"platform": "partition",
|
||||
"name": f"BAR {bar_nr} Right RGB Front",
|
||||
"id": f"bar{bar_nr}_right_rgb_front",
|
||||
"segments": [{"id": "neopixels", "from": offset + 2, "to": offset + 2}],
|
||||
"effects": get_light_effects()
|
||||
"effects": light_effects
|
||||
},
|
||||
{
|
||||
"platform": "partition",
|
||||
"name": f"BAR {bar_nr} Right RGB Back",
|
||||
"id": f"bar{bar_nr}_right_rgb_back",
|
||||
"segments": [{"id": "neopixels", "from": offset + 3, "to": offset + 3}],
|
||||
"effects": get_light_effects()
|
||||
"effects": light_effects
|
||||
},
|
||||
]
|
||||
|
||||
@@ -359,6 +362,7 @@ def _bars_script_update_entry(
|
||||
|
||||
generated_cpp = ""
|
||||
|
||||
# Loop through both lists at the same time
|
||||
for bar, state in zip(bars_ids, bars_state):
|
||||
generated_cpp += f"id({bar}).turn_{state}();\n"
|
||||
|
||||
@@ -437,7 +441,7 @@ def _bars_script_draw_entry(
|
||||
f" // Page {page_num} - {page_names[page_num]}\n"
|
||||
f" case {page_num}:\n"
|
||||
f' id(bar_display).printf(80, 0, id(font_arial20), id(accent), TextAlign::TOP_CENTER , "Bar {bar_nr} {bar_side}");\n'
|
||||
f' id(bar_display).printf(80, 80, id(font_arial20), id(white), TextAlign::BOTTOM_CENTER , "Page {page_num}");\n'
|
||||
f' id(bar_display).printf(80, 80, id(font_arial20), id(white), TextAlign::BOTTOM_CENTER , "{page_names[page_num]}");\n'
|
||||
f" break;\n"
|
||||
)
|
||||
|
||||
|
||||
@@ -44,7 +44,10 @@ def base_config(device_name: str) -> Dict[str, Any]:
|
||||
"friendly_name": device_name,
|
||||
"on_boot": {
|
||||
"priority": -100,
|
||||
"then": [{"script.execute": "setup_bar_displays"}],
|
||||
"then": [
|
||||
{"script.execute": "setup_bar_displays"},
|
||||
{"script.execute": "test_all_leds"},
|
||||
],
|
||||
},
|
||||
},
|
||||
"esp32": {
|
||||
@@ -145,22 +148,32 @@ def pages(nr_of_pages: int, page_names: List[str]) -> Dict[str, Any]:
|
||||
}
|
||||
]
|
||||
|
||||
next_page_cpp = (
|
||||
"id(active_page_nr) = id(active_page_nr) + 1;\n"
|
||||
"if(id(active_page_nr) >= id(nr_of_pages)) {\n"
|
||||
" id(active_page_nr) = 0;\n"
|
||||
"}"
|
||||
)
|
||||
|
||||
prev_page_cpp = (
|
||||
"id(active_page_nr) = id(active_page_nr) - 1;\n"
|
||||
"if(id(active_page_nr) < 0) {\n"
|
||||
" id(active_page_nr) = id(nr_of_pages) - 1;\n"
|
||||
"}"
|
||||
)
|
||||
|
||||
page_dict["script"] = [
|
||||
{
|
||||
"id": "next_page",
|
||||
"then": [
|
||||
{
|
||||
"lambda": "id(active_page_nr) = id(active_page_nr) + 1;\nif(id(active_page_nr) >= id(nr_of_pages)) {\n id(active_page_nr) = 0;\n}"
|
||||
},
|
||||
{"lambda": next_page_cpp},
|
||||
{"script.execute": "update_page"},
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "prev_page",
|
||||
"then": [
|
||||
{
|
||||
"lambda": "id(active_page_nr) = id(active_page_nr) - 1;\nif(id(active_page_nr) < 0) {\n id(active_page_nr) = id(nr_of_pages) - 1;\n}"
|
||||
},
|
||||
{"lambda": prev_page_cpp},
|
||||
{"script.execute": "update_page"},
|
||||
],
|
||||
},
|
||||
@@ -248,6 +261,43 @@ def spi() -> Dict[str, Any]:
|
||||
|
||||
def neopixels(num_leds: int) -> Dict[str, Any]:
|
||||
return {
|
||||
"script": [
|
||||
{
|
||||
"id": "test_all_leds",
|
||||
"then": [
|
||||
{"delay": "1000ms"},
|
||||
{
|
||||
"light.turn_on": {
|
||||
"id": "internal_all_rgb",
|
||||
"red": "100%",
|
||||
"green": "0%",
|
||||
"blue": "0%",
|
||||
"flash_length": "100ms",
|
||||
}
|
||||
},
|
||||
{"delay": "200ms"},
|
||||
{
|
||||
"light.turn_on": {
|
||||
"id": "internal_all_rgb",
|
||||
"red": "0%",
|
||||
"green": "100%",
|
||||
"blue": "0%",
|
||||
"flash_length": "100ms",
|
||||
}
|
||||
},
|
||||
{"delay": "200ms"},
|
||||
{
|
||||
"light.turn_on": {
|
||||
"id": "internal_all_rgb",
|
||||
"red": "0%",
|
||||
"green": "0%",
|
||||
"blue": "100%",
|
||||
"flash_length": "100ms",
|
||||
}
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
"light": [
|
||||
{
|
||||
"platform": "esp32_rmt_led_strip",
|
||||
@@ -256,8 +306,21 @@ def neopixels(num_leds: int) -> Dict[str, Any]:
|
||||
"chipset": "ws2812",
|
||||
"pin": GPIO_NEOPIXELS,
|
||||
"num_leds": num_leds,
|
||||
"internal": True,
|
||||
},
|
||||
]
|
||||
{
|
||||
"platform": "partition",
|
||||
"id": "internal_all_rgb",
|
||||
"internal": True,
|
||||
"segments": [
|
||||
{
|
||||
"id": "neopixels",
|
||||
"from": 0,
|
||||
"to": num_leds - 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -328,6 +391,7 @@ def sensors(ambient_gain: str, extra_ambient_sensors: bool) -> Dict[str, Any]:
|
||||
|
||||
return sensors_dict
|
||||
|
||||
|
||||
def update_scripts(num_bars: int) -> Dict[str, Any]:
|
||||
common_dict = {"script": []}
|
||||
|
||||
@@ -339,13 +403,17 @@ def update_scripts(num_bars: int) -> Dict[str, Any]:
|
||||
]
|
||||
|
||||
if num_bars < 4:
|
||||
update_list.extend([
|
||||
update_list.extend(
|
||||
[
|
||||
{
|
||||
"script.execute": "update_main",
|
||||
},
|
||||
{"delay": "0.1s"},
|
||||
])
|
||||
]
|
||||
)
|
||||
|
||||
common_dict["script"].append({"id": "update_all", "then": update_list[:-1]})
|
||||
common_dict["script"].append(
|
||||
{"id": "update_all", "mode": "restart", "then": update_list[:-1]}
|
||||
)
|
||||
|
||||
return common_dict
|
||||
@@ -4,12 +4,12 @@ from buttonplus_generator.utils import get_display_id, get_display_address, get_
|
||||
from buttonplus_generator.merger import deep_merge
|
||||
|
||||
|
||||
def config_display(version: int, num_bars: int, page_names: List[str]) -> Dict[str, Any]:
|
||||
def config_display(version: int, num_bars: int, page_names: List[str], add_effects: bool) -> Dict[str, Any]:
|
||||
config = display_backlight(num_bars=num_bars)
|
||||
config = deep_merge(config, display_setup(num_bars=num_bars))
|
||||
config = deep_merge(config, display_buttons(num_bars=num_bars))
|
||||
config = deep_merge(
|
||||
config, display_lights(num_bars=num_bars, display_has_leds=(version == 2))
|
||||
config, display_lights(num_bars=num_bars, display_has_leds=(version == 2), add_effects=add_effects)
|
||||
)
|
||||
config = deep_merge(config, update_scripts(page_names=page_names))
|
||||
|
||||
@@ -112,13 +112,15 @@ def display_buttons(num_bars: int) -> Dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def display_lights(num_bars: int, display_has_leds: bool = True) -> Dict[str, Any]:
|
||||
def display_lights(num_bars: int, display_has_leds: bool, add_effects: bool) -> Dict[str, Any]:
|
||||
if not display_has_leds:
|
||||
return {}
|
||||
|
||||
if num_bars > 3:
|
||||
raise ValueError("At most three bars must be connected to use a display!")
|
||||
|
||||
light_effects = get_light_effects(add_effects)
|
||||
|
||||
return {
|
||||
"light": [
|
||||
{
|
||||
@@ -126,28 +128,28 @@ def display_lights(num_bars: int, display_has_leds: bool = True) -> Dict[str, An
|
||||
"name": "Main Display Left RGB Front",
|
||||
"id": "main_display_left_rgb_front",
|
||||
"segments": [{"id": "neopixels", "from": 0, "to": 0}],
|
||||
"effects": get_light_effects()
|
||||
"effects": light_effects
|
||||
},
|
||||
{
|
||||
"platform": "partition",
|
||||
"name": "Main Display Left RGB Back",
|
||||
"id": "main_display_left_rgb_back",
|
||||
"segments": [{"id": "neopixels", "from": 1, "to": 1}],
|
||||
"effects": get_light_effects()
|
||||
"effects": light_effects
|
||||
},
|
||||
{
|
||||
"platform": "partition",
|
||||
"name": "Main Display Right RGB Front",
|
||||
"id": "main_display_right_rgb_front",
|
||||
"segments": [{"id": "neopixels", "from": 2, "to": 2}],
|
||||
"effects": get_light_effects()
|
||||
"effects": light_effects
|
||||
},
|
||||
{
|
||||
"platform": "partition",
|
||||
"name": "Main Display Right RGB Back",
|
||||
"id": "main_display_right_rgb_back",
|
||||
"segments": [{"id": "neopixels", "from": 3, "to": 3}],
|
||||
"effects": get_light_effects()
|
||||
"effects": light_effects
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ def _generate_event_names(
|
||||
page_names: List[str], click_types: List[ClickType]
|
||||
) -> List[str]:
|
||||
return [
|
||||
f"{str(ct)} page {page_num}"
|
||||
for page_num in range(0, len(page_names))
|
||||
f"{str(ct)} {page}"
|
||||
for page in page_names
|
||||
for ct in click_types
|
||||
]
|
||||
|
||||
@@ -267,7 +267,7 @@ def _timing_entry(
|
||||
"event_msg": YAMLLambda(
|
||||
'return "'
|
||||
+ event_type
|
||||
+ ' page " + std::to_string(id(active_page_nr));'
|
||||
+ ' " + id(active_page_name);'
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,15 +66,19 @@ def notification_service(version: int) -> Dict[str, Any]:
|
||||
"}\n"
|
||||
)
|
||||
|
||||
led_left = "main_display_left_rgb_front"
|
||||
led_right = "main_display_right_rgb_front"
|
||||
notification_led_partition_left = 0
|
||||
notification_led_partition_right = 2
|
||||
notification_led_left = "main_display_left_rgb_front"
|
||||
notification_led_right = "main_display_right_rgb_front"
|
||||
|
||||
# No display leds, switch to BAR 1 wall leds
|
||||
if version == 1:
|
||||
led_left = "bar1_left_rgb_back"
|
||||
led_right = "bar1_right_rgb_back"
|
||||
notification_led_partition_left = 1
|
||||
notification_led_partition_right = 3
|
||||
notification_led_left = "bar1_left_rgb_back"
|
||||
notification_led_right = "bar1_right_rgb_back"
|
||||
|
||||
return {
|
||||
service_dict = {
|
||||
"globals": [
|
||||
{"id": "internal_notify", "type": "std::string", "initial_value": ""}
|
||||
],
|
||||
@@ -100,17 +104,7 @@ def notification_service(version: int) -> Dict[str, Any]:
|
||||
"then": [
|
||||
{
|
||||
"light.turn_on": {
|
||||
"id": led_left,
|
||||
"brightness": "100%",
|
||||
"red": "100%",
|
||||
"green": "100%",
|
||||
"blue": "100%",
|
||||
"flash_length": "1s",
|
||||
}
|
||||
},
|
||||
{
|
||||
"light.turn_on": {
|
||||
"id": led_right,
|
||||
"id": "internal_notification_rgb",
|
||||
"brightness": "100%",
|
||||
"red": "100%",
|
||||
"green": "100%",
|
||||
@@ -122,6 +116,15 @@ def notification_service(version: int) -> Dict[str, Any]:
|
||||
],
|
||||
}
|
||||
},
|
||||
{
|
||||
"wait_until": {
|
||||
"condition": {
|
||||
"lambda": "return id(internal_notify).size() == 0;"
|
||||
}
|
||||
}
|
||||
},
|
||||
{"light.control": {"id": notification_led_left}},
|
||||
{"light.control": {"id": notification_led_right}},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -138,4 +141,51 @@ def notification_service(version: int) -> Dict[str, Any]:
|
||||
},
|
||||
]
|
||||
},
|
||||
"light": [
|
||||
{
|
||||
"platform": "partition",
|
||||
"id": "internal_notification_rgb",
|
||||
"internal": True,
|
||||
"segments": [
|
||||
{
|
||||
"id": "neopixels",
|
||||
"from": notification_led_partition_left,
|
||||
"to": notification_led_partition_left,
|
||||
},
|
||||
{
|
||||
"id": "neopixels",
|
||||
"from": notification_led_partition_right,
|
||||
"to": notification_led_partition_right,
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
dismiss_notification = {
|
||||
"prepend": True,
|
||||
"if": {
|
||||
"condition": [
|
||||
{"lambda": YAMLLambda("return id(internal_notify).size() > 0;")}
|
||||
],
|
||||
"then": [
|
||||
{
|
||||
"globals.set": {
|
||||
"id": "internal_notify",
|
||||
"value": YAMLLambda("return std::string();"),
|
||||
},
|
||||
},
|
||||
{"script.execute": "update_main"},
|
||||
{"script.stop": "next_page"},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
service_dict["script"].extend(
|
||||
[
|
||||
{"id": "next_page", "then": [dismiss_notification]},
|
||||
{"id": "prev_page", "then": [dismiss_notification]},
|
||||
]
|
||||
)
|
||||
|
||||
return service_dict
|
||||
|
||||
@@ -32,23 +32,25 @@ def get_display_address(num_bars : int) -> str:
|
||||
|
||||
return 0x23 - num_bars
|
||||
|
||||
def get_light_effects() -> List[Dict[str, Any]]:
|
||||
def get_light_effects(enabled: bool) -> List[Dict[str, Any]]:
|
||||
if not enabled:
|
||||
return []
|
||||
|
||||
return [
|
||||
{
|
||||
"pulse": {
|
||||
"name": "Breathe",
|
||||
"transition_length": "500ms",
|
||||
"update_interval": "2s"
|
||||
"transition_length": "1s",
|
||||
"update_interval": "1.5s",
|
||||
"min_brightness": "20%",
|
||||
"max_brightness": "100%"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pulse": {
|
||||
"name": "Blink",
|
||||
"transition_length": {
|
||||
"on_length": "500ms",
|
||||
"off_length": "1s"
|
||||
},
|
||||
"update_interval": "100ms"
|
||||
"transition_length": "50ms",
|
||||
"update_interval": "500ms"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user