First valid working config with drawing
This commit is contained in:
@@ -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
|
- Notification service: until dismissed, or with timeout
|
||||||
- LED effects: flash, breathe
|
- LED effects: flash, breathe
|
||||||
- Top level config only for drawing, everything else hidden
|
- Top level config only for drawing, everything else hidden
|
||||||
|
- back to using packages or includes probably
|
||||||
- Allow adding of font and icons easily
|
- Allow adding of font and icons easily
|
||||||
|
|
||||||
## Missing config
|
## Missing config
|
||||||
- Scripts for updating displays (see scripts.yaml)
|
|
||||||
- Draw routines (see config.yaml)
|
|
||||||
- Event generation (triggers and stuff, see events.yaml)
|
- Event generation (triggers and stuff, see events.yaml)
|
||||||
- configurable timing and button events
|
- configurable timing and button events
|
||||||
- Always set display to left and right page
|
- Always set display to left and right page
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
## GPIO Pins
|
## GPIO Pins
|
||||||
|
|
||||||
|
from enum import StrEnum
|
||||||
|
|
||||||
|
|
||||||
GPIO_NEOPIXELS = "GPIO4" #Neopixel LED's
|
GPIO_NEOPIXELS = "GPIO4" #Neopixel LED's
|
||||||
GPIO_SPI_MOSI = "GPIO5" #SPI MOSI
|
GPIO_SPI_MOSI = "GPIO5" #SPI MOSI
|
||||||
GPIO_SPI_CLK = "GPIO6" #SPI SCK
|
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_SDA = "GPIO1" #I2C SDA > Buttons
|
||||||
GPIO_I2C_BUTTONS_SCL = "GPIO2" #I2C SCL > Buttons
|
GPIO_I2C_BUTTONS_SCL = "GPIO2" #I2C SCL > Buttons
|
||||||
GPIO_I2C_SENSORS_SDA = "GPIO47" #I2C SDA > Temperature & Ambient Sensor
|
GPIO_I2C_SENSORS_SDA = "GPIO47" #I2C SDA > Temperature & Ambient Sensor
|
||||||
GPIO_I2C_SENSORS_SCL = "GPIO48" #I2S SCL > Temperature & Ambient Sensor
|
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
|
||||||
@@ -10,26 +10,29 @@ from typing import Any, Dict, List
|
|||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from buttonplus_generator.constants import YAMLExtend, YAMLLambda, YAMLSecret
|
||||||
from buttonplus_generator.snippets.common import config_common
|
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.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)
|
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
|
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
|
return config
|
||||||
|
|
||||||
def yaml_dumper(config: Dict[str, Any], fh) -> str:
|
def yaml_dumper(config: Dict[str, Any], fh) -> str:
|
||||||
|
|
||||||
## Handle multiline strings
|
## Handle multiline strings
|
||||||
def str_presenter(dumper, data):
|
def represent_multistr(dumper, data):
|
||||||
"""configures yaml for dumping multiline strings
|
"""configures yaml for dumping multiline strings
|
||||||
Ref: https://stackoverflow.com/questions/8640959/how-can-i-control-what-scalar-form-pyyaml-uses-for-my-data
|
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, style='|')
|
||||||
return dumper.represent_scalar('tag:yaml.org,2002:str', data)
|
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)
|
yaml.dump(config, fh, sort_keys=False, encoding="utf-8", default_flow_style=False)
|
||||||
|
|
||||||
def main(argv=None) -> int:
|
def main(argv=None) -> int:
|
||||||
@@ -47,8 +63,7 @@ def main(argv=None) -> int:
|
|||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--device-name",
|
"--device-name",
|
||||||
"--name",
|
"-d",
|
||||||
"-n",
|
|
||||||
default="buttonplus",
|
default="buttonplus",
|
||||||
help="ESPHome device name",
|
help="ESPHome device name",
|
||||||
)
|
)
|
||||||
@@ -59,7 +74,7 @@ def main(argv=None) -> int:
|
|||||||
choices=[1,2],
|
choices=[1,2],
|
||||||
required=True,
|
required=True,
|
||||||
help="The version of the display and bars. Only V2 PCB is supported.",
|
help="The version of the display and bars. Only V2 PCB is supported.",
|
||||||
metavar="VER"
|
metavar="[1|2]"
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--bars",
|
"--bars",
|
||||||
@@ -77,6 +92,14 @@ def main(argv=None) -> int:
|
|||||||
help="List of page names",
|
help="List of page names",
|
||||||
metavar="NAME"
|
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(
|
parser.add_argument(
|
||||||
"--output", "-o", default="buttonplus.yaml", help="Output file path"
|
"--output", "-o", default="buttonplus.yaml", help="Output file path"
|
||||||
)
|
)
|
||||||
@@ -86,9 +109,10 @@ def main(argv=None) -> int:
|
|||||||
version: int = args.version
|
version: int = args.version
|
||||||
num_bars: int = args.bars
|
num_bars: int = args.bars
|
||||||
pages: List[str] = args.pages
|
pages: List[str] = args.pages
|
||||||
|
click_types: List[str] = args.click_types
|
||||||
output: str = args.output
|
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:
|
with open(output, "w", encoding="utf-8") as fh:
|
||||||
fh.writelines(
|
fh.writelines(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -2,18 +2,27 @@ from typing import Dict, Any, List
|
|||||||
from buttonplus_generator.constants import *
|
from buttonplus_generator.constants import *
|
||||||
from buttonplus_generator.merger import deep_merge
|
from buttonplus_generator.merger import deep_merge
|
||||||
|
|
||||||
def config_bars(
|
|
||||||
version: int, num_bars: int
|
def config_bars(version: int, num_bars: int, page_names: List[str]) -> Dict[str, Any]:
|
||||||
) -> Dict[str, Any]:
|
|
||||||
config = bars_backlight()
|
config = bars_backlight()
|
||||||
config = deep_merge(config, bars_setup(num_bars=num_bars))
|
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_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_output(num_bars=num_bars))
|
||||||
config = deep_merge(config, bars_display())
|
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
|
return config
|
||||||
|
|
||||||
|
|
||||||
def bars_backlight() -> Dict[str, Any]:
|
def bars_backlight() -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"output": [
|
"output": [
|
||||||
@@ -55,8 +64,10 @@ def bars_setup(num_bars: int = 3) -> Dict[str, Any]:
|
|||||||
)
|
)
|
||||||
|
|
||||||
scripts.extend(
|
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
|
# At least two bars, in bottom two slots
|
||||||
@@ -66,8 +77,10 @@ def bars_setup(num_bars: int = 3) -> Dict[str, Any]:
|
|||||||
)
|
)
|
||||||
|
|
||||||
scripts.extend(
|
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
|
# At least three bars, in bottom three slots
|
||||||
@@ -77,8 +90,10 @@ def bars_setup(num_bars: int = 3) -> Dict[str, Any]:
|
|||||||
)
|
)
|
||||||
|
|
||||||
scripts.extend(
|
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
|
# No display, only bars, also in top slot
|
||||||
@@ -88,8 +103,10 @@ def bars_setup(num_bars: int = 3) -> Dict[str, Any]:
|
|||||||
)
|
)
|
||||||
|
|
||||||
scripts.extend(
|
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}}
|
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))
|
bar_dict["light"].extend(_bar_lights_entry(3, 8 + display_offset))
|
||||||
|
|
||||||
if num_bars > 3:
|
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
|
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) -> List[Dict[str, Any]]:
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"platform": "partition",
|
"platform": "partition",
|
||||||
"name": f"BAR {bar_nr} Left RGB Front",
|
"name": f"BAR {bar_nr} Left RGB Front",
|
||||||
"id": f"bar{bar_nr}_left_rgb_front",
|
"id": f"bar{bar_nr}_left_rgb_front",
|
||||||
"segments": [
|
"segments": [{"id": "neopixels", "from": offset + 0, "to": offset + 0}],
|
||||||
{
|
},
|
||||||
"id": "neopixels",
|
{
|
||||||
"from": offset + 0,
|
"platform": "partition",
|
||||||
"to": offset + 0
|
"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",
|
"platform": "partition",
|
||||||
"name": f"BAR {bar_nr} Left RGB Back",
|
"name": f"BAR {bar_nr} Right RGB Front",
|
||||||
"id": f"bar{bar_nr}_left_rgb_back",
|
"id": f"bar{bar_nr}_right_rgb_front",
|
||||||
"segments": [
|
"segments": [{"id": "neopixels", "from": offset + 2, "to": offset + 2}],
|
||||||
{
|
},
|
||||||
"id": "neopixels",
|
{
|
||||||
"from": offset + 1,
|
"platform": "partition",
|
||||||
"to": offset + 1
|
"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} 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]:
|
def bars_display_output(num_bars: int = 3) -> Dict[str, Any]:
|
||||||
bar_dict = {"output": []}
|
bar_dict = {"output": []}
|
||||||
|
|
||||||
@@ -260,9 +255,7 @@ def _bar_display_output_entry(bar_nr: int, base_id: str) -> List[Dict[str, Any]]
|
|||||||
"pin": {
|
"pin": {
|
||||||
"mcp23xxx": base_id,
|
"mcp23xxx": base_id,
|
||||||
"number": 5,
|
"number": 5,
|
||||||
"mode": {
|
"mode": {"output": True},
|
||||||
"output": True
|
|
||||||
},
|
|
||||||
"inverted": True,
|
"inverted": True,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -272,14 +265,13 @@ def _bar_display_output_entry(bar_nr: int, base_id: str) -> List[Dict[str, Any]]
|
|||||||
"pin": {
|
"pin": {
|
||||||
"mcp23xxx": base_id,
|
"mcp23xxx": base_id,
|
||||||
"number": 1,
|
"number": 1,
|
||||||
"mode": {
|
"mode": {"output": True},
|
||||||
"output": True
|
|
||||||
},
|
|
||||||
"inverted": True,
|
"inverted": True,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def bars_display() -> Dict[str, Any]:
|
def bars_display() -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"display": [
|
"display": [
|
||||||
@@ -289,18 +281,168 @@ def bars_display() -> Dict[str, Any]:
|
|||||||
"model": "ST7735",
|
"model": "ST7735",
|
||||||
"color_order": "bgr",
|
"color_order": "bgr",
|
||||||
"update_interval": "never",
|
"update_interval": "never",
|
||||||
"dc_pin": {
|
"dc_pin": {"number": GPIO_SPI_REG, "allow_other_uses": True},
|
||||||
"number": GPIO_SPI_REG,
|
|
||||||
"allow_other_uses": True
|
|
||||||
},
|
|
||||||
"invert_colors": False,
|
"invert_colors": False,
|
||||||
"show_test_card": False,
|
"show_test_card": False,
|
||||||
"auto_clear_enabled": False,
|
"auto_clear_enabled": False,
|
||||||
"dimensions": {
|
"dimensions": {"height": 160, "width": 80, "offset_width": 24},
|
||||||
"height": 160,
|
|
||||||
"width": 80,
|
|
||||||
"offset_width": 24
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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"},
|
||||||
|
]
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ def config_common(
|
|||||||
config = deep_merge(config, i2c())
|
config = deep_merge(config, i2c())
|
||||||
config = deep_merge(config, spi())
|
config = deep_merge(config, spi())
|
||||||
config = deep_merge(
|
config = deep_merge(
|
||||||
config, sensors(ambient_gain="auto", extra_ambient_sensors=False)
|
config, sensors(ambient_gain="96x", extra_ambient_sensors=False)
|
||||||
)
|
)
|
||||||
|
|
||||||
num_leds = 0
|
num_leds = 0
|
||||||
@@ -32,6 +32,7 @@ def config_common(
|
|||||||
num_leds = 17 #no display
|
num_leds = 17 #no display
|
||||||
|
|
||||||
config = deep_merge(config, neopixels(num_leds=num_leds))
|
config = deep_merge(config, neopixels(num_leds=num_leds))
|
||||||
|
config = deep_merge(config, update_scripts(num_bars=num_bars))
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
@@ -54,12 +55,12 @@ def base_config(device_name: str) -> Dict[str, Any]:
|
|||||||
},
|
},
|
||||||
"psram": {"mode": "octal", "speed": "80MHz"},
|
"psram": {"mode": "octal", "speed": "80MHz"},
|
||||||
"wifi": {
|
"wifi": {
|
||||||
"ssid": "!secret wifi_ssid",
|
"ssid": YAMLSecret("wifi_ssid"),
|
||||||
"password": "!secret wifi_password",
|
"password": YAMLSecret("wifi_password"),
|
||||||
},
|
},
|
||||||
"logger": {"level": "DEBUG"},
|
"logger": {"level": "DEBUG"},
|
||||||
"api": {"encryption": {"key": "!secret encryption_key"}},
|
"api": {"encryption": {"key": YAMLSecret("encryption_key")}},
|
||||||
"ota": [{"platform": "esphome", "password": "!secret ota_password"}],
|
"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_nr", "type": "int", "initial_value": "0"},
|
||||||
{"id": "active_page_name", "type": "std::string", "initial_value": ""},
|
{"id": "active_page_name", "type": "std::string", "initial_value": ""},
|
||||||
],
|
],
|
||||||
"sensors": [
|
"sensor": [
|
||||||
{
|
{
|
||||||
"platform": "template",
|
"platform": "template",
|
||||||
"name": "Active Page Number",
|
"name": "Active Page Number",
|
||||||
@@ -170,14 +171,14 @@ def pages(nr_of_pages: int, page_names: List[str]) -> Dict[str, Any]:
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"sensor.template.publish": {
|
"sensor.template.publish": {
|
||||||
"id": "active_page_id_ha",
|
"id": "active_page_nr_ha",
|
||||||
"state": "return id(active_page_nr);",
|
"state": YAMLLambda("return id(active_page_nr);"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text_sensor.template.publish": {
|
"text_sensor.template.publish": {
|
||||||
"id": "active_page_name_ha",
|
"id": "active_page_name_ha",
|
||||||
"state": "return id(active_page_name);",
|
"state": YAMLLambda("return id(active_page_name);"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"script.execute": "update_all"},
|
{"script.execute": "update_all"},
|
||||||
@@ -189,7 +190,7 @@ def pages(nr_of_pages: int, page_names: List[str]) -> Dict[str, Any]:
|
|||||||
{
|
{
|
||||||
"number.set": {
|
"number.set": {
|
||||||
"id": "pageselector",
|
"id": "pageselector",
|
||||||
"value": "return id(active_page_nr);",
|
"value": YAMLLambda("return id(active_page_nr);"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{"script.execute": "set_page"},
|
{"script.execute": "set_page"},
|
||||||
@@ -325,3 +326,25 @@ def sensors(ambient_gain: str, extra_ambient_sensors: bool) -> Dict[str, Any]:
|
|||||||
}
|
}
|
||||||
|
|
||||||
return sensors_dict
|
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
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
from typing import Dict, Any
|
from typing import Dict, Any, List
|
||||||
from buttonplus_generator.constants import *
|
from buttonplus_generator.constants import *
|
||||||
from buttonplus_generator.utils import get_display_id, get_display_address
|
from buttonplus_generator.utils import get_display_id, get_display_address
|
||||||
from buttonplus_generator.merger import deep_merge
|
from buttonplus_generator.merger import deep_merge
|
||||||
|
|
||||||
def config_display(
|
|
||||||
version: int, num_bars: int
|
def config_display(version: int, num_bars: int, page_names: List[str]) -> Dict[str, Any]:
|
||||||
) -> Dict[str, Any]:
|
|
||||||
config = display_backlight(num_bars=num_bars)
|
config = display_backlight(num_bars=num_bars)
|
||||||
config = deep_merge(config, display_setup(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_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
|
return config
|
||||||
|
|
||||||
@@ -44,24 +46,17 @@ def display_backlight(num_bars: int) -> Dict[str, Any]:
|
|||||||
"invert_colors": False,
|
"invert_colors": False,
|
||||||
"color_order": "rgb",
|
"color_order": "rgb",
|
||||||
"update_interval": "30s",
|
"update_interval": "30s",
|
||||||
"dc_pin": {
|
"dc_pin": {"number": GPIO_SPI_REG, "allow_other_uses": True},
|
||||||
"number": GPIO_SPI_REG,
|
|
||||||
"allow_other_uses": True
|
|
||||||
},
|
|
||||||
"cs_pin": {
|
"cs_pin": {
|
||||||
"mcp23xxx": get_display_id(num_bars),
|
"mcp23xxx": get_display_id(num_bars),
|
||||||
"number": 5,
|
"number": 5,
|
||||||
"mode": {
|
"mode": {"output": True},
|
||||||
"output": True
|
"inverted": False,
|
||||||
},
|
|
||||||
"inverted": False
|
|
||||||
},
|
},
|
||||||
"show_test_card": False,
|
"show_test_card": False,
|
||||||
"dimensions": {
|
"dimensions": {"height": 240, "width": 320},
|
||||||
"height": 240,
|
"rotation": 180,
|
||||||
"width": 320
|
"lambda": "id(main_draw).execute();"
|
||||||
},
|
|
||||||
"rotation": 180
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user