Implement led per page
This commit is contained in:
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"python.analysis.typeCheckingMode": "basic"
|
||||
}
|
||||
@@ -21,15 +21,20 @@ The configuration (handmade) on which this generator is based, can be found in t
|
||||
## Todo
|
||||
|
||||
### Ideas
|
||||
- SHow image service
|
||||
- LED effects: flash, breathe
|
||||
- Show image service
|
||||
- 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!
|
||||
- with --no-split option
|
||||
- two files
|
||||
|
||||
### Missing config
|
||||
- Event lambda's (see config.yaml)
|
||||
- Implement --no-click-confirm
|
||||
- Fix LED effects: Blink and Breathe
|
||||
- And make effects optional (--no-effects)
|
||||
- Make effects optional (--no-effects)
|
||||
- service: get led state
|
||||
- led name
|
||||
- page name
|
||||
- page num
|
||||
- service: get_page_info
|
||||
- rename the service
|
||||
- add the effect options
|
||||
@@ -16,6 +16,7 @@ from buttonplus_generator.snippets.bars import config_bars
|
||||
from buttonplus_generator.snippets.display import config_display
|
||||
from buttonplus_generator.snippets.events import config_events
|
||||
from buttonplus_generator.snippets.services import config_services
|
||||
from buttonplus_generator.snippets.leds import config_leds
|
||||
from buttonplus_generator.merger import deep_merge
|
||||
from buttonplus_generator.utils import list_to_click_type
|
||||
|
||||
@@ -62,9 +63,11 @@ def compose_config(
|
||||
),
|
||||
)
|
||||
|
||||
config = deep_merge(config, config_leds(version=version, num_bars=num_bars, page_names=pages))
|
||||
|
||||
return config
|
||||
|
||||
def yaml_dumper(config: Dict[str, Any], fh) -> str:
|
||||
def yaml_dumper(config: Dict[str, Any], fh):
|
||||
|
||||
## Handle multiline strings
|
||||
def represent_multistr(dumper, data):
|
||||
@@ -79,6 +82,8 @@ def yaml_dumper(config: Dict[str, Any], fh) -> str:
|
||||
return dumper.represent_scalar("!extend", data.value)
|
||||
|
||||
def represent_lambda(dumper, data):
|
||||
if len(data.value.splitlines()) > 1: # check for multiline string
|
||||
return dumper.represent_scalar("!lambda", data.value, style="|")
|
||||
return dumper.represent_scalar("!lambda", data.value, style='"')
|
||||
|
||||
def represent_secret(dumper, data):
|
||||
|
||||
@@ -431,7 +431,7 @@ def bars_draw_scripts(num_bars: int, page_names: List[str]) -> Dict[str, Any]:
|
||||
update_list.extend(_bars_script_execute_entry(3, Side.LEFT))
|
||||
update_list.extend(_bars_script_execute_entry(3, Side.RIGHT))
|
||||
|
||||
bar_dict["script"].append({"id": "update_bars", "then": update_list[:-1]})
|
||||
bar_dict["script"].append({"id": bar_id(IdSuffix.SCRIPT_UPDATE, None), "then": update_list[:-1]})
|
||||
|
||||
return bar_dict
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Dict, Any, List
|
||||
from buttonplus_generator.merger import deep_merge
|
||||
from buttonplus_generator.utils import slugify, array_to_cpp_vector
|
||||
from buttonplus_generator.utils import bar_id, display_id, slugify, array_to_cpp_vector
|
||||
from buttonplus_generator.constants import *
|
||||
|
||||
|
||||
@@ -397,7 +397,7 @@ def update_scripts(num_bars: int) -> Dict[str, Any]:
|
||||
|
||||
update_list = [
|
||||
{
|
||||
"script.execute": "update_bars",
|
||||
"script.execute": bar_id(IdSuffix.SCRIPT_UPDATE, None),
|
||||
},
|
||||
{"delay": "0.1s"},
|
||||
]
|
||||
@@ -406,7 +406,7 @@ def update_scripts(num_bars: int) -> Dict[str, Any]:
|
||||
update_list.extend(
|
||||
[
|
||||
{
|
||||
"script.execute": "update_main",
|
||||
"script.execute": display_id(IdSuffix.SCRIPT_UPDATE),
|
||||
},
|
||||
{"delay": "0.1s"},
|
||||
]
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
from typing import Dict, Any, List
|
||||
from buttonplus_generator.constants import *
|
||||
from buttonplus_generator.merger import deep_merge
|
||||
from buttonplus_generator.utils import (
|
||||
array_to_cpp_vector,
|
||||
array_to_cpp_vector_raw,
|
||||
display_id,
|
||||
bar_id,
|
||||
)
|
||||
|
||||
|
||||
def config_leds(version: int, num_bars: int, page_names: List[str]) -> Dict[str, Any]:
|
||||
config = leds_globals(version=version, num_bars=num_bars, page_names=page_names)
|
||||
config = deep_merge(config, leds_actions(version=version, num_bars=num_bars))
|
||||
config = deep_merge(config, leds_script(version=version, num_bars=num_bars))
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def leds_actions(version: int, num_bars: int) -> Dict[str, Any]:
|
||||
|
||||
all_led_ids = _get_list_leds(version, num_bars)
|
||||
generated_cpp = ""
|
||||
|
||||
#TODO add effect to page info, or not if --no-effects
|
||||
|
||||
for led_id in all_led_ids:
|
||||
generated_cpp += f'leds.add("{led_id}");\n'
|
||||
|
||||
return {
|
||||
"api": {
|
||||
"actions": [
|
||||
{
|
||||
"action": "set_page_led",
|
||||
"variables": {
|
||||
"led": "string",
|
||||
"page_name": "string",
|
||||
"r": "float",
|
||||
"g": "float",
|
||||
"b": "float",
|
||||
"brightness": "float",
|
||||
"effect": "string",
|
||||
},
|
||||
"then": [
|
||||
{
|
||||
"if": {
|
||||
"condition": {
|
||||
"lambda": (
|
||||
"// Validate page_name if provided\n"
|
||||
"auto it = std::find(id(page_names).begin(), id(page_names).end(), page_name);\n"
|
||||
"if (it == id(page_names).end()) return true;\n"
|
||||
"return false;"
|
||||
)
|
||||
},
|
||||
"then": [
|
||||
{
|
||||
"api.respond": {
|
||||
"success": False,
|
||||
"error_message": "Invalid page_name (not found).",
|
||||
}
|
||||
}
|
||||
],
|
||||
"else": [
|
||||
{
|
||||
"if": {
|
||||
"condition": {
|
||||
"lambda": "return id(internal_page_leds_r).find(led) == id(internal_page_leds_r).end();"
|
||||
},
|
||||
"then": [
|
||||
{
|
||||
"api.respond": {
|
||||
"success": False,
|
||||
"error_message": "The requested LED does not exist.",
|
||||
}
|
||||
}
|
||||
],
|
||||
"else": [
|
||||
{
|
||||
"lambda": (
|
||||
"// Resolve final page index\n"
|
||||
"auto it = std::find(id(page_names).begin(), id(page_names).end(), page_name);\n"
|
||||
"int page_num = std::distance(id(page_names).begin(), it);\n"
|
||||
"\n"
|
||||
"id(internal_page_leds_r)[led][page_num] = r;\n"
|
||||
"id(internal_page_leds_g)[led][page_num] = g;\n"
|
||||
"id(internal_page_leds_b)[led][page_num] = b;\n"
|
||||
"id(internal_page_leds_brightness)[led][page_num] = brightness;\n"
|
||||
"id(internal_page_leds_effect)[led][page_num] = effect;"
|
||||
)
|
||||
},
|
||||
{"api.respond": {"success": True}},
|
||||
{
|
||||
"if": {
|
||||
"condition": {
|
||||
"lambda": (
|
||||
"auto it = std::find(id(page_names).begin(), id(page_names).end(), page_name);\n"
|
||||
"int page_num = std::distance(id(page_names).begin(), it);\n"
|
||||
"return page_num == id(active_page_nr);"
|
||||
)
|
||||
},
|
||||
"then": [
|
||||
{
|
||||
"script.execute": "update_all_page_leds"
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"action": "get_page_info",
|
||||
"supports_response": "only",
|
||||
"then": [
|
||||
{
|
||||
"api.respond": {
|
||||
"data": YAMLLambda(
|
||||
(
|
||||
'root["num_pages"] = id(nr_of_pages);\n'
|
||||
'JsonArray pages = root["page_names"].to<JsonArray>();\n'
|
||||
"for(const std::string& page_name : id(page_names)){\n"
|
||||
" pages.add(page_name);\n"
|
||||
"}\n"
|
||||
'JsonArray leds = root["leds"].to<JsonArray>();\n'
|
||||
)
|
||||
+ generated_cpp
|
||||
)
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def leds_script(version: int, num_bars: int) -> Dict[str, Any]:
|
||||
|
||||
all_led_ids = _get_list_leds(version, num_bars)
|
||||
generated_cpp = ""
|
||||
|
||||
for led_id in all_led_ids:
|
||||
generated_cpp += f'id(update_single_led).execute("{led_id}", id({led_id}), id(active_page_nr));\n'
|
||||
|
||||
return {
|
||||
"script": [
|
||||
{
|
||||
"id": "update_all_page_leds",
|
||||
"then": [{"lambda": generated_cpp}],
|
||||
},
|
||||
{
|
||||
"id": "update_single_led",
|
||||
"parameters": {
|
||||
"led_name": "string",
|
||||
"led_id": "light::LightState*",
|
||||
"page": "int",
|
||||
},
|
||||
"then": [
|
||||
{
|
||||
"lambda": (
|
||||
"if(led_id != nullptr){\n"
|
||||
" float r = id(internal_page_leds_r)[led_name][page];\n"
|
||||
" float g = id(internal_page_leds_g)[led_name][page];\n"
|
||||
" float b = id(internal_page_leds_b)[led_name][page];\n"
|
||||
" float br = id(internal_page_leds_brightness)[led_name][page];\n"
|
||||
" std::string effect = id(internal_page_leds_effect)[led_name][page];\n"
|
||||
" if(r > 1.5) r = r / 255.0;\n"
|
||||
" if(g > 1.5) g = g / 255.0;\n"
|
||||
" if(b > 1.5) b = b / 255.0;\n"
|
||||
" if(br > 1.5) br = br / 255.0;\n"
|
||||
" auto call = led_id->make_call();\n"
|
||||
" call.set_transition_length(10);\n"
|
||||
" if(br <= 0.0001) {\n"
|
||||
" call.set_state(false);\n"
|
||||
" } else {\n"
|
||||
" call.set_state(true);\n"
|
||||
" call.set_rgb(r,g,b);\n"
|
||||
" call.set_brightness(br);\n"
|
||||
" call.set_effect(effect);\n"
|
||||
" }\n"
|
||||
" call.perform();\n"
|
||||
"}"
|
||||
)
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "set_page",
|
||||
"then": [
|
||||
{"script.execute": "update_all_page_leds"},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def leds_globals(version: int, num_bars: int, page_names: List[str]) -> Dict[str, Any]:
|
||||
|
||||
all_led_ids = _get_list_leds(version, num_bars)
|
||||
|
||||
return {
|
||||
"globals": [
|
||||
{
|
||||
"id": "internal_page_leds_r",
|
||||
"type": "std::unordered_map<std::string, std::vector<float>>",
|
||||
"initial_value": _global_initialization_float(
|
||||
all_led_ids, len(page_names)
|
||||
),
|
||||
},
|
||||
{
|
||||
"id": "internal_page_leds_g",
|
||||
"type": "std::unordered_map<std::string, std::vector<float>>",
|
||||
"initial_value": _global_initialization_float(
|
||||
all_led_ids, len(page_names)
|
||||
),
|
||||
},
|
||||
{
|
||||
"id": "internal_page_leds_b",
|
||||
"type": "std::unordered_map<std::string, std::vector<float>>",
|
||||
"initial_value": _global_initialization_float(
|
||||
all_led_ids, len(page_names)
|
||||
),
|
||||
},
|
||||
{
|
||||
"id": "internal_page_leds_brightness",
|
||||
"type": "std::unordered_map<std::string, std::vector<float>>",
|
||||
"initial_value": _global_initialization_float(
|
||||
all_led_ids, len(page_names)
|
||||
),
|
||||
},
|
||||
{
|
||||
"id": "internal_page_leds_effect",
|
||||
"type": "std::unordered_map<std::string, std::vector<std::string>>",
|
||||
"initial_value": _global_initialization_string(
|
||||
all_led_ids, len(page_names)
|
||||
),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def _global_initialization_float(led_ids: List[str], num_pages: int) -> str:
|
||||
zero_floats = ["0.0" for _ in range(num_pages)]
|
||||
return _global_initialization(led_ids, array_to_cpp_vector_raw(zero_floats))
|
||||
|
||||
|
||||
def _global_initialization_string(led_ids: List[str], num_pages: int) -> str:
|
||||
zero_strings = ["" for _ in range(num_pages)]
|
||||
return _global_initialization(led_ids, array_to_cpp_vector(zero_strings))
|
||||
|
||||
|
||||
def _global_initialization(led_ids: List[str], init_list: str) -> str:
|
||||
"""
|
||||
{{"led_id_1", {0.0, 0.0}}, {"led_id_2", {0.0, 0.0}}};
|
||||
"""
|
||||
|
||||
init_str = "{"
|
||||
|
||||
for led in led_ids:
|
||||
init_str += '{"' + led + '", ' + init_list + "}, "
|
||||
|
||||
init_str = init_str[:-2] + "}"
|
||||
|
||||
return init_str
|
||||
|
||||
|
||||
def _get_list_leds(version: int, num_bars: int) -> List[str]:
|
||||
led_list: List[str] = []
|
||||
|
||||
if version == 2:
|
||||
led_list.append(display_id(IdSuffix.LED, Side.LEFT, Direction.FRONT))
|
||||
led_list.append(display_id(IdSuffix.LED, Side.RIGHT, Direction.FRONT))
|
||||
led_list.append(display_id(IdSuffix.LED, Side.LEFT, Direction.BACK))
|
||||
led_list.append(display_id(IdSuffix.LED, Side.RIGHT, Direction.BACK))
|
||||
|
||||
if num_bars > 0:
|
||||
led_list.append(bar_id(IdSuffix.LED, 1, Side.LEFT, Direction.FRONT))
|
||||
led_list.append(bar_id(IdSuffix.LED, 1, Side.RIGHT, Direction.FRONT))
|
||||
led_list.append(bar_id(IdSuffix.LED, 1, Side.LEFT, Direction.BACK))
|
||||
led_list.append(bar_id(IdSuffix.LED, 1, Side.RIGHT, Direction.BACK))
|
||||
|
||||
if num_bars > 1:
|
||||
led_list.append(bar_id(IdSuffix.LED, 2, Side.LEFT, Direction.FRONT))
|
||||
led_list.append(bar_id(IdSuffix.LED, 2, Side.RIGHT, Direction.FRONT))
|
||||
led_list.append(bar_id(IdSuffix.LED, 2, Side.LEFT, Direction.BACK))
|
||||
led_list.append(bar_id(IdSuffix.LED, 2, Side.RIGHT, Direction.BACK))
|
||||
|
||||
if num_bars > 2:
|
||||
led_list.append(bar_id(IdSuffix.LED, 3, Side.LEFT, Direction.FRONT))
|
||||
led_list.append(bar_id(IdSuffix.LED, 3, Side.RIGHT, Direction.FRONT))
|
||||
led_list.append(bar_id(IdSuffix.LED, 3, Side.LEFT, Direction.BACK))
|
||||
led_list.append(bar_id(IdSuffix.LED, 3, Side.RIGHT, Direction.BACK))
|
||||
|
||||
if num_bars > 3:
|
||||
led_list.append(bar_id(IdSuffix.LED, 3, Side.LEFT, Direction.FRONT))
|
||||
led_list.append(bar_id(IdSuffix.LED, 3, Side.RIGHT, Direction.FRONT))
|
||||
led_list.append(bar_id(IdSuffix.LED, 3, Side.LEFT, Direction.BACK))
|
||||
led_list.append(bar_id(IdSuffix.LED, 3, Side.RIGHT, Direction.BACK))
|
||||
|
||||
return led_list
|
||||
@@ -1,3 +1,4 @@
|
||||
import copy
|
||||
from typing import Dict, Any, List
|
||||
from buttonplus_generator.merger import deep_merge
|
||||
from buttonplus_generator.constants import *
|
||||
@@ -184,8 +185,8 @@ def notification_service(version: int) -> Dict[str, Any]:
|
||||
|
||||
service_dict["script"].extend(
|
||||
[
|
||||
{"id": "next_page", "then": [dismiss_notification]},
|
||||
{"id": "prev_page", "then": [dismiss_notification]},
|
||||
{"id": "next_page", "then": [copy.deepcopy(dismiss_notification)]},
|
||||
{"id": "prev_page", "then": [copy.deepcopy(dismiss_notification)]},
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user