148 lines
7.1 KiB
YAML
148 lines
7.1 KiB
YAML
# ============================================================================
|
|
# DEMO / EXAMPLE SCREEN (base id 6, carousel name "demo")
|
|
# ----------------------------------------------------------------------------
|
|
# A minimal, heavily-commented screen that shows how a screen package is built:
|
|
# * it registers itself in the carousel (g_present),
|
|
# * it shows its own LVGL page,
|
|
# * it reacts to a tap (toggles the background black <-> white, text inverts),
|
|
# * it declares its OWN settings toggles (Settings -> Widgets -> Demo):
|
|
# g_demo_border -> draw a border
|
|
# g_demo_led -> drive the LED ring (green on white bg, red on black bg)
|
|
# The globals live in THIS file and are registered into the core's generic settings
|
|
# registry (g_wgrp_* / g_wopt_*) in on_boot - see how below as the template.
|
|
# * it drives the LED ring directly (a simple demo - it bypasses the ring
|
|
# reaction-priority system in the core; that is fine for an example).
|
|
#
|
|
# Everything a screen needs lives in THIS file (globals/scripts/interval/lvgl page +
|
|
# its settings registration). Remove the screen by dropping this file from the package
|
|
# "files:" list - nothing else to edit, anywhere.
|
|
# ============================================================================
|
|
|
|
esphome:
|
|
on_boot:
|
|
# Register this screen so the carousel knows it exists. The core builds the
|
|
# carousel order from `screen_order`, including only screens that set g_present.
|
|
- priority: 655
|
|
then:
|
|
- lambda: 'id(g_present)[6] = true;'
|
|
# Register this screen's settings (Settings -> Widgets -> Demo) in the generic registry.
|
|
- priority: 650
|
|
then:
|
|
- lambda: |-
|
|
int g = id(g_wgrp_n)++;
|
|
id(g_wgrp_labels) += (g ? "\n" : ""); id(g_wgrp_labels) += "Demo";
|
|
int o;
|
|
o = id(g_wopt_n)++; id(g_wopt_group)[o] = g; id(g_wopt_label)[o] = "Border"; id(g_wopt_kind)[o] = 0; id(g_wopt_ptr)[o] = &id(g_demo_border);
|
|
o = id(g_wopt_n)++; id(g_wopt_group)[o] = g; id(g_wopt_label)[o] = "Demo LED"; id(g_wopt_kind)[o] = 0; id(g_wopt_ptr)[o] = &id(g_demo_led);
|
|
|
|
globals:
|
|
- id: g_demo_bg # background: false = black, true = white (runtime state)
|
|
type: bool
|
|
restore_value: no
|
|
initial_value: 'false'
|
|
# Demo settings (declared here, registered above; the core menu reaches them by pointer).
|
|
- id: g_demo_border # draw a border (Settings -> Widgets -> Demo)
|
|
type: bool
|
|
restore_value: yes
|
|
initial_value: 'false'
|
|
- id: g_demo_led # drive the LED ring (Settings -> Widgets -> Demo)
|
|
type: bool
|
|
restore_value: yes
|
|
initial_value: 'false'
|
|
# Tap de-duplication: the core bumps g_tap_seq on every normal-mode tap; we
|
|
# remember the last value we handled so one tap = one toggle.
|
|
- id: g_demo_lasttap
|
|
type: int
|
|
restore_value: no
|
|
initial_value: '0'
|
|
# Tracks whether WE currently own the LED ring, so we can release it on leave.
|
|
# Persistent so that after a reboot (the ring component restores its last colour) the
|
|
# 80ms loop below sees "we owned it", and since we boot onto the home screen it turns
|
|
# the ring back off instead of leaving the demo colour stuck on.
|
|
- id: g_demo_ring_on
|
|
type: bool
|
|
restore_value: yes
|
|
initial_value: 'false'
|
|
|
|
script:
|
|
# Redraws the screen from the three state flags (g_demo_bg / border / led).
|
|
- id: demo_render
|
|
then:
|
|
# background + text colour (text is the inverse of the background)
|
|
- if:
|
|
condition: { lambda: 'return id(g_demo_bg);' } # white background
|
|
then:
|
|
- lvgl.widget.update: { id: demo_bg, bg_color: 0xFFFFFF, border_color: 0x000000 }
|
|
- lvgl.label.update: { id: demo_lbl, text_color: 0x000000 }
|
|
else: # black background
|
|
- lvgl.widget.update: { id: demo_bg, bg_color: 0x000000, border_color: 0xFFFFFF }
|
|
- lvgl.label.update: { id: demo_lbl, text_color: 0xFFFFFF }
|
|
# border on/off (width is an int, so a lambda is fine here)
|
|
- lvgl.widget.update: { id: demo_bg, border_width: !lambda 'return id(g_demo_border) ? 6 : 0;' }
|
|
# LED ring: green when the background is white, red when it is black
|
|
- if:
|
|
condition: { lambda: 'return id(g_demo_led);' }
|
|
then:
|
|
- if:
|
|
condition: { lambda: 'return id(g_demo_bg);' }
|
|
then: [ light.turn_on: { id: ring_light, red: 0%, green: 100%, blue: 0%, effect: "None" } ]
|
|
else: [ light.turn_on: { id: ring_light, red: 100%, green: 0%, blue: 0%, effect: "None" } ]
|
|
- lambda: 'id(g_demo_ring_on) = true;'
|
|
else:
|
|
# LED toggle is off: release the ring if we were driving it
|
|
- if:
|
|
condition: { lambda: 'return id(g_demo_ring_on);' }
|
|
then:
|
|
- light.turn_off: ring_light
|
|
- lambda: 'id(g_demo_ring_on) = false;'
|
|
|
|
interval:
|
|
# Carousel navigation: when this screen becomes selected, show its page.
|
|
- interval: 50ms
|
|
then:
|
|
- if:
|
|
condition: { lambda: 'return id(g_nav_req) && id(g_base)==6;' }
|
|
then:
|
|
- lambda: 'id(g_nav_req) = false; id(g_demo_lasttap) = id(g_tap_seq);' # sync tap counter so arriving never counts as a tap
|
|
- if: { condition: { lambda: 'return id(g_nav_anim)==0;' }, then: [lvgl.page.show: { id: page_demo, animation: move_left, time: 250ms }] }
|
|
- if: { condition: { lambda: 'return id(g_nav_anim)==1;' }, then: [lvgl.page.show: { id: page_demo, animation: move_right, time: 250ms }] }
|
|
- if: { condition: { lambda: 'return id(g_nav_anim)==2;' }, then: [lvgl.page.show: { id: page_demo, animation: move_top, time: 250ms }] }
|
|
- if: { condition: { lambda: 'return id(g_nav_anim)==3;' }, then: [lvgl.page.show: { id: page_demo, animation: move_bottom, time: 250ms }] }
|
|
- script.execute: demo_render
|
|
# React to a tap while this screen is on top; release the LED when we leave.
|
|
- interval: 80ms
|
|
then:
|
|
- if:
|
|
condition: { lambda: 'return id(g_base)==6 && id(g_tap_seq) != id(g_demo_lasttap);' }
|
|
then:
|
|
- lambda: 'id(g_demo_lasttap) = id(g_tap_seq); id(g_demo_bg) = !id(g_demo_bg);' # one tap = flip background
|
|
- script.execute: demo_render
|
|
- if:
|
|
condition: { lambda: 'return id(g_base) != 6 && id(g_demo_ring_on);' }
|
|
then:
|
|
- lambda: 'id(g_demo_ring_on) = false;'
|
|
|
|
lvgl:
|
|
pages:
|
|
- id: page_demo
|
|
bg_color: 0x000000
|
|
widgets:
|
|
# A full circle that fills the round screen - this is the background we recolour.
|
|
# radius 180 on a 360x360 box makes it a circle, so the optional border is a clean ring.
|
|
- obj:
|
|
id: demo_bg
|
|
align: CENTER
|
|
width: 360
|
|
height: 360
|
|
radius: 180
|
|
bg_color: 0x000000
|
|
bg_opa: COVER
|
|
border_width: 0
|
|
border_color: 0xFFFFFF
|
|
- label:
|
|
id: demo_lbl
|
|
align: CENTER
|
|
text: "TAP ME!"
|
|
text_font: montserrat_34
|
|
text_color: 0xFFFFFF
|