############################################################ # CYD Base – LVGL UI + scripts layer # Include via: packages: !include cyd-base-ui.yaml ############################################################ lvgl: displays: - my_display touchscreens: - touchscreen_id: ts_touch # Use a 1/10th frame buffer (~15KB) instead of the default full frame (~150KB). # Required on CYDs without PSRAM. The display is rendered in horizontal strips. buffer_size: 10% style_definitions: - id: style_tile bg_color: 0xFFFFFF bg_opa: 95% radius: 18 border_width: 0 pad_left: 8 pad_right: 8 pad_top: 8 pad_bottom: 8 shadow_width: 0 shadow_opa: 40% - id: style_tile_disabled bg_color: 0x3a3a3a bg_opa: 95% radius: 18 border_width: 0 pad_left: 8 pad_right: 8 pad_top: 8 pad_bottom: 8 shadow_width: 0 shadow_opa: 25% - id: style_icon_circle bg_color: 0xFEC600 bg_opa: COVER radius: 999 border_width: 0 - id: style_icon_circle_disabled bg_color: 0x7B7B6F bg_opa: 95% radius: 999 border_width: 0 - id: style_room text_font: headline text_color: 0xFFFFFF text_opa: 100% - id: style_time text_font: time_label text_color: 0xFFFFFF text_opa: 100% - id: style_title text_font: label text_color: 0x000000 text_opa: 100% - id: style_value text_font: sublabel text_color: 0x7A7A7C text_opa: 100% - id: style_value_big text_font: sublabel_big text_color: 0xFFFFFF text_opa: 80% - id: style_title_disabled text_font: label text_color: 0xFFFFFF text_opa: 100% - id: style_value_disabled text_font: sublabel text_color: 0xD9D9D9 text_opa: 100% pages: - id: home_page bg_color: 0x000000 bg_opa: COVER scrollable: false scrollbar_mode: 'OFF' widgets: - image: id: bg src: bg_home x: 0 y: 0 - label: id: lbl_room x: 11 y: 14 text: "${ROOM_NAME}" styles: style_room - label: id: lbl_time align: TOP_RIGHT x: -11 y: 14 text: "" styles: style_time # ---------- TILE 1 ---------- - obj: id: tile1 x: 9 y: 54 width: 147 height: 52 styles: style_tile scrollable: false scrollbar_mode: 'OFF' widgets: - obj: id: tile1_icon_circle x: 0 y: 0 width: 36 height: 36 styles: style_icon_circle clickable: false scrollable: false scrollbar_mode: 'OFF' widgets: - label: id: tile1_icon_lbl align: CENTER text_font: materialdesign_icons text_color: 0xFFFFFF text: "${TILE1_ICON}" clickable: false - label: id: t1_title x: 48 y: 4 text: "${TILE1_TITLE}" styles: style_title clickable: false - label: id: t1_value x: 48 y: 18 text: "—" styles: style_value clickable: false on_short_click: - script.execute: { id: publish_action, action: "tile1_press" } - script.execute: id: do_tile_action tile_type: "${TILE1_TYPE}" tap_action: "${TILE1_TAP_ACTION}" service: "${TILE1_TAP_SERVICE}" entity_id: "${TILE1_ENTITY}" param_key: "${TILE1_TAP_PARAM_KEY}" param_val: "${TILE1_TAP_PARAM_VAL}" was_on: !lambda "return id(ha_state_tile1).state;" on_long_press: - if: condition: lambda: |- std::string lp = "${TILE1_LONGPRESS}"; std::string type = "${TILE1_TYPE}"; if (lp == "none") return false; if (lp == "auto") return (type == "light" || type == "fan"); return (lp == "brightness" || lp == "percentage"); then: - script.execute: id: open_value_overlay title: "${TILE1_TITLE}" entity: "${TILE1_ENTITY}" tile_type: "${TILE1_TYPE}" longpress_mode: "${TILE1_LONGPRESS}" was_on: !lambda "return id(ha_state_tile1).state;" off_value: !lambda "return atoi(\"${TILE1_LONGPRESS_OFF_VALUE}\");" brightness_value: !lambda "return id(tile1_brightness).state;" percentage_value: !lambda "return id(tile1_percentage).state;" icon_text: "${TILE1_ICON}" slider_bg_color: ${TILE1_BG_DISABLED_COLOR} slider_fill_color: ${TILE1_CIRCLE_ACTIVE_COLOR} slider_icon_color: ${TILE1_ICON_ACTIVE_COLOR} # ---------- TILE 2 ---------- - obj: id: tile2 x: 164 y: 54 width: 147 height: 52 styles: style_tile scrollable: false scrollbar_mode: 'OFF' widgets: - obj: id: tile2_icon_circle x: 0 y: 0 width: 36 height: 36 styles: style_icon_circle clickable: false scrollable: false scrollbar_mode: 'OFF' widgets: - label: id: tile2_icon_lbl align: CENTER text_font: materialdesign_icons text_color: 0xFFFFFF text: "${TILE2_ICON}" clickable: false - label: id: t2_title x: 48 y: 4 text: "${TILE2_TITLE}" styles: style_title clickable: false - label: id: t2_value x: 48 y: 18 text: "—" styles: style_value clickable: false on_short_click: - script.execute: { id: publish_action, action: "tile2_press" } - script.execute: id: do_tile_action tile_type: "${TILE2_TYPE}" tap_action: "${TILE2_TAP_ACTION}" service: "${TILE2_TAP_SERVICE}" entity_id: "${TILE2_ENTITY}" param_key: "${TILE2_TAP_PARAM_KEY}" param_val: "${TILE2_TAP_PARAM_VAL}" was_on: !lambda "return id(ha_state_tile2).state;" on_long_press: - if: condition: lambda: |- std::string lp = "${TILE2_LONGPRESS}"; std::string type = "${TILE2_TYPE}"; if (lp == "none") return false; if (lp == "auto") return (type == "light" || type == "fan"); return (lp == "brightness" || lp == "percentage"); then: - script.execute: id: open_value_overlay title: "${TILE2_TITLE}" entity: "${TILE2_ENTITY}" tile_type: "${TILE2_TYPE}" longpress_mode: "${TILE2_LONGPRESS}" was_on: !lambda "return id(ha_state_tile2).state;" off_value: !lambda "return atoi(\"${TILE2_LONGPRESS_OFF_VALUE}\");" brightness_value: !lambda "return id(tile2_brightness).state;" percentage_value: !lambda "return id(tile2_percentage).state;" icon_text: "${TILE2_ICON}" slider_bg_color: ${TILE2_BG_DISABLED_COLOR} slider_fill_color: ${TILE2_CIRCLE_ACTIVE_COLOR} slider_icon_color: ${TILE2_ICON_ACTIVE_COLOR} # ---------- TILE 3 ---------- - obj: id: tile3 x: 9 y: 114 width: 147 height: 52 styles: style_tile scrollable: false scrollbar_mode: 'OFF' widgets: - obj: id: tile3_icon_circle x: 0 y: 0 width: 36 height: 36 styles: style_icon_circle clickable: false scrollable: false scrollbar_mode: 'OFF' widgets: - label: id: tile3_icon_lbl align: CENTER text_font: materialdesign_icons text_color: 0xFFFFFF text: "${TILE3_ICON}" clickable: false - label: id: t3_title x: 48 y: 4 text: "${TILE3_TITLE}" styles: style_title clickable: false - label: id: t3_value x: 48 y: 18 text: "—" styles: style_value clickable: false on_short_click: - script.execute: { id: publish_action, action: "tile3_press" } - script.execute: id: do_tile_action tile_type: "${TILE3_TYPE}" tap_action: "${TILE3_TAP_ACTION}" service: "${TILE3_TAP_SERVICE}" entity_id: "${TILE3_ENTITY}" param_key: "${TILE3_TAP_PARAM_KEY}" param_val: "${TILE3_TAP_PARAM_VAL}" was_on: !lambda "return id(ha_state_tile3).state;" on_long_press: - if: condition: lambda: |- std::string lp = "${TILE3_LONGPRESS}"; std::string type = "${TILE3_TYPE}"; if (lp == "none") return false; if (lp == "auto") return (type == "light" || type == "fan"); return (lp == "brightness" || lp == "percentage"); then: - script.execute: id: open_value_overlay title: "${TILE3_TITLE}" entity: "${TILE3_ENTITY}" tile_type: "${TILE3_TYPE}" longpress_mode: "${TILE3_LONGPRESS}" was_on: !lambda "return id(ha_state_tile3).state;" off_value: !lambda "return atoi(\"${TILE3_LONGPRESS_OFF_VALUE}\");" brightness_value: !lambda "return id(tile3_brightness).state;" percentage_value: !lambda "return id(tile3_percentage).state;" icon_text: "${TILE3_ICON}" slider_bg_color: ${TILE3_BG_DISABLED_COLOR} slider_fill_color: ${TILE3_CIRCLE_ACTIVE_COLOR} slider_icon_color: ${TILE3_ICON_ACTIVE_COLOR} # ---------- TILE 4 ---------- - obj: id: tile4 x: 164 y: 114 width: 147 height: 52 styles: style_tile scrollable: false scrollbar_mode: 'OFF' widgets: - obj: id: tile4_icon_circle x: 0 y: 0 width: 36 height: 36 styles: style_icon_circle clickable: false scrollable: false scrollbar_mode: 'OFF' widgets: - label: id: tile4_icon_lbl align: CENTER text_font: materialdesign_icons text_color: 0xFFFFFF text: "${TILE4_ICON}" clickable: false - label: id: t4_title x: 48 y: 4 text: "${TILE4_TITLE}" styles: style_title clickable: false - label: id: t4_value x: 48 y: 18 text: "—" styles: style_value clickable: false on_short_click: - script.execute: { id: publish_action, action: "tile4_press" } - script.execute: id: do_tile_action tile_type: "${TILE4_TYPE}" tap_action: "${TILE4_TAP_ACTION}" service: "${TILE4_TAP_SERVICE}" entity_id: "${TILE4_ENTITY}" param_key: "${TILE4_TAP_PARAM_KEY}" param_val: "${TILE4_TAP_PARAM_VAL}" was_on: !lambda "return id(ha_state_tile4).state;" on_long_press: - if: condition: lambda: |- std::string lp = "${TILE4_LONGPRESS}"; std::string type = "${TILE4_TYPE}"; if (lp == "none") return false; if (lp == "auto") return (type == "light" || type == "fan"); return (lp == "brightness" || lp == "percentage"); then: - script.execute: id: open_value_overlay title: "${TILE4_TITLE}" entity: "${TILE4_ENTITY}" tile_type: "${TILE4_TYPE}" longpress_mode: "${TILE4_LONGPRESS}" was_on: !lambda "return id(ha_state_tile4).state;" off_value: !lambda "return atoi(\"${TILE4_LONGPRESS_OFF_VALUE}\");" brightness_value: !lambda "return id(tile4_brightness).state;" percentage_value: !lambda "return id(tile4_percentage).state;" icon_text: "${TILE4_ICON}" slider_bg_color: ${TILE4_BG_DISABLED_COLOR} slider_fill_color: ${TILE4_CIRCLE_ACTIVE_COLOR} slider_icon_color: ${TILE4_ICON_ACTIVE_COLOR} # ---------- TILE 5 ---------- - obj: id: tile5 x: 9 y: 174 width: 147 height: 52 styles: style_tile scrollable: false scrollbar_mode: 'OFF' widgets: - obj: id: tile5_icon_circle x: 0 y: 0 width: 36 height: 36 styles: style_icon_circle clickable: false scrollable: false scrollbar_mode: 'OFF' widgets: - label: id: tile5_icon_lbl align: CENTER text_font: materialdesign_icons text_color: 0xFFFFFF text: "${TILE5_ICON}" clickable: false - label: id: t5_title x: 48 y: 4 text: "${TILE5_TITLE}" styles: style_title clickable: false - label: id: t5_value x: 48 y: 18 text: "—" styles: style_value clickable: false on_short_click: - script.execute: { id: publish_action, action: "tile5_press" } - script.execute: id: do_tile_action tile_type: "${TILE5_TYPE}" tap_action: "${TILE5_TAP_ACTION}" service: "${TILE5_TAP_SERVICE}" entity_id: "${TILE5_ENTITY}" param_key: "${TILE5_TAP_PARAM_KEY}" param_val: "${TILE5_TAP_PARAM_VAL}" was_on: !lambda "return id(ha_state_tile5).state;" on_long_press: - if: condition: lambda: |- std::string lp = "${TILE5_LONGPRESS}"; std::string type = "${TILE5_TYPE}"; if (lp == "none") return false; if (lp == "auto") return (type == "light" || type == "fan"); return (lp == "brightness" || lp == "percentage"); then: - script.execute: id: open_value_overlay title: "${TILE5_TITLE}" entity: "${TILE5_ENTITY}" tile_type: "${TILE5_TYPE}" longpress_mode: "${TILE5_LONGPRESS}" was_on: !lambda "return id(ha_state_tile5).state;" off_value: !lambda "return atoi(\"${TILE5_LONGPRESS_OFF_VALUE}\");" brightness_value: !lambda "return id(tile5_brightness).state;" percentage_value: !lambda "return id(tile5_percentage).state;" icon_text: "${TILE5_ICON}" slider_bg_color: ${TILE5_BG_DISABLED_COLOR} slider_fill_color: ${TILE5_CIRCLE_ACTIVE_COLOR} slider_icon_color: ${TILE5_ICON_ACTIVE_COLOR} # ---------- TILE 6 ---------- - obj: id: tile6 x: 164 y: 174 width: 147 height: 52 styles: style_tile scrollable: false scrollbar_mode: 'OFF' widgets: - obj: id: tile6_icon_circle x: 0 y: 0 width: 36 height: 36 styles: style_icon_circle clickable: false scrollable: false scrollbar_mode: 'OFF' widgets: - label: id: tile6_icon_lbl align: CENTER text_font: materialdesign_icons text_color: 0xFFFFFF text: "${TILE6_ICON}" clickable: false - label: id: t6_title x: 48 y: 4 text: "${TILE6_TITLE}" styles: style_title clickable: false - label: id: t6_value x: 48 y: 18 text: "—" styles: style_value clickable: false on_short_click: - script.execute: { id: publish_action, action: "tile6_press" } - script.execute: id: do_tile_action tile_type: "${TILE6_TYPE}" tap_action: "${TILE6_TAP_ACTION}" service: "${TILE6_TAP_SERVICE}" entity_id: "${TILE6_ENTITY}" param_key: "${TILE6_TAP_PARAM_KEY}" param_val: "${TILE6_TAP_PARAM_VAL}" was_on: !lambda "return id(ha_state_tile6).state;" on_long_press: - if: condition: lambda: |- std::string lp = "${TILE6_LONGPRESS}"; std::string type = "${TILE6_TYPE}"; if (lp == "none") return false; if (lp == "auto") return (type == "light" || type == "fan"); return (lp == "brightness" || lp == "percentage"); then: - script.execute: id: open_value_overlay title: "${TILE6_TITLE}" entity: "${TILE6_ENTITY}" tile_type: "${TILE6_TYPE}" longpress_mode: "${TILE6_LONGPRESS}" was_on: !lambda "return id(ha_state_tile6).state;" off_value: !lambda "return atoi(\"${TILE6_LONGPRESS_OFF_VALUE}\");" brightness_value: !lambda "return id(tile6_brightness).state;" percentage_value: !lambda "return id(tile6_percentage).state;" icon_text: "${TILE6_ICON}" slider_bg_color: ${TILE6_BG_DISABLED_COLOR} slider_fill_color: ${TILE6_CIRCLE_ACTIVE_COLOR} slider_icon_color: ${TILE6_ICON_ACTIVE_COLOR} # ---------- VALUE SLIDER OVERLAY ---------- - obj: id: brightness_overlay x: 0 y: 0 width: 320 height: 240 bg_opa: TRANSP hidden: true scrollable: false scrollbar_mode: 'OFF' pad_left: 0 pad_right: 0 pad_top: 0 pad_bottom: 0 border_width: 0 widgets: - image: id: brightness_overlay_bg src: bg_home x: 0 y: 0 clickable: true on_click: - lvgl.widget.hide: brightness_overlay - obj: id: brightness_overlay_dim x: 0 y: 0 width: 320 height: 240 bg_color: 0x000000 bg_opa: 18% border_width: 0 clickable: false scrollable: false - label: id: overlay_title align: TOP_MID y: 10 text: "Light" styles: style_room - label: id: overlay_value align: TOP_MID y: 35 text: "100 %" styles: style_value_big - slider: id: overlay_slider align: CENTER y: 18 width: 96 height: 160 min_value: 0 max_value: 100 value: 100 adv_hittest: false bg_color: 0x939391 bg_opa: 100% radius: 28 border_width: 0 indicator: bg_color: 0xFEC600 bg_opa: 100% radius: 28 knob: bg_opa: 0% border_width: 0 shadow_width: 0 pad_all: 10 on_value: - script.execute: id: slider_preview value: !lambda "return x;" on_release: - script.execute: id: slider_commit value: !lambda "return lv_slider_get_value(id(overlay_slider));" widgets: - label: id: overlay_icon align: BOTTOM_MID y: -10 text_font: materialdesign_icons text_color: 0xFFFFFF text: "${TILE1_ICON}" clickable: false script: - id: publish_action mode: queued parameters: action: string then: - text_sensor.template.publish: id: smartdisplay_action state: !lambda 'return action;' - delay: 200ms - text_sensor.template.publish: id: smartdisplay_action state: "" - id: slider_preview parameters: value: int then: - lambda: |- char buf[20]; snprintf(buf, sizeof(buf), "%d%s", value, id(active_value_suffix).c_str()); lv_label_set_text(id(overlay_value), buf); - id: slider_commit parameters: value: int then: - if: condition: lambda: "return id(active_control_kind) == \"light_brightness\";" then: - homeassistant.action: action: light.turn_on data: entity_id: !lambda "return id(active_entity);" brightness_pct: !lambda "return value;" else: - if: condition: lambda: "return id(active_control_kind) == \"fan_percentage\";" then: - if: condition: lambda: "return value <= 0;" then: - homeassistant.action: action: fan.turn_off data: entity_id: !lambda "return id(active_entity);" else: - homeassistant.action: action: fan.turn_on data: entity_id: !lambda "return id(active_entity);" - delay: 150ms - homeassistant.action: action: fan.set_percentage data: entity_id: !lambda "return id(active_entity);" percentage: !lambda "return value;" - id: do_tile_action mode: queued parameters: tile_type: string tap_action: string service: string entity_id: string param_key: string param_val: string was_on: bool then: - if: condition: lambda: 'return std::string("${DIRECT_ACTIONS}") == "true";' then: - lambda: |- ESP_LOGD("tile", "do_tile_action type=%s action=%s service=%s entity=%s key=%s val=%s was_on=%d", tile_type.c_str(), tap_action.c_str(), service.c_str(), entity_id.c_str(), param_key.c_str(), param_val.c_str(), (int)was_on); - if: condition: lambda: "return tap_action == \"fan_toggle_preset\";" then: - if: condition: lambda: "return was_on;" then: - homeassistant.action: action: fan.turn_off data: entity_id: !lambda 'return entity_id;' else: - homeassistant.action: action: fan.turn_on data: entity_id: !lambda 'return entity_id;' - delay: 150ms - homeassistant.action: action: fan.set_preset_mode data: entity_id: !lambda 'return entity_id;' preset_mode: !lambda 'return param_val;' else: - if: condition: lambda: |- std::string r = tap_action; if (r == "auto") r = (tile_type == "scene" || tile_type == "script") ? "activate" : "toggle"; return r == "toggle"; then: - if: condition: lambda: "return service.size() > 0;" then: - homeassistant.action: action: !lambda 'return service;' data: entity_id: !lambda 'return entity_id;' else: - if: condition: lambda: 'return tile_type == "light";' then: - homeassistant.action: action: light.toggle data: entity_id: !lambda 'return entity_id;' else: - if: condition: lambda: 'return tile_type == "fan";' then: - homeassistant.action: action: fan.toggle data: entity_id: !lambda 'return entity_id;' else: - if: condition: lambda: 'return tile_type == "switch";' then: - homeassistant.action: action: switch.toggle data: entity_id: !lambda 'return entity_id;' else: - if: condition: lambda: |- std::string r = tap_action; if (r == "auto") r = (tile_type == "scene" || tile_type == "script") ? "activate" : "toggle"; return r == "activate"; then: - if: condition: lambda: "return service.size() > 0;" then: - if: condition: lambda: 'return param_key == "preset_mode";' then: - homeassistant.action: action: !lambda 'return service;' data: entity_id: !lambda 'return entity_id;' preset_mode: !lambda 'return param_val;' else: - if: condition: lambda: 'return param_key == "brightness_pct";' then: - homeassistant.action: action: !lambda 'return service;' data: entity_id: !lambda 'return entity_id;' brightness_pct: !lambda 'return atoi(param_val.c_str());' else: - if: condition: lambda: 'return param_key == "percentage";' then: - homeassistant.action: action: !lambda 'return service;' data: entity_id: !lambda 'return entity_id;' percentage: !lambda 'return atoi(param_val.c_str());' else: - homeassistant.action: action: !lambda 'return service;' data: entity_id: !lambda 'return entity_id;' else: - if: condition: lambda: 'return tile_type == "scene";' then: - homeassistant.action: action: scene.turn_on data: entity_id: !lambda 'return entity_id;' else: - if: condition: lambda: 'return tile_type == "script";' then: - homeassistant.action: action: script.turn_on data: entity_id: !lambda 'return entity_id;' else: - if: condition: lambda: 'return tile_type == "light";' then: - homeassistant.action: action: light.turn_on data: entity_id: !lambda 'return entity_id;' else: - if: condition: lambda: 'return tile_type == "fan";' then: - homeassistant.action: action: fan.turn_on data: entity_id: !lambda 'return entity_id;' else: - if: condition: lambda: 'return tile_type == "switch";' then: - homeassistant.action: action: switch.turn_on data: entity_id: !lambda 'return entity_id;' - id: open_value_overlay parameters: title: string entity: string tile_type: string longpress_mode: string was_on: bool off_value: int brightness_value: float percentage_value: float icon_text: string slider_bg_color: uint32_t slider_fill_color: uint32_t slider_icon_color: uint32_t then: - lambda: |- std::string mode = longpress_mode; if (mode == "auto") { if (tile_type == "light") mode = "brightness"; else if (tile_type == "fan") mode = "percentage"; else mode = "none"; } if (mode == "none") return; id(active_entity) = entity; id(active_value_suffix) = " %"; id(overlay_slider_bg_color) = slider_bg_color; id(overlay_slider_fill_color) = slider_fill_color; int pct = off_value; if (mode == "brightness") { id(active_control_kind) = "light_brightness"; if (was_on) { if (isnan(brightness_value)) pct = 100; else pct = (int) lround((brightness_value / 255.0f) * 100.0f); } } else if (mode == "percentage") { id(active_control_kind) = "fan_percentage"; if (was_on) { if (isnan(percentage_value)) pct = 0; else pct = (int) lround(percentage_value); } } else { return; } if (pct < 0) pct = 0; if (pct > 100) pct = 100; lv_label_set_text(id(overlay_title), title.c_str()); lv_label_set_text(id(overlay_icon), icon_text.c_str()); lv_slider_set_value(id(overlay_slider), pct, LV_ANIM_OFF); char buf[20]; snprintf(buf, sizeof(buf), "%d%s", pct, id(active_value_suffix).c_str()); lv_label_set_text(id(overlay_value), buf); lv_obj_set_style_bg_color(id(overlay_slider), lv_color_hex(slider_bg_color), LV_PART_MAIN); lv_obj_set_style_bg_opa(id(overlay_slider), LV_OPA_COVER, LV_PART_MAIN); lv_obj_set_style_bg_color(id(overlay_slider), lv_color_hex(slider_fill_color), LV_PART_INDICATOR); lv_obj_set_style_bg_opa(id(overlay_slider), LV_OPA_COVER, LV_PART_INDICATOR); lv_obj_set_style_text_color(id(overlay_icon), lv_color_hex(slider_icon_color), 0); - lvgl.widget.show: brightness_overlay - id: ui_refresh mode: queued then: - lambda: |- auto set_lbl = [](lv_obj_t* lbl, const std::string& s) { if (lbl) lv_label_set_text(lbl, s.c_str()); }; auto set_value_auto = [&](lv_obj_t* lbl, bool on, const std::string& tile_type, const std::string& value_mode, float brightness, float percentage, const std::string& preset, const std::string& label_on, const std::string& label_off) { std::string mode = value_mode; if (mode == "auto" || mode.empty()) { if (tile_type == "light") mode = "brightness"; else if (tile_type == "fan") mode = preset.empty() ? "percentage" : "preset"; else mode = "text"; } if (mode == "brightness") { if (!on) { set_lbl(lbl, label_off); return; } if (isnan(brightness)) { set_lbl(lbl, "100 %"); return; } int pct = (int) lround((brightness / 255.0f) * 100.0f); char buf[8]; snprintf(buf, sizeof(buf), "%d %%", pct); set_lbl(lbl, std::string(buf)); return; } if (mode == "percentage") { if (!on) { set_lbl(lbl, label_off); return; } int pct = isnan(percentage) ? 0 : (int) lround(percentage); char buf[8]; snprintf(buf, sizeof(buf), "%d %%", pct); set_lbl(lbl, std::string(buf)); return; } if (mode == "preset") { if (!on) { set_lbl(lbl, label_off); return; } set_lbl(lbl, !preset.empty() ? preset : label_on); return; } if (mode == "text") { if (tile_type == "scene" || tile_type == "script") set_lbl(lbl, label_on); else set_lbl(lbl, on ? label_on : label_off); return; } set_lbl(lbl, "—"); }; set_value_auto(id(t1_value), id(ha_state_tile1).state, "${TILE1_TYPE}", "${TILE1_VALUE_MODE}", id(tile1_brightness).state, id(tile1_percentage).state, std::string(id(tile1_preset).state.c_str()), "${TILE1_LABEL_ON}", "${TILE1_LABEL_OFF}"); set_value_auto(id(t2_value), id(ha_state_tile2).state, "${TILE2_TYPE}", "${TILE2_VALUE_MODE}", id(tile2_brightness).state, id(tile2_percentage).state, std::string(id(tile2_preset).state.c_str()), "${TILE2_LABEL_ON}", "${TILE2_LABEL_OFF}"); set_value_auto(id(t3_value), id(ha_state_tile3).state, "${TILE3_TYPE}", "${TILE3_VALUE_MODE}", id(tile3_brightness).state, id(tile3_percentage).state, std::string(id(tile3_preset).state.c_str()), "${TILE3_LABEL_ON}", "${TILE3_LABEL_OFF}"); set_value_auto(id(t4_value), id(ha_state_tile4).state, "${TILE4_TYPE}", "${TILE4_VALUE_MODE}", id(tile4_brightness).state, id(tile4_percentage).state, std::string(id(tile4_preset).state.c_str()), "${TILE4_LABEL_ON}", "${TILE4_LABEL_OFF}"); set_value_auto(id(t5_value), id(ha_state_tile5).state, "${TILE5_TYPE}", "${TILE5_VALUE_MODE}", id(tile5_brightness).state, id(tile5_percentage).state, std::string(id(tile5_preset).state.c_str()), "${TILE5_LABEL_ON}", "${TILE5_LABEL_OFF}"); set_value_auto(id(t6_value), id(ha_state_tile6).state, "${TILE6_TYPE}", "${TILE6_VALUE_MODE}", id(tile6_brightness).state, id(tile6_percentage).state, std::string(id(tile6_preset).state.c_str()), "${TILE6_LABEL_ON}", "${TILE6_LABEL_OFF}"); { auto now = id(homeassistant_time).now(); char buf[10]; if (std::string("${TIME_24H}") == "true") { snprintf(buf, sizeof(buf), "%02d:%02d", now.hour, now.minute); } else { int h = now.hour % 12; if (h == 0) h = 12; snprintf(buf, sizeof(buf), "%d:%02d %s", h, now.minute, now.hour >= 12 ? "PM" : "AM"); } set_lbl(id(lbl_time), std::string(buf)); } auto apply_tile = [&](bool active, lv_obj_t* tile, lv_obj_t* circle, lv_obj_t* title, lv_obj_t* value, lv_obj_t* icon_lbl, uint32_t ca, uint32_t cd, uint32_t ia, uint32_t id_, uint32_t ba, uint32_t bd, uint32_t ta, uint32_t td, uint32_t va, uint32_t vd) { lv_obj_set_style_bg_color(tile, lv_color_hex(active ? ba : bd), 0); lv_obj_set_style_bg_color(circle, lv_color_hex(active ? ca : cd), 0); lv_obj_set_style_text_color(icon_lbl, lv_color_hex(active ? ia : id_), 0); lv_obj_set_style_text_color(title, lv_color_hex(active ? ta : td), 0); lv_obj_set_style_text_color(value, lv_color_hex(active ? va : vd), 0); }; apply_tile(id(ha_state_tile1).state, id(tile1), id(tile1_icon_circle), id(t1_title), id(t1_value), id(tile1_icon_lbl), ${TILE1_CIRCLE_ACTIVE_COLOR}, ${TILE1_CIRCLE_DISABLED_COLOR}, ${TILE1_ICON_ACTIVE_COLOR}, ${TILE1_ICON_DISABLED_COLOR}, ${TILE1_BG_ACTIVE_COLOR}, ${TILE1_BG_DISABLED_COLOR}, ${TILE1_TITLE_ACTIVE_COLOR}, ${TILE1_TITLE_DISABLED_COLOR}, ${TILE1_VALUE_ACTIVE_COLOR}, ${TILE1_VALUE_DISABLED_COLOR}); apply_tile(id(ha_state_tile2).state, id(tile2), id(tile2_icon_circle), id(t2_title), id(t2_value), id(tile2_icon_lbl), ${TILE2_CIRCLE_ACTIVE_COLOR}, ${TILE2_CIRCLE_DISABLED_COLOR}, ${TILE2_ICON_ACTIVE_COLOR}, ${TILE2_ICON_DISABLED_COLOR}, ${TILE2_BG_ACTIVE_COLOR}, ${TILE2_BG_DISABLED_COLOR}, ${TILE2_TITLE_ACTIVE_COLOR}, ${TILE2_TITLE_DISABLED_COLOR}, ${TILE2_VALUE_ACTIVE_COLOR}, ${TILE2_VALUE_DISABLED_COLOR}); apply_tile(id(ha_state_tile3).state, id(tile3), id(tile3_icon_circle), id(t3_title), id(t3_value), id(tile3_icon_lbl), ${TILE3_CIRCLE_ACTIVE_COLOR}, ${TILE3_CIRCLE_DISABLED_COLOR}, ${TILE3_ICON_ACTIVE_COLOR}, ${TILE3_ICON_DISABLED_COLOR}, ${TILE3_BG_ACTIVE_COLOR}, ${TILE3_BG_DISABLED_COLOR}, ${TILE3_TITLE_ACTIVE_COLOR}, ${TILE3_TITLE_DISABLED_COLOR}, ${TILE3_VALUE_ACTIVE_COLOR}, ${TILE3_VALUE_DISABLED_COLOR}); apply_tile(id(ha_state_tile4).state, id(tile4), id(tile4_icon_circle), id(t4_title), id(t4_value), id(tile4_icon_lbl), ${TILE4_CIRCLE_ACTIVE_COLOR}, ${TILE4_CIRCLE_DISABLED_COLOR}, ${TILE4_ICON_ACTIVE_COLOR}, ${TILE4_ICON_DISABLED_COLOR}, ${TILE4_BG_ACTIVE_COLOR}, ${TILE4_BG_DISABLED_COLOR}, ${TILE4_TITLE_ACTIVE_COLOR}, ${TILE4_TITLE_DISABLED_COLOR}, ${TILE4_VALUE_ACTIVE_COLOR}, ${TILE4_VALUE_DISABLED_COLOR}); apply_tile(id(ha_state_tile5).state, id(tile5), id(tile5_icon_circle), id(t5_title), id(t5_value), id(tile5_icon_lbl), ${TILE5_CIRCLE_ACTIVE_COLOR}, ${TILE5_CIRCLE_DISABLED_COLOR}, ${TILE5_ICON_ACTIVE_COLOR}, ${TILE5_ICON_DISABLED_COLOR}, ${TILE5_BG_ACTIVE_COLOR}, ${TILE5_BG_DISABLED_COLOR}, ${TILE5_TITLE_ACTIVE_COLOR}, ${TILE5_TITLE_DISABLED_COLOR}, ${TILE5_VALUE_ACTIVE_COLOR}, ${TILE5_VALUE_DISABLED_COLOR}); apply_tile(id(ha_state_tile6).state, id(tile6), id(tile6_icon_circle), id(t6_title), id(t6_value), id(tile6_icon_lbl), ${TILE6_CIRCLE_ACTIVE_COLOR}, ${TILE6_CIRCLE_DISABLED_COLOR}, ${TILE6_ICON_ACTIVE_COLOR}, ${TILE6_ICON_DISABLED_COLOR}, ${TILE6_BG_ACTIVE_COLOR}, ${TILE6_BG_DISABLED_COLOR}, ${TILE6_TITLE_ACTIVE_COLOR}, ${TILE6_TITLE_DISABLED_COLOR}, ${TILE6_VALUE_ACTIVE_COLOR}, ${TILE6_VALUE_DISABLED_COLOR}); - component.update: my_display