e37148f9b1
Every screen gets the user action esphome.<device>_show_alert with title, subtitle, icon, color, button_text, timeout and flash. The card sits on LVGL's top layer above every page, card and the dim overlay, wakes the screen and keeps the backlight at its normal brightness until the button (or the timeout; 0 waits for the button, the button always closes at once). flash: true blinks the backlight four times on arrival. Icons are the tile picker names (also mdi:name or the hex codepoint of a compiled glyph, else alert-outline), colours the tile pastels. A new alert replaces the current one; every ending fires esphome.screen_alert with action, title and screen. dismiss_alert removes the card remotely. The field is button_text rather than button: ESPHome reserves the names of loaded components as ids and the CYD profile loads button:. The C++ namespace is screen_alert because the widget id alert_overlay becomes a global lv_obj_t*. tools/generate_icons.py now also writes tile_icon_names.h (name to codepoint) from the one icon list. Firmware 0.2.31 for both boards. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
69 lines
3.6 KiB
Python
69 lines
3.6 KiB
Python
"""Generate self-contained remote packages from the maintained board profiles."""
|
|
import argparse
|
|
from pathlib import Path
|
|
import re
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
REPO = 'https://github.com/MaxGramser/homeassistant_espscreen'
|
|
REFS = {'cyd': 'main', 'guition': 'main'}
|
|
|
|
def generate(board):
|
|
source = ROOT / ('home-like-2432s028.yaml' if board == 'cyd' else 'guition-4848s040.yaml')
|
|
s = source.read_text()
|
|
defaults = (ROOT / ('device.example.yaml' if board == 'cyd' else 'guition-device.example.yaml')).read_text()
|
|
defaults += '\n' + (ROOT / 'calibration.example.yaml').read_text()
|
|
replacements = dict(re.findall(r'^ (\w+): ("[^"\n]*")', defaults, re.M))
|
|
replacements.update(DYNAMIC_TILES='"true"', DASHBOARD_INBOX_INTERNAL='"false"', DIRECT_ACTIONS='"true"',
|
|
ROOM_NAME='"Kies tegels in HA"', TILE_COUNT='"1"')
|
|
s = re.sub(r'^ (\w+): ("[^"\n]*")', lambda m: f' {m[1]}: {replacements.get(m[1],m[2])}', s, flags=re.M)
|
|
# The owner's wizard YAML supplies wifi/API/OTA credentials. No shared keys.
|
|
s = re.sub(r'^ encryption:\n key: !secret api_encryption_key\n', '', s, flags=re.M)
|
|
s = re.sub(r'^ota:\n.*?(?=^\w)', '', s, flags=re.M | re.S)
|
|
s = re.sub(r'^wifi:\n.*?(?=^\w)', '', s, flags=re.M | re.S)
|
|
# Referenced files are fetched as an external component or over HTTPS.
|
|
s = re.sub(r'^ - (cyd_ui.h|light_controls.h|guition_diagnostics.h|backlight_fade.h|alert_overlay.h)$', r' - <esphome/components/smart_display/\1>', s, flags=re.M)
|
|
components = '[xpt2046, smart_display]' if board == 'cyd' else '[smart_display]'
|
|
external = f'''external_components:
|
|
- source:
|
|
type: git
|
|
url: {REPO}.git
|
|
ref: {REFS[board]}
|
|
path: components
|
|
refresh: 0s
|
|
components: {components}
|
|
|
|
'''
|
|
s = re.sub(r'^external_components:\n.*?(?=^\w)', lambda m: external, s, flags=re.M | re.S)
|
|
s = re.sub(r'file: ["\']fonts/([^"\']+)["\']', lambda m: 'file: "https://raw.githubusercontent.com/MaxGramser/homeassistant_espscreen/main/fonts/' + m[1] + '"', s)
|
|
# Keep the established card bindings, but remove all fixed HA subscriptions.
|
|
# Runtime values arrive through ESP Screen Manager, including after changing entities.
|
|
for section in ['sensor', 'text_sensor']:
|
|
match = re.search(r'^' + section + r':\n.*?(?=^[a-zA-Z_]+:|\Z)', s, re.M | re.S)
|
|
if not match: continue
|
|
block = match[0]
|
|
def sensor(m):
|
|
body = re.sub(r'^ (entity_id|attribute):.*\n', '', m[1], flags=re.M)
|
|
return ' - platform: template\n update_interval: never\n' + body
|
|
block = re.sub(r'^ - platform: homeassistant\n(.*?)(?=^ - platform:|\Z)', sensor, block, flags=re.M | re.S)
|
|
s = s[:match.start()] + block + s[match.end():]
|
|
if '!secret' in s: raise ValueError('Remote package still depends on local secrets')
|
|
return '# GENERATED by tools/generate_packages.py; edit the source board profile.\n' + s
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument('--check', action='store_true')
|
|
args = parser.parse_args()
|
|
for board in REFS:
|
|
source = ROOT / ('home-like-2432s028.yaml' if board == 'cyd' else 'guition-4848s040.yaml')
|
|
if not source.exists(): continue
|
|
path = ROOT / 'packages' / f'{board}.yaml'
|
|
expected = generate(board)
|
|
if args.check:
|
|
if not path.exists() or path.read_text() != expected: raise SystemExit(f'Outdated: {path}')
|
|
else:
|
|
path.parent.mkdir(exist_ok=True)
|
|
path.write_text(expected)
|
|
print(f'{board}: package ' + ('verified' if args.check else 'generated'))
|
|
|
|
if __name__ == '__main__': main()
|