diff --git a/README.md b/README.md index 35f3e97..b95b170 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,10 @@ The configuration (handmade) on which this generator is based, can be found in t - Notification service: until dismissed, or with timeout - 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 ## Missing config -- Scripts for updating displays (see scripts.yaml) -- Draw routines (see config.yaml) - Event generation (triggers and stuff, see events.yaml) - configurable timing and button events - Always set display to left and right page diff --git a/src/buttonplus_generator/constants.py b/src/buttonplus_generator/constants.py index f4d1d16..bac5c7b 100644 --- a/src/buttonplus_generator/constants.py +++ b/src/buttonplus_generator/constants.py @@ -1,5 +1,8 @@ ## GPIO Pins +from enum import StrEnum + + GPIO_NEOPIXELS = "GPIO4" #Neopixel LED's GPIO_SPI_MOSI = "GPIO5" #SPI MOSI GPIO_SPI_CLK = "GPIO6" #SPI SCK @@ -9,4 +12,23 @@ GPIO_BACKLIGHT_MINI = "GPIO46" #Backlight mini displays GPIO_I2C_BUTTONS_SDA = "GPIO1" #I2C SDA > Buttons GPIO_I2C_BUTTONS_SCL = "GPIO2" #I2C SCL > Buttons GPIO_I2C_SENSORS_SDA = "GPIO47" #I2C SDA > Temperature & Ambient Sensor -GPIO_I2C_SENSORS_SCL = "GPIO48" #I2S SCL > Temperature & Ambient Sensor \ No newline at end of file +GPIO_I2C_SENSORS_SCL = "GPIO48" #I2S SCL > Temperature & Ambient Sensor + +class BarSide(StrEnum): + LEFT = "left" + RIGHT = "right" + +class ClickTypes(StrEnum): + SINGLE = "single" + DOUBLE = "double" + TRIPLE = "triple" + HOLD = "hold" + +class YAMLExtend: + def __init__(self, value): self.value = value + +class YAMLLambda: + def __init__(self, value): self.value = value + +class YAMLSecret: + def __init__(self, value): self.value = value \ No newline at end of file diff --git a/src/buttonplus_generator/generator.py b/src/buttonplus_generator/generator.py index c9cf2af..fa86835 100644 --- a/src/buttonplus_generator/generator.py +++ b/src/buttonplus_generator/generator.py @@ -10,26 +10,29 @@ from typing import Any, Dict, List import yaml +from buttonplus_generator.constants import YAMLExtend, YAMLLambda, YAMLSecret from buttonplus_generator.snippets.common import config_common -from buttonplus_generator.snippets.display import config_display -from buttonplus_generator.merger import deep_merge 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.merger import deep_merge -def compose_config(device_name: str, version: int, num_bars: int, pages: List[str]) -> Dict[str, Any]: +def compose_config(device_name: str, version: int, num_bars: int, pages: List[str], click_types: List[str]) -> Dict[str, Any]: config = config_common(device_name=device_name, version=version, page_names=pages, num_bars=num_bars) if(num_bars < 4): # Always assume display if less than 4 bars - config = deep_merge(config, config_display(version=version, num_bars=num_bars)) + config = deep_merge(config, config_display(version=version, num_bars=num_bars, page_names=pages)) - config = deep_merge(config, config_bars(version=version, num_bars=num_bars)) + config = deep_merge(config, config_bars(version=version, num_bars=num_bars, page_names=pages)) + #config = deep_merge(config, config_events(version=version, num_bars=num_bars, page_names=pages, click_types=click_types)) return config def yaml_dumper(config: Dict[str, Any], fh) -> str: ## Handle multiline strings - def str_presenter(dumper, data): + def represent_multistr(dumper, data): """configures yaml for dumping multiline strings Ref: https://stackoverflow.com/questions/8640959/how-can-i-control-what-scalar-form-pyyaml-uses-for-my-data """ @@ -37,7 +40,20 @@ def yaml_dumper(config: Dict[str, Any], fh) -> str: return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') return dumper.represent_scalar('tag:yaml.org,2002:str', data) - yaml.add_representer(str, str_presenter) + def represent_extend(dumper, data): + return dumper.represent_scalar('!extend', data.value) + + def represent_lambda(dumper, data): + return dumper.represent_scalar('!lambda', data.value, style='"') + + def represent_secret(dumper, data): + return dumper.represent_scalar('!secret', data.value, style="'") + + yaml.add_representer(str, represent_multistr) + yaml.add_representer(YAMLExtend, represent_extend) + yaml.add_representer(YAMLLambda, represent_lambda) + yaml.add_representer(YAMLSecret, represent_secret) + yaml.dump(config, fh, sort_keys=False, encoding="utf-8", default_flow_style=False) def main(argv=None) -> int: @@ -47,8 +63,7 @@ def main(argv=None) -> int: ) parser.add_argument( "--device-name", - "--name", - "-n", + "-d", default="buttonplus", help="ESPHome device name", ) @@ -59,7 +74,7 @@ def main(argv=None) -> int: choices=[1,2], required=True, help="The version of the display and bars. Only V2 PCB is supported.", - metavar="VER" + metavar="[1|2]" ) parser.add_argument( "--bars", @@ -77,6 +92,14 @@ def main(argv=None) -> int: help="List of page names", metavar="NAME" ) + parser.add_argument( + "--click-types", + "-c", + nargs="+", + default=["single", "double", "triple", "hold"], + help="List click types buttons, choices are [single|double|triple|hold].", + metavar="TYPE" + ) parser.add_argument( "--output", "-o", default="buttonplus.yaml", help="Output file path" ) @@ -86,9 +109,10 @@ def main(argv=None) -> int: version: int = args.version num_bars: int = args.bars pages: List[str] = args.pages + click_types: List[str] = args.click_types output: str = args.output - config = compose_config(device_name, version, num_bars, pages) + config = compose_config(device_name, version, num_bars, pages, click_types) with open(output, "w", encoding="utf-8") as fh: fh.writelines( [ diff --git a/src/buttonplus_generator/snippets/bars.py b/src/buttonplus_generator/snippets/bars.py index 57b129f..a19be77 100644 --- a/src/buttonplus_generator/snippets/bars.py +++ b/src/buttonplus_generator/snippets/bars.py @@ -2,18 +2,27 @@ from typing import Dict, Any, List from buttonplus_generator.constants import * from buttonplus_generator.merger import deep_merge -def config_bars( - version: int, num_bars: int -) -> Dict[str, Any]: + +def config_bars(version: int, num_bars: int, page_names: List[str]) -> 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))) + config = deep_merge( + config, + bars_lights( + num_bars=num_bars, display_has_leds=(version == 2 and num_bars < 4) + ), + ) config = deep_merge(config, bars_display_output(num_bars=num_bars)) config = deep_merge(config, bars_display()) + config = deep_merge(config, bars_scripts(num_bars=num_bars)) + config = deep_merge( + config, bars_draw_scripts(num_bars=num_bars, page_names=page_names) + ) return config + def bars_backlight() -> Dict[str, Any]: return { "output": [ @@ -55,8 +64,10 @@ def bars_setup(num_bars: int = 3) -> Dict[str, Any]: ) scripts.extend( - [{"script.execute": "update_bar1_left"}, - {"script.execute": "update_bar1_right"}] + [ + {"script.execute": "update_bar1_left"}, + {"script.execute": "update_bar1_right"}, + ] ) # At least two bars, in bottom two slots @@ -66,8 +77,10 @@ def bars_setup(num_bars: int = 3) -> Dict[str, Any]: ) scripts.extend( - [{"script.execute": "update_bar2_left"}, - {"script.execute": "update_bar2_right"}] + [ + {"script.execute": "update_bar2_left"}, + {"script.execute": "update_bar2_right"}, + ] ) # At least three bars, in bottom three slots @@ -77,8 +90,10 @@ def bars_setup(num_bars: int = 3) -> Dict[str, Any]: ) scripts.extend( - [{"script.execute": "update_bar3_left"}, - {"script.execute": "update_bar3_right"}] + [ + {"script.execute": "update_bar3_left"}, + {"script.execute": "update_bar3_right"}, + ] ) # No display, only bars, also in top slot @@ -88,8 +103,10 @@ def bars_setup(num_bars: int = 3) -> Dict[str, Any]: ) scripts.extend( - [{"script.execute": "update_bar4_left"}, - {"script.execute": "update_bar4_right"}] + [ + {"script.execute": "update_bar4_left"}, + {"script.execute": "update_bar4_right"}, + ] ) bar_dict["esphome"] = {"on_boot": {"then": scripts}} @@ -169,62 +186,40 @@ def bars_lights(num_bars: int, display_has_leds: bool = True) -> Dict[str, Any]: bar_dict["light"].extend(_bar_lights_entry(3, 8 + display_offset)) if num_bars > 3: - bar_dict["light"].extend(_bar_lights_entry(4, 12)) # no display + bar_dict["light"].extend(_bar_lights_entry(4, 12)) # no display return bar_dict + def _bar_lights_entry(bar_nr: int, offset: int) -> List[Dict[str, Any]]: 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 - } - ] - }, - { - "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 - } - ] - }, - { - "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 - } - ] - }, - { - "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 - } - ] - }, + "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}], + }, + { + "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}], + }, + { + "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}], + }, + { + "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}], + }, ] - + + def bars_display_output(num_bars: int = 3) -> Dict[str, Any]: bar_dict = {"output": []} @@ -260,9 +255,7 @@ def _bar_display_output_entry(bar_nr: int, base_id: str) -> List[Dict[str, Any]] "pin": { "mcp23xxx": base_id, "number": 5, - "mode": { - "output": True - }, + "mode": {"output": True}, "inverted": True, }, }, @@ -272,14 +265,13 @@ def _bar_display_output_entry(bar_nr: int, base_id: str) -> List[Dict[str, Any]] "pin": { "mcp23xxx": base_id, "number": 1, - "mode": { - "output": True - }, + "mode": {"output": True}, "inverted": True, }, }, ] - + + def bars_display() -> Dict[str, Any]: return { "display": [ @@ -289,18 +281,168 @@ def bars_display() -> Dict[str, Any]: "model": "ST7735", "color_order": "bgr", "update_interval": "never", - "dc_pin": { - "number": GPIO_SPI_REG, - "allow_other_uses": True - }, + "dc_pin": {"number": GPIO_SPI_REG, "allow_other_uses": True}, "invert_colors": False, "show_test_card": False, "auto_clear_enabled": False, - "dimensions": { - "height": 160, - "width": 80, - "offset_width": 24 - } + "dimensions": {"height": 160, "width": 80, "offset_width": 24}, } ], - } \ No newline at end of file + } + + +def bars_scripts(num_bars: int) -> Dict[str, Any]: + bar_dict = {"script": []} + + if num_bars < 1: + raise ValueError("At least one bar must be connected!") + + setup_cpp = "" + + if num_bars > 0: + bar_dict["script"].append(_bars_script_update_entry(1, BarSide.LEFT, num_bars)) + bar_dict["script"].append(_bars_script_update_entry(1, BarSide.RIGHT, num_bars)) + + setup_cpp += _bars_script_setup_entry(1, BarSide.LEFT) + setup_cpp += _bars_script_setup_entry(1, BarSide.RIGHT) + + if num_bars > 1: + bar_dict["script"].append(_bars_script_update_entry(2, BarSide.LEFT, num_bars)) + bar_dict["script"].append(_bars_script_update_entry(2, BarSide.RIGHT, num_bars)) + + setup_cpp += _bars_script_setup_entry(2, BarSide.LEFT) + setup_cpp += _bars_script_setup_entry(2, BarSide.RIGHT) + + if num_bars > 2: + bar_dict["script"].append(_bars_script_update_entry(3, BarSide.LEFT, num_bars)) + bar_dict["script"].append(_bars_script_update_entry(3, BarSide.RIGHT, num_bars)) + + setup_cpp += _bars_script_setup_entry(3, BarSide.LEFT) + setup_cpp += _bars_script_setup_entry(3, BarSide.RIGHT) + + if num_bars > 3: + bar_dict["script"].append(_bars_script_update_entry(4, BarSide.LEFT, num_bars)) + bar_dict["script"].append(_bars_script_update_entry(4, BarSide.RIGHT, num_bars)) + + setup_cpp += _bars_script_setup_entry(4, BarSide.LEFT) + setup_cpp += _bars_script_setup_entry(4, BarSide.RIGHT) + + bar_dict["script"].append( + {"id": "setup_bar_displays", "then": [{"lambda": setup_cpp}]} + ) + + return bar_dict + + +def _bars_script_update_entry( + bar_nr: int, bar_side: BarSide, num_bars: int +) -> Dict[str, Any]: + + # Generate all possible bars + bars_ids = [ + f"cs_pin_bar{nr}_{side}" + for nr in range(1, num_bars + 1) + for side in [BarSide.LEFT, BarSide.RIGHT] + ] + bars_state = [ + "on" if (nr is bar_nr and side is bar_side) else "off" + for nr in range(1, num_bars + 1) + for side in [BarSide.LEFT, BarSide.RIGHT] + ] + + generated_cpp = "" + + for bar, state in zip(bars_ids, bars_state): + generated_cpp += f"id({bar}).turn_{state}();\n" + + rotation = "90" if bar_side is BarSide.RIGHT else "270" + + generated_cpp += ( + "id(bar_display).clear();\n" + f"id(bar_display).set_rotation(display::DisplayRotation::DISPLAY_ROTATION_{rotation}_DEGREES);\n" + f"id(bar{bar_nr}_{bar_side}_draw).execute();\n" + "id(bar_display).update();\n" + "delay(1);\n" + f"id(cs_pin_bar{bar_nr}_{bar_side}).turn_off();" + ) + + return {"id": f"update_bar{bar_nr}_{bar_side}", "then": [{"lambda": generated_cpp}]} + + +def _bars_script_setup_entry(bar_nr: int, bar_side: BarSide) -> str: + return ( + f"id(cs_pin_bar{bar_nr}_{bar_side}).turn_on();\n" + "id(bar_display).setup();\n" + "delay(5);\n" + f"id(cs_pin_bar{bar_nr}_{bar_side}).turn_off();\n" + ) + + +def bars_draw_scripts(num_bars: int, page_names: List[str]) -> Dict[str, Any]: + bar_dict = {"script": []} + + if num_bars < 1: + raise ValueError("At least one bar must be connected!") + + update_list = [] + + if num_bars > 0: + bar_dict["script"].append(_bars_script_draw_entry(1, BarSide.LEFT, page_names)) + bar_dict["script"].append(_bars_script_draw_entry(1, BarSide.RIGHT, page_names)) + + update_list.extend(_bars_script_execute_entry(1, BarSide.LEFT)) + update_list.extend(_bars_script_execute_entry(1, BarSide.RIGHT)) + + if num_bars > 1: + bar_dict["script"].append(_bars_script_draw_entry(2, BarSide.LEFT, page_names)) + bar_dict["script"].append(_bars_script_draw_entry(2, BarSide.RIGHT, page_names)) + + update_list.extend(_bars_script_execute_entry(2, BarSide.LEFT)) + update_list.extend(_bars_script_execute_entry(2, BarSide.RIGHT)) + + if num_bars > 2: + bar_dict["script"].append(_bars_script_draw_entry(3, BarSide.LEFT, page_names)) + bar_dict["script"].append(_bars_script_draw_entry(3, BarSide.RIGHT, page_names)) + + update_list.extend(_bars_script_execute_entry(3, BarSide.LEFT)) + update_list.extend(_bars_script_execute_entry(3, BarSide.RIGHT)) + + if num_bars > 3: + bar_dict["script"].append(_bars_script_draw_entry(4, BarSide.LEFT, page_names)) + bar_dict["script"].append(_bars_script_draw_entry(4, BarSide.RIGHT, page_names)) + + update_list.extend(_bars_script_execute_entry(3, BarSide.LEFT)) + update_list.extend(_bars_script_execute_entry(3, BarSide.RIGHT)) + + bar_dict["script"].append({"id": "update_bars", "then": update_list[:-1]}) + + return bar_dict + + +def _bars_script_draw_entry( + bar_nr: int, bar_side: BarSide, page_names: List[str] +) -> Dict[str, Any]: + + generated_cpp = "switch (id(active_page_nr)){\n" + + for page_num in range(0, len(page_names)): + generated_cpp += ( + 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" break;\n" + ) + + generated_cpp += "}\n" + + return {"id": f"bar{bar_nr}_{bar_side}_draw", "then": [{"lambda": generated_cpp}]} + + +def _bars_script_execute_entry(bar_nr: int, bar_side: BarSide) -> List[Dict[str, str]]: + return [ + { + "script.execute": f"update_bar{bar_nr}_{bar_side}", + }, + {"delay": "0.1s"}, + ] diff --git a/src/buttonplus_generator/snippets/common.py b/src/buttonplus_generator/snippets/common.py index bd61421..7496a7e 100644 --- a/src/buttonplus_generator/snippets/common.py +++ b/src/buttonplus_generator/snippets/common.py @@ -17,7 +17,7 @@ def config_common( config = deep_merge(config, i2c()) config = deep_merge(config, spi()) config = deep_merge( - config, sensors(ambient_gain="auto", extra_ambient_sensors=False) + config, sensors(ambient_gain="96x", extra_ambient_sensors=False) ) num_leds = 0 @@ -32,6 +32,7 @@ def config_common( num_leds = 17 #no display config = deep_merge(config, neopixels(num_leds=num_leds)) + config = deep_merge(config, update_scripts(num_bars=num_bars)) return config @@ -54,12 +55,12 @@ def base_config(device_name: str) -> Dict[str, Any]: }, "psram": {"mode": "octal", "speed": "80MHz"}, "wifi": { - "ssid": "!secret wifi_ssid", - "password": "!secret wifi_password", + "ssid": YAMLSecret("wifi_ssid"), + "password": YAMLSecret("wifi_password"), }, "logger": {"level": "DEBUG"}, - "api": {"encryption": {"key": "!secret encryption_key"}}, - "ota": [{"platform": "esphome", "password": "!secret ota_password"}], + "api": {"encryption": {"key": YAMLSecret("encryption_key")}}, + "ota": [{"platform": "esphome", "password": YAMLSecret("ota_password")}], } @@ -101,7 +102,7 @@ def pages(nr_of_pages: int, page_names: List[str]) -> Dict[str, Any]: {"id": "active_page_nr", "type": "int", "initial_value": "0"}, {"id": "active_page_name", "type": "std::string", "initial_value": ""}, ], - "sensors": [ + "sensor": [ { "platform": "template", "name": "Active Page Number", @@ -170,14 +171,14 @@ def pages(nr_of_pages: int, page_names: List[str]) -> Dict[str, Any]: }, { "sensor.template.publish": { - "id": "active_page_id_ha", - "state": "return id(active_page_nr);", + "id": "active_page_nr_ha", + "state": YAMLLambda("return id(active_page_nr);"), } }, { "text_sensor.template.publish": { "id": "active_page_name_ha", - "state": "return id(active_page_name);", + "state": YAMLLambda("return id(active_page_name);"), } }, {"script.execute": "update_all"}, @@ -189,7 +190,7 @@ def pages(nr_of_pages: int, page_names: List[str]) -> Dict[str, Any]: { "number.set": { "id": "pageselector", - "value": "return id(active_page_nr);", + "value": YAMLLambda("return id(active_page_nr);"), } }, {"script.execute": "set_page"}, @@ -325,3 +326,25 @@ 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": []} + + update_list = [ + { + "script.execute": "update_bars", + }, + {"delay": "0.1s"}, + ] + + if num_bars < 4: + update_list.extend([ + { + "script.execute": "update_main", + }, + {"delay": "0.1s"}, + ]) + + common_dict["script"].append({"id": "update_all", "then": update_list[:-1]}) + + return common_dict \ No newline at end of file diff --git a/src/buttonplus_generator/snippets/display.py b/src/buttonplus_generator/snippets/display.py index 7c8056c..1bb9a89 100644 --- a/src/buttonplus_generator/snippets/display.py +++ b/src/buttonplus_generator/snippets/display.py @@ -1,15 +1,17 @@ -from typing import Dict, Any +from typing import Dict, Any, List from buttonplus_generator.constants import * from buttonplus_generator.utils import get_display_id, get_display_address from buttonplus_generator.merger import deep_merge -def config_display( - version: int, num_bars: int -) -> Dict[str, Any]: + +def config_display(version: int, num_bars: int, page_names: List[str]) -> 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 = deep_merge( + config, display_lights(num_bars=num_bars, display_has_leds=(version == 2)) + ) + config = deep_merge(config, update_scripts(page_names=page_names)) return config @@ -44,24 +46,17 @@ def display_backlight(num_bars: int) -> Dict[str, Any]: "invert_colors": False, "color_order": "rgb", "update_interval": "30s", - "dc_pin": { - "number": GPIO_SPI_REG, - "allow_other_uses": True - }, + "dc_pin": {"number": GPIO_SPI_REG, "allow_other_uses": True}, "cs_pin": { "mcp23xxx": get_display_id(num_bars), "number": 5, - "mode": { - "output": True - }, - "inverted": False + "mode": {"output": True}, + "inverted": False, }, "show_test_card": False, - "dimensions": { - "height": 240, - "width": 320 - }, - "rotation": 180 + "dimensions": {"height": 240, "width": 320}, + "rotation": 180, + "lambda": "id(main_draw).execute();" }, ], } @@ -150,3 +145,50 @@ def display_lights(num_bars: int, display_has_leds: bool = True) -> Dict[str, An }, ] } + + +def update_scripts(page_names: List[str]) -> Dict[str, Any]: + display_dict = {"script": []} + + display_dict["script"].append( + { + "id": "update_main", + "then": [ + { + "component.update": "main_display", + } + ], + } + ) + + generated_cpp = ( + "// All pages\n" + "id(main_display).image(0, 235, id(icon_prev_page), ImageAlign::BOTTOM_LEFT, id(grey));\n" + "id(main_display).image(320, 235, id(icon_next_page), ImageAlign::BOTTOM_RIGHT, id(grey));\n" + "\n" + "id(main_display).strftime(160, 5, id(font_arial20), TextAlign::TOP_CENTER, \"%H:%M\", id(datetime).now());\n" + "id(main_display).strftime(160, 80, id(font_arial20), TextAlign::TOP_CENTER, \"%d-%m-%Y\", id(datetime).now());\n" + "\n" + "switch (id(active_page_nr)){\n" + ) + + for page_num in range(0, len(page_names)): + generated_cpp += ( + f" // Page {page_num} - {page_names[page_num]}\n" + f" case {page_num}:\n" + f" id(main_display).print(160, 235, id(font_arial20), id(white), TextAlign::BOTTOM_CENTER, id(active_page_name).c_str());\n" + f" break;\n" + ) + + generated_cpp += "}\n" + + display_dict["script"].append( + { + "id": "main_draw", + "then": [ + {"lambda": generated_cpp} + ], + } + ) + + return display_dict